Compare commits

...

55 Commits

Author SHA1 Message Date
PCSX2 Bot
5dc015c0a3 Qt: Update Base Translation 2024-07-27 20:24:35 -04:00
Florin9doi
edd39dfe08 USB: ASCII Trance Vib emulation 2024-07-27 14:25:29 -04:00
KamFretoZ
f5320e201e FSUI: Update Base Translation 2024-07-27 13:05:56 -04:00
KamFretoZ
37569d1526 DiscordRPC: More translatable strings. 2024-07-27 13:05:56 -04:00
KamFretoZ
1efeab4078 OSD: Move hardcore notification from toast to OSD 2024-07-27 13:05:56 -04:00
Florin9doi
2bff3579e5 USB: Gametrak/RealPlay emulation 2024-07-27 12:01:31 -04:00
TheTechnician27
2fa85c56c2 GameList: Make compat strings translatable 2024-07-26 19:30:02 -04:00
TheLastRar
ded55635c1 input-rec: Directly use recorded values for pressure sensitive buttons 2024-07-26 08:57:14 +02:00
PCSX2 Bot
c9b8874eb6 Qt: Update Base Translation 2024-07-25 20:17:06 -04:00
KamFretoZ
9172a1a6f8 Qt: Add prompt to missing ffmpeg warning 2024-07-25 09:26:58 -04:00
KamFretoZ
b2ac7afbcb Qt: Add Video Capture button to toolbar 2024-07-25 09:26:58 -04:00
TheTechnician27
dcfd663c19 Qt: Simplify compat line in GameSummaryWidget 2024-07-24 13:14:05 -04:00
TheLastRar
225f057a5c gitignore: Ignore bin* 2024-07-23 18:56:17 -04:00
TheLastRar
0017e33023 Deps: Remove hardcoded version for zstd 2024-07-23 18:56:17 -04:00
TheLastRar
76ced16f9e Deps: Update Windows ARM64 dependencies 2024-07-23 18:56:17 -04:00
TheLastRar
245937eb85 3rdparty/cpuinfo: Fix ARM64 project 2024-07-23 18:56:17 -04:00
TheTechnician27
3a72328d55 Qt: Add per-game link to PCSX2 Wiki pages on right-click 2024-07-23 18:51:44 -04:00
PCSX2 Bot
06bc0300c0 Qt: Update Base Translation 2024-07-22 22:17:10 +02:00
PCSX2 Bot
98dcf40967 PAD: Update to latest controller database. 2024-07-22 21:39:29 +02:00
Ty Lamontagne
6b61ffbb63 GS Capture: Allow selecting the pixel format based on the current codec 2024-07-22 10:56:30 -04:00
Ty Lamontagne
dd7eef723a GS Capture: Set ffmpeg channel layout 2024-07-22 10:56:30 -04:00
TellowKrinkle
328275cd45 GS:Capture: VAAPI support 2024-07-21 14:31:22 -04:00
PCSX2 Bot
a4f1431bcc Qt: Update Base Translation 2024-07-20 23:10:29 +02:00
lightningterror
473df8dad4 Debugger: Cleanup warnings and casts.
MemoryViewWidget.cpp
BreakpointModel.cpp
2024-07-20 23:09:51 +02:00
lightningterror
042959958e GS/HW: Use enum for blend_hw shader bit everywhere.
Leftover places I forgot to replace.
2024-07-20 15:20:07 +02:00
KamFretoZ
cd4de28b9e OSD: Add PCSX2 Version toggle 2024-07-19 12:46:35 -04:00
TheTechnician27
24a87c3fee Qt: Disable Single Frame GS Dump tool when not playing a game 2024-07-19 09:14:43 -04:00
GovanifY
17567b960f qt/MainWindow: for disable hide window if render to main is enabled
This fixes a crash on wayland (and possibly others)
2024-07-19 07:49:50 -04:00
JordanTheToaster
7a3d22ecdf GameDB: TC SOLA fixes 2024-07-18 19:55:28 -04:00
Ty Lamontagne
7e5016fdab linux/cmake: Allow libbacktrace to be disabled 2024-07-18 16:46:24 -04:00
PCSX2 Bot
47606400fa Qt: Update Base Translation 2024-07-18 19:11:09 +02:00
TheLastRar
d6076a6107 DEV9: Use const in ICMP session 2024-07-18 19:10:40 +02:00
TheLastRar
95c57462cc DEV9: FreeBSD/Mac Fixes for ICMP session 2024-07-18 19:10:40 +02:00
TheLastRar
48a1ec3531 DEV9: Use std::unique_ptr for tracking active pings 2024-07-18 19:10:40 +02:00
TheLastRar
9da3bccca2 DEV9: Use vector for ICMP temp buffer 2024-07-18 19:10:40 +02:00
TheLastRar
a1a92920b2 DEV9: Fix handling of ICMP timeout 2024-07-18 19:10:40 +02:00
TheLastRar
b6b775e44e DEV9: Fix IP_PayloadPtr::WriteBytes() 2024-07-18 19:10:40 +02:00
TheLastRar
5ea46ac076 DEV9: Use non-blocking sockets for ICMP Sessions on Unix 2024-07-18 19:10:40 +02:00
TheLastRar
ab008bf5d0 DEV9: Correct ICMP log messages 2024-07-18 19:10:40 +02:00
TheLastRar
54782cbf70 DEV9: Amend ICMP_Session comments 2024-07-18 19:10:40 +02:00
TheLastRar
3c7cff99f4 DEV9: Eliminate c-style casts from ICMP_Session 2024-07-18 19:10:40 +02:00
TheLastRar
f326e8775f DEV9: Correct spelling in ICMP session 2024-07-18 19:10:40 +02:00
AKuHAK
a2a711b1b3 Bios: add support for Rom2 up to 4Mb 2024-07-18 11:50:57 -04:00
PCSX2 Bot
dfb857b68f Qt: Update Base Translation 2024-07-17 22:20:21 +02:00
TheLastRar
ad64d88e7b Common: Fix FreeBSD build 2024-07-17 22:15:09 +02:00
TheTechnician27
cbd207d3f4 Qt: Add Emerald theme and fix palette var names 2024-07-17 21:56:46 +02:00
gooosedev
4bf8b23204 Debugger: change how the nullbyte (0x00) are displayed in the memoryview widget. 2024-07-17 21:55:04 +02:00
Ty Lamontagne
951780b43d Debugger: Implement little endian memory view support 2024-07-17 21:55:04 +02:00
TheTechnician27
84fe413635 GameDB: Ensure NativeScaling doesn't nag users at native res 2024-07-17 15:01:07 -04:00
Mrlinkwii
17aaa31362 github: mention to verify games if making an issue
[ci skip]
2024-07-17 14:58:37 -04:00
TheTechnician27
f943bdad98 Covers: Use serial for cover image names when selected individually 2024-07-17 14:58:04 -04:00
JordanTheToaster
09b2b6f949 GameDB: Fix up ATV ORF 3 fixes 2024-07-17 20:57:56 +02:00
L1Q
c46902c0f5 ReadMe: Fix BIOS dump link. (#11552) 2024-07-17 20:57:07 +02:00
PCSX2 Bot
c0dce9f64b PAD: Update to latest controller database. 2024-07-17 20:55:31 +02:00
Silent
cd3e11bff7 InputManager: Release settings lock before shutting down the input source 2024-07-13 07:29:26 -04:00
82 changed files with 6876 additions and 3560 deletions

View File

@@ -18,6 +18,8 @@ body:
Please make an effort to make sure your issue isn't already reported.
Please make sure your game is verified using the built-in game verifier.
Do not create issues involving software piracy of BIOS or ISO files, our rules specifically prohibit this and your issue will be closed.
### Please Avoid Issues Pertaining to the Following:

View File

@@ -47,13 +47,13 @@ set HARFBUZZ=8.3.1
set LIBJPEG=9f
set LIBPNG=1643
set LZ4=b8fd2d15309dd4e605070bd4486e26b6ef814e29
set QT=6.7.0
set QT=6.7.2
set QTMINOR=6.7
set SDL=SDL2-2.30.2
set WEBP=1.3.2
set SDL=SDL2-2.30.5
set WEBP=1.4.0
set ZLIB=1.3.1
set ZLIBSHORT=131
set ZSTD=1.5.5
set ZSTD=1.5.6
set SHADERC=2024.1
set SHADERC_GLSLANG=142052fa30f9eca191aa9dcf65359fcaed09eeec
@@ -64,16 +64,17 @@ call :downloadfile "freetype-%FREETYPE%.tar.gz" https://sourceforge.net/projects
call :downloadfile "harfbuzz-%HARFBUZZ%.zip" https://github.com/harfbuzz/harfbuzz/archive/refs/tags/%HARFBUZZ%.zip b2bc56184ae37324bc4829fde7d3f9e6916866ad711ee85792e457547c9fd127 || goto error
call :downloadfile "lpng%LIBPNG%.zip" https://download.sourceforge.net/libpng/lpng1643.zip fc466a1e638e635d6c66363bdf3f38555b81b0141d0b06ba45b49ccca327436d || goto error
call :downloadfile "jpegsr%LIBJPEG%.zip" https://ijg.org/files/jpegsr%LIBJPEG%.zip 6255da8c89e09d694e6800688c76145eb6870a76ac0d36c74fccd61b3940aafa || goto error
call :downloadfile "libwebp-%WEBP%.tar.gz" "https://storage.googleapis.com/downloads.webmproject.org/releases/webp/libwebp-%WEBP%.tar.gz" 2a499607df669e40258e53d0ade8035ba4ec0175244869d1025d460562aa09b4 || goto error
call :downloadfile "libwebp-%WEBP%.tar.gz" "https://storage.googleapis.com/downloads.webmproject.org/releases/webp/libwebp-%WEBP%.tar.gz" 61f873ec69e3be1b99535634340d5bde750b2e4447caa1db9f61be3fd49ab1e5 || goto error
call :downloadfile "lz4-%LZ4%.zip" "https://github.com/lz4/lz4/archive/%LZ4%.zip" 0c33119688d6b180c7e760b0acd70059222389cfd581632623784bee27e51a31 || goto error
call :downloadfile "%SDL%.zip" "https://libsdl.org/release/%SDL%.zip" c5d78a9e0346c6695f03df8ba25e5e111a1e23c8aefa8372a1c5a0dd79acaf10 || goto error
call :downloadfile "qtbase-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qtbase-everywhere-src-%QT%.zip" 3027fb990cb66436b5476b9dd17cd58f23b55a42eb1c1bcf9c7d78bca3ad7d63 || goto error
call :downloadfile "qtimageformats-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qtimageformats-everywhere-src-%QT%.zip" f30065289517847d721467827ee446a5f606f6d1c750e166cbfb0ed5bf066c5e || goto error
call :downloadfile "qtsvg-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qtsvg-everywhere-src-%QT%.zip" 882d1db58d35155bd92e4ed92b485d7d713b6aff0d7cf78655de0b414a980689 || goto error
call :downloadfile "qttools-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qttools-everywhere-src-%QT%.zip" 93a31892ca8a4f38464e923328788ce3da881d82016fe18fa1ed12dd43ce486c || goto error
call :downloadfile "qttranslations-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qttranslations-everywhere-src-%QT%.zip" 102ca62fa682c0d3e700ba89069fd3b6663b9f0c2890b058e97998b6e8971fb3 || goto error
call :downloadfile "%SDL%.zip" "https://libsdl.org/release/%SDL%.zip" 688d3da2bf7e887d0ba8e0f81c926119f85029544f4f6da8dea96db70f9d28e3 || goto error
call :downloadfile "qtbase-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qtbase-everywhere-src-%QT%.zip" 488119aad60719a085a1e45c31641ac2406ef86fc088a3c99885c18e9d6b4bb9 || goto error
call :downloadfile "qtimageformats-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qtimageformats-everywhere-src-%QT%.zip" 8e736b02db7dd67dbe834d56503b242344ce85d3532da692f1812b30ccf80997 || goto error
call :downloadfile "qtsvg-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qtsvg-everywhere-src-%QT%.zip" 85a22142270a92be0dd0ab5d27cc53617b2a2f1a45fc0a3890024164032f8475 || goto error
call :downloadfile "qttools-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qttools-everywhere-src-%QT%.zip" 9e15f1fdbd83e4123e733bff20aff1b45921c09056c3790fa42eb71d0a5cd01f || goto error
call :downloadfile "qttranslations-everywhere-src-%QT%.zip" "https://download.qt.io/official_releases/qt/%QTMINOR%/%QT%/submodules/qttranslations-everywhere-src-%QT%.zip" d1f25e0f68a1282feffdd5fe795a027ee5f16ad19e3b1fa2e04a51cea19110ec || goto error
call :downloadfile "zlib%ZLIBSHORT%.zip" "https://zlib.net/zlib%ZLIBSHORT%.zip" 72af66d44fcc14c22013b46b814d5d2514673dda3d115e64b690c1ad636e7b17 || goto error
call :downloadfile "zstd-%ZSTD%.zip" "https://github.com/facebook/zstd/archive/refs/tags/v%ZSTD%.zip" c5c8daa1d40dabc51790c62a5b86af2b36dfc4e1a738ff10dc4a46ea4e68ee51 || goto error
call :downloadfile "zstd-%ZSTD%.zip" "https://github.com/facebook/zstd/archive/refs/tags/v%ZSTD%.zip" 3b1c3b46e416d36931efd34663122d7f51b550c87f74de2d38249516fe7d8be5 || goto error
call :downloadfile "zstd-fd5f8106a58601a963ee816e6a57aa7c61fafc53.patch" https://github.com/facebook/zstd/commit/fd5f8106a58601a963ee816e6a57aa7c61fafc53.patch 675f144b11f8ab2424b64bed8ccdca5d3f35b9326046fa7a883925dd180f0651 || goto error
call :downloadfile "shaderc-%SHADERC%.zip" "https://github.com/google/shaderc/archive/refs/tags/v%SHADERC%.zip" 6c9f42ed6bf42750f5369b089909abfdcf0101488b4a1f41116d5159d00af8e7 || goto error
call :downloadfile "shaderc-glslang-%SHADERC_GLSLANG%.zip" "https://github.com/KhronosGroup/glslang/archive/%SHADERC_GLSLANG%.zip" 03ad8a6fa987af4653d0cfe6bdaed41bcf617f1366a151fb1574da75950cd3e8 || goto error
@@ -108,6 +109,7 @@ ninja -C build install || goto error
cd .. || goto error
echo Building libjpeg...
rmdir /S /Q "jpeg-%LIBJPEG%"
%SEVENZIP% x "jpegsr%LIBJPEG%.zip" || goto error
cd "jpeg-%LIBJPEG%" || goto error
%PATCH% -p1 < "%SCRIPTDIR%\libjpeg-cmake.patch" || goto error
@@ -155,8 +157,9 @@ cd .. || goto error
echo Building Zstandard...
rmdir /S /Q "zstd-%ZSTD%"
%SEVENZIP% x "-x^!zstd-1.5.5\tests\cli-tests\bin" "zstd-%ZSTD%.zip" || goto error
%SEVENZIP% x "-x^!zstd-%ZSTD%\tests\cli-tests\bin" "zstd-%ZSTD%.zip" || goto error
cd "zstd-%ZSTD%"
%PATCH% -p1 < "..\zstd-fd5f8106a58601a963ee816e6a57aa7c61fafc53.patch" || goto error
cmake %ARM64TOOLCHAIN% -DCMAKE_BUILD_TYPE=Release -DCMAKE_PREFIX_PATH="%INSTALLDIR%" -DCMAKE_INSTALL_PREFIX="%INSTALLDIR%" -DBUILD_SHARED_LIBS=ON -DZSTD_BUILD_SHARED=ON -DZSTD_BUILD_STATIC=OFF -DZSTD_BUILD_PROGRAMS=OFF -B build -G Ninja build/cmake
cmake --build build --parallel || goto error
ninja -C build install || goto error

View File

@@ -154,7 +154,7 @@ cd .. || goto error
echo Building Zstandard...
rmdir /S /Q "zstd-%ZSTD%"
%SEVENZIP% x "-x^!zstd-1.5.6\tests\cli-tests\bin" "zstd-%ZSTD%.zip" || goto error
%SEVENZIP% x "-x^!zstd-%ZSTD%\tests\cli-tests\bin" "zstd-%ZSTD%.zip" || goto error
cd "zstd-%ZSTD%"
%PATCH% -p1 < "..\zstd-fd5f8106a58601a963ee816e6a57aa7c61fafc53.patch" || goto error
cmake -DCMAKE_BUILD_TYPE=Release -DCMAKE_PREFIX_PATH="%INSTALLDIR%" -DCMAKE_INSTALL_PREFIX="%INSTALLDIR%" -DBUILD_SHARED_LIBS=ON -DZSTD_BUILD_SHARED=ON -DZSTD_BUILD_STATIC=OFF -DZSTD_BUILD_PROGRAMS=OFF -B build -G Ninja build/cmake

58
.gitignore vendored
View File

@@ -63,35 +63,35 @@ oprofile_data/
*.kdev4
/.kdev4*
/bin/**/*.dll
/bin/**/*.dmp
/bin/**/*.exp
/bin/**/*.ilk
/bin/**/*.lib
/bin/**/*.pdb
/bin/pcsx2*
/bin/qt.conf
/bin/bios
/bin/cache
/bin/cheats
/bin/patches
/bin/covers
/bin/dumps
/bin/gamesettings
/bin/help
/bin/inis
/bin/inis/debuggersettings
/bin/logs
/bin/memcards
/bin/plugins
/bin/snaps
/bin/sstates
/bin/textures
/bin/translations
/bin/inputprofiles
/bin/videos
/bin/portable.ini
/bin/portable.txt
/bin*/**/*.dll
/bin*/**/*.dmp
/bin*/**/*.exp
/bin*/**/*.ilk
/bin*/**/*.lib
/bin*/**/*.pdb
/bin*/pcsx2*
/bin*/qt.conf
/bin*/bios
/bin*/cache
/bin*/cheats
/bin*/patches
/bin*/covers
/bin*/dumps
/bin*/gamesettings
/bin*/help
/bin*/inis
/bin*/inis/debuggersettings
/bin*/logs
/bin*/memcards
/bin*/plugins
/bin*/snaps
/bin*/sstates
/bin*/textures
/bin*/translations
/bin*/inputprofiles
/bin*/videos
/bin*/portable.ini
/bin*/portable.txt
# Manually added by user.
/bin/resources/patches.zip

View File

@@ -30,13 +30,16 @@
<CodeAnalysisRuleSet>AllRules.ruleset</CodeAnalysisRuleSet>
</PropertyGroup>
<ItemGroup>
<ClCompile Include="..\..\..\duckstation\dep\cpuinfo\src\arm\cache.c">
<ClCompile Include="src\arm\cache.c">
<ExcludedFromBuild Condition="'$(Platform)'!='ARM64'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="..\..\..\duckstation\dep\cpuinfo\src\arm\uarch.c">
<ClCompile Include="src\arm\uarch.c">
<ExcludedFromBuild Condition="'$(Platform)'!='ARM64'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="..\..\..\duckstation\dep\cpuinfo\src\arm\windows\init.c">
<ClCompile Include="src\arm\windows\init-by-logical-sys-info.c">
<ExcludedFromBuild Condition="'$(Platform)'!='ARM64'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="src\arm\windows\init.c">
<ExcludedFromBuild Condition="'$(Platform)'!='ARM64'">true</ExcludedFromBuild>
</ClCompile>
<ClCompile Include="deps\clog\src\clog.c" />
@@ -78,13 +81,13 @@
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="..\..\..\duckstation\dep\cpuinfo\src\arm\api.h">
<ClInclude Include="src\arm\api.h">
<ExcludedFromBuild Condition="'$(Platform)'!='ARM64'">true</ExcludedFromBuild>
</ClInclude>
<ClInclude Include="..\..\..\duckstation\dep\cpuinfo\src\arm\midr.h">
<ClInclude Include="src\arm\midr.h">
<ExcludedFromBuild Condition="'$(Platform)'!='ARM64'">true</ExcludedFromBuild>
</ClInclude>
<ClInclude Include="..\..\..\duckstation\dep\cpuinfo\src\arm\windows\api.h">
<ClInclude Include="src\arm\windows\windows-arm-init.h">
<ExcludedFromBuild Condition="'$(Platform)'!='ARM64'">true</ExcludedFromBuild>
</ClInclude>
<ClInclude Include="deps\clog\include\clog.h" />

View File

@@ -63,13 +63,16 @@
<ClCompile Include="deps\clog\src\clog.c">
<Filter>clog</Filter>
</ClCompile>
<ClCompile Include="..\..\..\duckstation\dep\cpuinfo\src\arm\cache.c">
<ClCompile Include="src\arm\cache.c">
<Filter>arm</Filter>
</ClCompile>
<ClCompile Include="..\..\..\duckstation\dep\cpuinfo\src\arm\uarch.c">
<ClCompile Include="src\arm\uarch.c">
<Filter>arm</Filter>
</ClCompile>
<ClCompile Include="..\..\..\duckstation\dep\cpuinfo\src\arm\windows\init.c">
<ClCompile Include="src\arm\windows\init.c">
<Filter>arm\windows</Filter>
</ClCompile>
<ClCompile Include="src\arm\windows\init-by-logical-sys-info.c">
<Filter>arm\windows</Filter>
</ClCompile>
</ItemGroup>
@@ -99,13 +102,13 @@
<ClInclude Include="deps\clog\include\clog.h">
<Filter>clog</Filter>
</ClInclude>
<ClInclude Include="..\..\..\duckstation\dep\cpuinfo\src\arm\api.h">
<ClInclude Include="src\arm\api.h">
<Filter>arm</Filter>
</ClInclude>
<ClInclude Include="..\..\..\duckstation\dep\cpuinfo\src\arm\midr.h">
<ClInclude Include="src\arm\midr.h">
<Filter>arm</Filter>
</ClInclude>
<ClInclude Include="..\..\..\duckstation\dep\cpuinfo\src\arm\windows\api.h">
<ClInclude Include="src\arm\windows\windows-arm-init.h">
<Filter>arm\windows</Filter>
</ClInclude>
</ItemGroup>

View File

@@ -18,7 +18,7 @@ Installers and binaries for both stable and nightly builds are available from [o
PCSX2 supports Windows, Linux, and Mac platforms. Our [setup documentation page](https://pcsx2.net/docs/setup/requirements) contains additional details on software and hardware requirements.
Please note that a BIOS dump from a legitimately-owned PS2 console is required to use the emulator. For more information, visit [this page](https://pcsx2.net/docs/setup/gather/#how-to-dump-your-ps2-bios).
Please note that a BIOS dump from a legitimately-owned PS2 console is required to use the emulator. For more information, visit [this page](https://pcsx2.net/docs/setup/bios/).
## Contributing / Building

View File

@@ -11186,8 +11186,6 @@ SCUS-97436:
SCUS-97437:
name: "ATV Offroad Fury 3 [Demo]"
region: "NTSC-U"
speedHacks:
mtvu: 0 # Increases FPS drastically.
SCUS-97438:
name: "EyeToy - Antigrav [Demo]"
region: "NTSC-U"
@@ -11583,8 +11581,6 @@ SCUS-97513:
SCUS-97514:
name: "ATV Offroad Fury 3 [Greatest Hits]"
region: "NTSC-U"
speedHacks:
mtvu: 0 # Increases FPS drastically.
SCUS-97515:
name: "Hot Shots Golf FORE! [Greatest Hits]"
region: "NTSC-U"
@@ -12497,7 +12493,7 @@ SLED-51211:
gsHWFixes:
gpuTargetCLUT: 1 # Fixes bloom and sun rendering in front of everything.
autoFlush: 1 # Fixes bloom and sun rendering in front of everything.
halfPixelOffset: 4 # Aligns bloom effect.
halfPixelOffset: 2 # Aligns bloom effect.
bilinearUpscale: 2 # Reduces color banding of the sun glare.
nativeScaling: 2 # Fixes post lighting.
roundModes:
@@ -12585,6 +12581,7 @@ SLED-51902:
halfPixelOffset: 3 # Fixes double image.
gpuTargetCLUT: 1 # Fixes sun penetrating buildings.
autoFlush: 1 # Fixes sun occlusion.
bilinearUpscale: 2 # Fixes sun glare textures to behave like native.
SLED-51921:
name: "Final Fantasy X-2 [Demo]"
region: "PAL-Unk"
@@ -15583,7 +15580,7 @@ SLES-51044:
gsHWFixes:
gpuTargetCLUT: 1 # Fixes bloom and sun rendering in front of everything.
autoFlush: 1 # Fixes bloom and sun rendering in front of everything.
halfPixelOffset: 4 # Aligns bloom effect.
halfPixelOffset: 2 # Aligns bloom effect.
bilinearUpscale: 2 # Reduces color banding of the sun glare.
nativeScaling: 2 # Fixes post lighting.
roundModes:
@@ -17217,6 +17214,7 @@ SLES-51753:
halfPixelOffset: 3 # Fixes double image.
gpuTargetCLUT: 1 # Fixes sun penetrating buildings.
autoFlush: 1 # Fixes sun occlusion.
bilinearUpscale: 2 # Fixes sun glare textures to behave like native.
SLES-51754:
name: "True Crime - Streets of L.A."
region: "PAL-M5"
@@ -17226,6 +17224,7 @@ SLES-51754:
halfPixelOffset: 3 # Fixes double image.
gpuTargetCLUT: 1 # Fixes sun penetrating buildings.
autoFlush: 1 # Fixes sun occlusion.
bilinearUpscale: 2 # Fixes sun glare textures to behave like native.
SLES-51755:
name: "Disney/Pixar Finding Nemo"
region: "PAL-E"
@@ -20435,7 +20434,7 @@ SLES-52968:
gsHWFixes:
gpuTargetCLUT: 1 # Fixes bloom and sun rendering in front of everything.
autoFlush: 1 # Fixes bloom and sun rendering in front of everything.
halfPixelOffset: 4 # Aligns bloom effect.
halfPixelOffset: 2 # Aligns bloom effect.
bilinearUpscale: 2 # Reduces color banding of the sun glare.
nativeScaling: 2 # Fixes post lighting.
roundModes:
@@ -22926,8 +22925,6 @@ SLES-53753:
SLES-53754:
name: "ATV Offroad Fury 3"
region: "PAL-M6"
speedHacks:
mtvu: 0 # Increases FPS drastically.
SLES-53755:
name: "Castlevania - Curse of Darkness"
region: "PAL-M5"
@@ -28951,7 +28948,7 @@ SLKA-25039:
gsHWFixes:
gpuTargetCLUT: 1 # Fixes bloom and sun rendering in front of everything.
autoFlush: 1 # Fixes bloom and sun rendering in front of everything.
halfPixelOffset: 4 # Aligns bloom effect.
halfPixelOffset: 2 # Aligns bloom effect.
bilinearUpscale: 2 # Reduces color banding of the sun glare.
nativeScaling: 2 # Fixes post lighting.
roundModes:
@@ -40829,6 +40826,7 @@ SLPM-65729:
halfPixelOffset: 3 # Fixes double image.
gpuTargetCLUT: 1 # Fixes sun penetrating buildings.
autoFlush: 1 # Fixes sun occlusion.
bilinearUpscale: 2 # Fixes sun glare textures to behave like native.
SLPM-65730:
name: "ロックマンX8"
name-sort: "ろっくまんえっくす8"
@@ -42962,6 +42960,7 @@ SLPM-66098:
halfPixelOffset: 3 # Fixes double image.
gpuTargetCLUT: 1 # Fixes sun penetrating buildings.
autoFlush: 1 # Fixes sun occlusion.
bilinearUpscale: 2 # Fixes sun glare textures to behave like native.
SLPM-66099:
name: "Harukanaru Toki no Naka de 3 - Izayoiki [Premium Box-Triple Pack]"
region: "NTSC-J"
@@ -53682,7 +53681,7 @@ SLPS-25351:
gsHWFixes:
gpuTargetCLUT: 1 # Fixes bloom and sun rendering in front of everything.
autoFlush: 1 # Fixes bloom and sun rendering in front of everything.
halfPixelOffset: 4 # Aligns bloom effect.
halfPixelOffset: 2 # Aligns bloom effect.
bilinearUpscale: 2 # Reduces color banding of the sun glare.
nativeScaling: 2 # Fixes post lighting.
roundModes:
@@ -60443,7 +60442,7 @@ SLUS-20497:
gsHWFixes:
gpuTargetCLUT: 1 # Fixes bloom and sun rendering in front of everything.
autoFlush: 1 # Fixes bloom and sun rendering in front of everything.
halfPixelOffset: 4 # Aligns bloom effect.
halfPixelOffset: 2 # Aligns bloom effect.
bilinearUpscale: 2 # Reduces color banding of the sun glare.
nativeScaling: 2 # Fixes post lighting.
roundModes:
@@ -60712,6 +60711,7 @@ SLUS-20550:
halfPixelOffset: 3 # Fixes double image.
gpuTargetCLUT: 1 # Fixes sun penetrating buildings.
autoFlush: 1 # Fixes sun occlusion.
bilinearUpscale: 2 # Fixes sun glare textures to behave like native.
SLUS-20552:
name: "Grand Theft Auto - Vice City"
region: "NTSC-U"
@@ -69617,8 +69617,6 @@ SLUS-90009:
SLUS-97405:
name: "ATV Offroad Fury 3"
region: "NTSC-U"
speedHacks:
mtvu: 0 # Increases FPS drastically.
SRPM-70201:
name: "Space Venus Starring Morning Musume."
region: "NTSC-J"

View File

@@ -484,7 +484,7 @@
03000000f0250000c183000000000000,PlayStation Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
03000000d9040000160f000000000000,PlayStation Controller 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:Windows,
030000004c0500003713000000000000,PlayStation Vita,a:b1,b:b2,back:b8,dpdown:b13,dpleft:b15,dpright:b14,dpup:b12,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,rightx:a3,righty:a4,start:b9,x:b0,y:b3,platform:Windows,
03000000d620000011a7000000000000,PowerA Core Plus GameCube Controller,a:b1,b:b0,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Windows,
03000000d620000011a7000000000000,PowerA Core Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
03000000dd62000015a7000000000000,PowerA Fusion Nintendo Switch Arcade Stick,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,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
03000000d620000012a7000000000000,PowerA Fusion Nintendo Switch Fight Pad,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,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
03000000dd62000016a7000000000000,PowerA Fusion Pro Nintendo Switch Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Windows,
@@ -1468,7 +1468,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
030000004c0500003713000011010000,PlayStation Vita,a:b1,b:b2,back:b8,dpdown:b13,dpleft:b15,dpright:b14,dpup:b12,leftshoulder:b4,leftx:a0,lefty:a1,rightshoulder:b5,rightx:a3,righty:a4,start:b9,x:b0,y:b3,platform:Linux,
03000000c62400000053000000010000,PowerA,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,
03000000c62400003a54000001010000,PowerA 1428124-01,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,
03000000d620000011a7000011010000,PowerA Core Plus Gamecube Controller,a:b1,b:b0,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b2,y:b3,platform:Linux,
03000000d620000011a7000011010000,PowerA Core Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
03000000dd62000015a7000011010000,PowerA Fusion Nintendo Switch Arcade Stick,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,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
03000000d620000012a7000011010000,PowerA Fusion Nintendo Switch Fight Pad,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,misc1:b13,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,platform:Linux,
03000000d62000000140000001010000,PowerA Fusion Pro 2 Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,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,
@@ -1690,6 +1690,7 @@ xinput,XInput Controller,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,
050000005e040000220b000013050000,Xbox One Elite 2 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,rightshoulder:b7,rightstick:b14,righttrigger:a4,rightx:a2,righty:a3,start:b11,x:b3,y:b4,platform:Linux,
050000005e040000050b000002090000,Xbox One Elite Series 2,a:b0,b:b1,back:b136,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,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,
030000005e040000ea02000011050000,Xbox One S 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,
050082795e040000e002000003090000,Xbox One S 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,
060000005e040000ea0200000b050000,Xbox One S 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,
060000005e040000ea0200000d050000,Xbox One S 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,
030000005e040000120b000001050000,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,

View File

@@ -23,6 +23,7 @@ if(UNIX AND NOT APPLE)
option(ENABLE_SETCAP "Enable networking capability for DEV9" OFF)
option(X11_API "Enable X11 support" ON)
option(WAYLAND_API "Enable Wayland support" ON)
option(USE_BACKTRACE "Enable libbacktrace support" ON)
endif()
if(UNIX)

View File

@@ -65,7 +65,10 @@ else()
find_package(Wayland REQUIRED Egl)
endif()
find_package(Libbacktrace REQUIRED)
if(USE_BACKTRACE)
find_package(Libbacktrace REQUIRED)
endif()
find_package(PkgConfig REQUIRED)
pkg_check_modules(DBUS REQUIRED dbus-1)
endif()

View File

@@ -167,10 +167,16 @@ else()
)
target_link_libraries(common PRIVATE
${DBUS_LINK_LIBRARIES}
libbacktrace::libbacktrace
X11::X11
X11::Xrandr
)
if(USE_BACKTRACE)
target_compile_definitions(common PRIVATE "HAS_LIBBACKTRACE=1")
target_link_libraries(common PRIVATE libbacktrace::libbacktrace)
endif()
if(${CMAKE_SYSTEM_NAME} STREQUAL "FreeBSD")
target_link_libraries(common PRIVATE cpuinfo)
endif()
endif()
set_source_files_properties(PrecompiledHeader.cpp PROPERTIES HEADER_FILE_ONLY TRUE)

View File

@@ -176,7 +176,7 @@ void CrashHandler::WriteDumpForCaller()
WriteMinidumpAndCallstack(nullptr);
}
#elif !defined(__APPLE__)
#elif !defined(__APPLE__) && defined(HAS_LIBBACKTRACE)
#include "FileSystem.h"
@@ -377,4 +377,4 @@ void CrashHandler::CrashSignalHandler(int signal, siginfo_t* siginfo, void* ctx)
std::abort();
}
#endif
#endif

View File

@@ -19,6 +19,10 @@
#include "fmt/core.h"
#if defined(__FreeBSD__)
#include "cpuinfo.h"
#endif
// FreeBSD does not have MAP_FIXED_NOREPLACE, but does have MAP_EXCL.
// MAP_FIXED combined with MAP_EXCL behaves like MAP_FIXED_NOREPLACE.
#if defined(__FreeBSD__) && !defined(MAP_FIXED_NOREPLACE)
@@ -142,6 +146,22 @@ size_t HostSys::GetRuntimePageSize()
size_t HostSys::GetRuntimeCacheLineSize()
{
#if defined(__FreeBSD__)
if (!cpuinfo_initialize())
return 0;
u32 max_line_size = 0;
for (u32 i = 0; i < cpuinfo_get_processors_count(); i++)
{
const u32 l1i = cpuinfo_get_processor(i)->cache.l1i->line_size;
const u32 l1d = cpuinfo_get_processor(i)->cache.l1d->line_size;
const u32 res = std::max<u32>(l1i, l1d);
max_line_size = std::max<u32>(max_line_size, res);
}
return static_cast<size_t>(max_line_size);
#else
int l1i = sysconf(_SC_LEVEL1_DCACHE_LINESIZE);
int l1d = sysconf(_SC_LEVEL1_ICACHE_LINESIZE);
int res = (l1i > l1d) ? l1i : l1d;
@@ -160,6 +180,7 @@ size_t HostSys::GetRuntimeCacheLineSize()
}
return (res > 0) ? static_cast<size_t>(res) : 0;
#endif
}
SharedMemoryMappingArea::SharedMemoryMappingArea(u8* base_ptr, size_t size, size_t num_pages)

View File

@@ -2,6 +2,7 @@
// SPDX-License-Identifier: LGPL-3.0+
#include "MemoryViewWidget.h"
#include "common/Console.h"
#include "QtHost.h"
#include "QtUtils.h"
@@ -10,7 +11,6 @@
#include <QtWidgets/QInputDialog>
#include <QtWidgets/QMessageBox>
#include <QtGui/QClipboard>
#include <QtCore/QtEndian>
using namespace QtUtils;
@@ -66,48 +66,78 @@ void MemoryViewTable::DrawTable(QPainter& painter, const QPalette& palette, s32
const u32 currentRowAddress = startAddress + (i * 0x10);
s32 valX = valuexAxis;
segmentXAxis[0] = valX;
u32 currentSegmentAddress = currentRowAddress;
for (int j = 0; j < 16; j++)
for (int j = 0; j < 16 / static_cast<s32>(displayType); j++)
{
const u32 currentByteAddress = currentRowAddress + j;
valX += charWidth;
const u32 thisSegmentsStart = currentRowAddress + (j * static_cast<s32>(displayType));
if (!(j % (s32)displayType))
{
valX += charWidth;
currentSegmentAddress = currentByteAddress;
}
segmentXAxis[j] = valX;
bool penDefault = false;
if ((selectedAddress & ~0xF) == currentRowAddress)
{
if (selectedAddress == currentByteAddress)
if (selectedAddress >= thisSegmentsStart && selectedAddress < (thisSegmentsStart + static_cast<s32>(displayType)))
{ // If the current byte and row we are drawing is selected
if (!selectedText)
{
s32 charsIntoSegment = ((selectedAddress - thisSegmentsStart) * 2) + ((selectedNibbleHI ? 0 : 1) ^ littleEndian);
if (littleEndian)
charsIntoSegment = (static_cast<s32>(displayType) * 2) - charsIntoSegment - 1;
painter.setPen(QColor::fromRgb(205, 165, 0)); // SELECTED NIBBLE LINE COLOUR
const QPoint lineStart(valX + (selectedNibbleHI ? 0 : charWidth) + 1, y + (rowHeight * i));
const QPoint lineStart(valX + (charsIntoSegment * charWidth) + 1, y + (rowHeight * i));
painter.drawLine(lineStart, lineStart + QPoint(charWidth - 3, 0));
}
painter.setPen(QColor::fromRgb(0xaa, 0x22, 0x22)); // SELECTED BYTE COLOUR
}
// If the current selected byte is in our current segment, highlight the entire segment
else if (displayType != MemoryViewType::BYTE &&
currentSegmentAddress <= selectedAddress && (selectedAddress <= (currentSegmentAddress + (s32)displayType - 1)))
{
painter.setPen(palette.highlight().color()); // SELECTED SEGMENT COLOUR
}
else
{
penDefault = true;
painter.setPen(palette.text().color()); // Default colour
}
}
else
{
penDefault = true;
painter.setPen(palette.text().color()); // Default colour
}
bool valid;
const u8 val = static_cast<u8>(m_cpu->read8(currentByteAddress, valid));
painter.drawText(valX, y + (rowHeight * i), valid ? FilledQStringFromValue(val, 16) : "??");
valX += charWidth * 2;
switch (displayType)
{
case MemoryViewType::BYTE:
{
const u8 val = static_cast<u8>(m_cpu->read8(thisSegmentsStart, valid));
if (penDefault && val == 0)
painter.setPen(QColor::fromRgb(145, 145, 155)); // ZERO BYTE COLOUR
painter.drawText(valX, y + (rowHeight * i), valid ? FilledQStringFromValue(val, 16) : "??");
break;
}
case MemoryViewType::BYTEHW:
{
const u16 val = convertEndian<u16>(static_cast<u16>(m_cpu->read16(thisSegmentsStart, valid)));
if (penDefault && val == 0)
painter.setPen(QColor::fromRgb(145, 145, 155)); // ZERO BYTE COLOUR
painter.drawText(valX, y + (rowHeight * i), valid ? FilledQStringFromValue(val, 16) : "????");
break;
}
case MemoryViewType::WORD:
{
const u32 val = convertEndian<u32>(m_cpu->read32(thisSegmentsStart, valid));
if (penDefault && val == 0)
painter.setPen(QColor::fromRgb(145, 145, 155)); // ZERO BYTE COLOUR
painter.drawText(valX, y + (rowHeight * i), valid ? FilledQStringFromValue(val, 16) : "????????");
break;
}
case MemoryViewType::DWORD:
{
const u64 val = convertEndian<u64>(m_cpu->read64(thisSegmentsStart, valid));
if (penDefault && val == 0)
painter.setPen(QColor::fromRgb(145, 145, 155)); // ZERO BYTE COLOUR
painter.drawText(valX, y + (rowHeight * i), valid ? FilledQStringFromValue(val, 16) : "????????????????");
break;
}
}
valX += charWidth * 2 * static_cast<s32>(displayType);
}
// valX is our new X position after the hex values
@@ -146,12 +176,15 @@ void MemoryViewTable::SelectAt(QPoint pos)
const u32 selectedRow = (pos.y() - 2) / (rowHeight);
const s32 x = pos.x();
const s32 avgSegmentWidth = segmentXAxis[1] - segmentXAxis[0];
const u32 nibbleWidth = (avgSegmentWidth / (2 * (s32)displayType));
selectedAddress = (selectedRow * 0x10) + startAddress;
if (x <= segmentXAxis[0])
{
selectedText = false;
// The user clicked before the first segment
selectedText = false;
if (littleEndian)
selectedAddress += static_cast<s32>(displayType) - 1;
selectedNibbleHI = true;
}
else if (x > valuexAxis && x < textXAxis)
@@ -160,10 +193,13 @@ void MemoryViewTable::SelectAt(QPoint pos)
// The user clicked inside of the hexadecimal area
for (s32 i = 0; i < 16; i++)
{
if (i == 15 || (x >= segmentXAxis[i] && x < (segmentXAxis[i + 1])))
if (i == ((16 / static_cast<s32>(displayType)) - 1) || (x >= segmentXAxis[i] && x < (segmentXAxis[i + 1])))
{
selectedAddress = selectedAddress + i;
selectedNibbleHI = ((x - segmentXAxis[i]) < ((avgSegmentWidth / 2) - 2)); // Subtract 2 units, makes selecting nibbles feel more natural
u32 indexInSegment = (x - segmentXAxis[i]) / nibbleWidth;
if (littleEndian)
indexInSegment = (static_cast<s32>(displayType) * 2) - indexInSegment - 1;
selectedAddress = selectedAddress + i * static_cast<s32>(displayType) + (indexInSegment / 2);
selectedNibbleHI = littleEndian ? indexInSegment & 1 : !(indexInSegment & 1);
break;
}
}
@@ -185,13 +221,13 @@ u128 MemoryViewTable::GetSelectedSegment()
val.lo = m_cpu->read8(selectedAddress);
break;
case MemoryViewType::BYTEHW:
val.lo = qToBigEndian((u16)m_cpu->read16(selectedAddress & ~1));
val.lo = convertEndian(static_cast<u16>(m_cpu->read16(selectedAddress & ~1)));
break;
case MemoryViewType::WORD:
val.lo = qToBigEndian(m_cpu->read32(selectedAddress & ~3));
val.lo = convertEndian(m_cpu->read32(selectedAddress & ~3));
break;
case MemoryViewType::DWORD:
val._u64[0] = qToBigEndian(m_cpu->read64(selectedAddress & ~7));
val._u64[0] = convertEndian(m_cpu->read64(selectedAddress & ~7));
break;
}
return val;
@@ -210,7 +246,8 @@ void MemoryViewTable::InsertIntoSelectedHexView(u8 value)
});
}
void MemoryViewTable::InsertAtCurrentSelection(const QString& text) {
void MemoryViewTable::InsertAtCurrentSelection(const QString& text)
{
if (!m_cpu->isValidAddress(selectedAddress))
return;
@@ -218,16 +255,89 @@ void MemoryViewTable::InsertAtCurrentSelection(const QString& text) {
// This approach prevents one from pasting on a nibble boundary, but that is almost always
// user error, and we don't have an undo function in this view, so best to stay conservative.
QByteArray input = selectedText ? text.toUtf8() : QByteArray::fromHex(text.toUtf8());
Host::RunOnCPUThread([this, address = selectedAddress, cpu = m_cpu, inBytes = input] {
u32 currAddr = address;
for (int i = 0; i < inBytes.size(); i++)
{
cpu->write8(address + i, inBytes[i]);
cpu->write8(currAddr, inBytes[i]);
currAddr = nextAddress(currAddr);
QtHost::RunOnUIThread([this] { parent->update(); });
}
QtHost::RunOnUIThread([this, inBytes] { UpdateSelectedAddress(selectedAddress + inBytes.size()); parent->update(); });
});
}
u32 MemoryViewTable::nextAddress(u32 addr)
{
if (!littleEndian)
{
return addr + 1;
}
else
{
if (selectedAddress % static_cast<s32>(displayType) == 0)
return addr + (static_cast<s32>(displayType) * 2 - 1);
else
return addr - 1;
}
}
u32 MemoryViewTable::prevAddress(u32 addr)
{
if (!littleEndian)
{
return addr - 1;
}
else
{
// It works
if ((addr & (static_cast<u32>(displayType) - 1)) == (static_cast<u32>(displayType) - 1))
return addr - (static_cast<s32>(displayType) * 2 - 1);
else
return selectedAddress + 1;
}
}
void MemoryViewTable::ForwardSelection()
{
if (!littleEndian)
{
if ((selectedNibbleHI = !selectedNibbleHI))
UpdateSelectedAddress(selectedAddress + 1);
}
else
{
if ((selectedNibbleHI = !selectedNibbleHI))
{
if (selectedAddress % static_cast<s32>(displayType) == 0)
UpdateSelectedAddress(selectedAddress + (static_cast<s32>(displayType) * 2 - 1));
else
UpdateSelectedAddress(selectedAddress - 1);
}
}
}
void MemoryViewTable::BackwardSelection()
{
if (!littleEndian)
{
if (!(selectedNibbleHI = !selectedNibbleHI))
UpdateSelectedAddress(selectedAddress - 1);
}
else
{
if (!(selectedNibbleHI = !selectedNibbleHI))
{
// It works
if ((selectedAddress & (static_cast<u32>(displayType) - 1)) == (static_cast<u32>(displayType) - 1))
UpdateSelectedAddress(selectedAddress - (static_cast<s32>(displayType) * 2 - 1));
else
UpdateSelectedAddress(selectedAddress + 1);
}
}
}
// We need both key and keychar because `key` is easy to use, but is case insensitive
bool MemoryViewTable::KeyPress(int key, QChar keychar)
{
@@ -255,16 +365,16 @@ bool MemoryViewTable::KeyPress(int key, QChar keychar)
case Qt::Key::Key_Escape:
Host::RunOnCPUThread([this, address = selectedAddress, cpu = m_cpu] {
cpu->write8(address, 0);
QtHost::RunOnUIThread([this] { UpdateSelectedAddress(selectedAddress - 1); parent->update(); });
QtHost::RunOnUIThread([this] {BackwardSelection(); parent->update(); });
});
pressHandled = true;
break;
case Qt::Key::Key_Right:
UpdateSelectedAddress(selectedAddress + 1);
ForwardSelection();
pressHandled = true;
break;
case Qt::Key::Key_Left:
UpdateSelectedAddress(selectedAddress - 1);
BackwardSelection();
pressHandled = true;
break;
default:
@@ -278,13 +388,11 @@ bool MemoryViewTable::KeyPress(int key, QChar keychar)
if (keyCharIsText)
{
// Check if key pressed is hex before insertion (QString conversion fails otherwise)
const u8 keyPressed = (u8)QString(QChar(key)).toInt(&pressHandled, 16);
const u8 keyPressed = static_cast<u8>(QString(QChar(key)).toInt(&pressHandled, 16));
if (pressHandled)
{
InsertIntoSelectedHexView(keyPressed);
// Increment to the next nibble or byte
if ((selectedNibbleHI = !selectedNibbleHI))
UpdateSelectedAddress(selectedAddress + 1);
ForwardSelection();
}
}
@@ -293,19 +401,15 @@ bool MemoryViewTable::KeyPress(int key, QChar keychar)
case Qt::Key::Key_Backspace:
case Qt::Key::Key_Escape:
InsertIntoSelectedHexView(0);
// Move back a byte or nibble if it's backspace being pressed
if (!(selectedNibbleHI = !selectedNibbleHI))
UpdateSelectedAddress(selectedAddress - 1);
BackwardSelection();
pressHandled = true;
break;
case Qt::Key::Key_Right:
if ((selectedNibbleHI = !selectedNibbleHI))
UpdateSelectedAddress(selectedAddress + 1);
ForwardSelection();
pressHandled = true;
break;
case Qt::Key::Key_Left:
if (!(selectedNibbleHI = !selectedNibbleHI))
UpdateSelectedAddress(selectedAddress - 1);
BackwardSelection();
pressHandled = true;
break;
default:
@@ -403,6 +507,11 @@ void MemoryViewWidget::customMenuRequested(QPoint pos)
m_contextMenu->addSeparator();
m_actionLittleEndian = new QAction(tr("Show as Little Endian"));
m_actionLittleEndian->setCheckable(true);
m_contextMenu->addAction(m_actionLittleEndian);
connect(m_actionLittleEndian, &QAction::triggered, this, [this]() { m_table.SetLittleEndian(m_actionLittleEndian->isChecked()); });
// View Types
m_actionBYTE = new QAction(tr("Show as 1 byte"));
m_actionBYTE->setCheckable(true);
@@ -446,6 +555,8 @@ void MemoryViewWidget::customMenuRequested(QPoint pos)
m_contextMenu->addAction(action);
connect(action, &QAction::triggered, this, [this]() { contextPaste(); });
}
m_actionLittleEndian->setChecked(m_table.GetLittleEndian());
const MemoryViewType currentViewType = m_table.GetViewType();
m_actionBYTE->setChecked(currentViewType == MemoryViewType::BYTE);

View File

@@ -12,6 +12,7 @@
#include <QtWidgets/QMenu>
#include <QtWidgets/QTabBar>
#include <QtGui/QPainter>
#include <QtCore/QtEndian>
#include <vector>
@@ -28,22 +29,39 @@ class MemoryViewTable
QWidget* parent;
DebugInterface* m_cpu;
MemoryViewType displayType = MemoryViewType::BYTE;
bool littleEndian = true;
u32 rowCount;
u32 rowVisible;
s32 rowHeight;
// Stuff used for selection handling
// This gets set every paint and depends on the window size / current display mode (1byte,2byte,etc)
s32 valuexAxis; // Where the hexadecimal view begins
s32 textXAxis; // Where the text view begins
s32 row1YAxis; // Where the first row starts
s32 segmentXAxis[16]; // Where the segments begin
s32 valuexAxis; // Where the hexadecimal view begins
s32 textXAxis; // Where the text view begins
s32 row1YAxis; // Where the first row starts
s32 segmentXAxis[16]; // Where the segments begin
bool selectedText = false; // Whether the user has clicked on text or hex
bool selectedNibbleHI = false;
void InsertIntoSelectedHexView(u8 value);
template <class T>
T convertEndian(T in)
{
if (littleEndian)
{
return in;
}
else
{
return qToBigEndian(in);
}
}
u32 nextAddress(u32 addr);
u32 prevAddress(u32 addr);
public:
MemoryViewTable(QWidget* parent)
: parent(parent){};
@@ -60,6 +78,8 @@ public:
void SelectAt(QPoint pos);
u128 GetSelectedSegment();
void InsertAtCurrentSelection(const QString& text);
void ForwardSelection();
void BackwardSelection();
// Returns true if the keypress was handled
bool KeyPress(int key, QChar keychar);
@@ -72,6 +92,16 @@ public:
{
displayType = viewType;
}
bool GetLittleEndian()
{
return littleEndian;
}
void SetLittleEndian(bool le)
{
littleEndian = le;
}
};
@@ -111,6 +141,7 @@ private:
Ui::RegisterWidget ui;
QMenu* m_contextMenu = 0x0;
QAction* m_actionLittleEndian;
QAction* m_actionBYTE;
QAction* m_actionBYTEHW;
QAction* m_actionWORD;

View File

@@ -256,8 +256,6 @@ Qt::ItemFlags BreakpointModel::flags(const QModelIndex& index) const
{
volatile const int row = index.row();
const bool is_breakpoint = std::holds_alternative<BreakPoint>(m_breakpoints.at(row));
switch (index.column())
{
case BreakpointColumns::CONDITION:

View File

@@ -396,7 +396,7 @@ void MainWindow::connectSignals()
connect(m_ui.actionSaveBlockDump, &QAction::toggled, this, &MainWindow::onBlockDumpActionToggled);
connect(m_ui.actionShowAdvancedSettings, &QAction::toggled, this, &MainWindow::onShowAdvancedSettingsToggled);
connect(m_ui.actionSaveGSDump, &QAction::triggered, this, &MainWindow::onSaveGSDumpActionTriggered);
connect(m_ui.actionToolsVideoCapture, &QAction::toggled, this, &MainWindow::onToolsVideoCaptureToggled);
connect(m_ui.actionVideoCapture, &QAction::toggled, this, &MainWindow::onVideoCaptureToggled);
connect(m_ui.actionEditPatches, &QAction::triggered, this, [this]() { onToolsEditCheatsPatchesTriggered(false); });
connect(m_ui.actionEditCheats, &QAction::triggered, this, [this]() { onToolsEditCheatsPatchesTriggered(true); });
@@ -712,14 +712,14 @@ void MainWindow::updateAdvancedSettingsVisibility()
m_ui.actionEnableVerboseLogging->setVisible(enabled);
}
void MainWindow::onToolsVideoCaptureToggled(bool checked)
void MainWindow::onVideoCaptureToggled(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);
QSignalBlocker sb(m_ui.actionVideoCapture);
m_ui.actionVideoCapture->setChecked(!checked);
if (!checked)
{
@@ -744,8 +744,8 @@ void MainWindow::onCaptureStarted(const QString& filename)
if (!s_vm_valid)
return;
QSignalBlocker sb(m_ui.actionToolsVideoCapture);
m_ui.actionToolsVideoCapture->setChecked(true);
QSignalBlocker sb(m_ui.actionVideoCapture);
m_ui.actionVideoCapture->setChecked(true);
}
void MainWindow::onCaptureStopped()
@@ -753,8 +753,8 @@ void MainWindow::onCaptureStopped()
if (!s_vm_valid)
return;
QSignalBlocker sb(m_ui.actionToolsVideoCapture);
m_ui.actionToolsVideoCapture->setChecked(false);
QSignalBlocker sb(m_ui.actionVideoCapture);
m_ui.actionVideoCapture->setChecked(false);
}
void MainWindow::onAchievementsLoginRequested(Achievements::LoginRequestReason reason)
@@ -851,16 +851,16 @@ void MainWindow::restoreStateFromConfig()
void MainWindow::updateEmulationActions(bool starting, bool running, bool stopping)
{
const bool starting_or_running = starting || running;
const bool starting_or_running_or_stopping = starting || running || stopping;
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.actionStartFullscreenUI->setDisabled(starting_or_running || stopping);
m_ui.actionToolbarStartFullscreenUI->setDisabled(starting_or_running || stopping);
m_ui.actionStartFile->setDisabled(starting_or_running_or_stopping);
m_ui.actionStartDisc->setDisabled(starting_or_running_or_stopping);
m_ui.actionStartBios->setDisabled(starting_or_running_or_stopping);
m_ui.actionToolbarStartFile->setDisabled(starting_or_running_or_stopping);
m_ui.actionToolbarStartDisc->setDisabled(starting_or_running_or_stopping);
m_ui.actionToolbarStartBios->setDisabled(starting_or_running_or_stopping);
m_ui.actionStartFullscreenUI->setDisabled(starting_or_running_or_stopping);
m_ui.actionToolbarStartFullscreenUI->setDisabled(starting_or_running_or_stopping);
m_ui.actionPowerOff->setEnabled(running);
m_ui.actionPowerOffWithoutSaving->setEnabled(running);
@@ -869,6 +869,7 @@ void MainWindow::updateEmulationActions(bool starting, bool running, bool stoppi
m_ui.actionScreenshot->setEnabled(running);
m_ui.menuChangeDisc->setEnabled(running);
m_ui.menuSaveState->setEnabled(running);
m_ui.actionSaveGSDump->setEnabled(running);
m_ui.actionToolbarPowerOff->setEnabled(running);
m_ui.actionToolbarReset->setEnabled(running);
@@ -879,11 +880,11 @@ void MainWindow::updateEmulationActions(bool starting, bool running, bool stoppi
m_ui.actionViewGameProperties->setEnabled(running);
m_ui.actionToolsVideoCapture->setEnabled(running);
if (!running && m_ui.actionToolsVideoCapture->isChecked())
m_ui.actionVideoCapture->setEnabled(running);
if (!running && m_ui.actionVideoCapture->isChecked())
{
QSignalBlocker sb(m_ui.actionToolsVideoCapture);
m_ui.actionToolsVideoCapture->setChecked(false);
QSignalBlocker sb(m_ui.actionVideoCapture);
m_ui.actionVideoCapture->setChecked(false);
}
m_game_list_widget->setDisabled(starting && !running);
@@ -902,8 +903,8 @@ void MainWindow::updateEmulationActions(bool starting, bool running, bool stoppi
}
// scanning needs to be disabled while running
m_ui.actionScanForNewGames->setDisabled(starting_or_running || stopping);
m_ui.actionRescanAllGames->setDisabled(starting_or_running || stopping);
m_ui.actionScanForNewGames->setDisabled(starting_or_running_or_stopping);
m_ui.actionRescanAllGames->setDisabled(starting_or_running_or_stopping);
}
void MainWindow::updateDisplayRelatedActions(bool has_surface, bool render_to_main, bool fullscreen)
@@ -1053,7 +1054,7 @@ bool MainWindow::shouldHideMouseCursor() const
bool MainWindow::shouldHideMainWindow() const
{
// NOTE: We can't use isRenderingToMain() here, because this happens post-fullscreen-switch.
return Host::GetBoolSettingValue("UI", "HideMainWindowWhenRunning", false) ||
return (Host::GetBoolSettingValue("UI", "HideMainWindowWhenRunning", false) && !g_emu_thread->shouldRenderToMain()) ||
(g_emu_thread->shouldRenderToMain() && (isRenderingFullscreen() || m_is_temporarily_windowed)) ||
QtHost::InNoGUIMode();
}
@@ -1355,6 +1356,11 @@ void MainWindow::onGameListEntryContextMenuRequested(const QPoint& point)
connect(menu.addAction(tr("Reset Play Time")), &QAction::triggered, [this, entry]() { clearGameListEntryPlayTime(entry); });
if (!entry->serial.empty())
{
connect(menu.addAction(tr("Check Wiki Page")), &QAction::triggered, [this, entry]() { goToWikiPage(entry); });
}
menu.addSeparator();
if (!s_vm_valid)
@@ -2664,7 +2670,7 @@ void MainWindow::setGameListEntryCoverImage(const GameList::Entry* entry)
return;
const QString old_filename = QString::fromStdString(GameList::GetCoverImagePathForEntry(entry));
const QString new_filename = QString::fromStdString(GameList::GetNewCoverImagePathForEntry(entry, filename.toUtf8().constData()));
const QString new_filename = QString::fromStdString(GameList::GetNewCoverImagePathForEntry(entry, filename.toUtf8().constData(), true));
if (new_filename.isEmpty())
return;
@@ -2718,6 +2724,11 @@ void MainWindow::clearGameListEntryPlayTime(const GameList::Entry* entry)
m_game_list_widget->refresh(false);
}
void MainWindow::goToWikiPage(const GameList::Entry* entry)
{
QtUtils::OpenURL(this, fmt::format("https://wiki.pcsx2.net/{}", entry->serial).c_str());
}
std::optional<bool> MainWindow::promptForResumeState(const QString& save_state_path)
{
if (save_state_path.isEmpty())

View File

@@ -171,7 +171,7 @@ private Q_SLOTS:
void onSaveGSDumpActionTriggered();
void onBlockDumpActionToggled(bool checked);
void onShowAdvancedSettingsToggled(bool checked);
void onToolsVideoCaptureToggled(bool checked);
void onVideoCaptureToggled(bool checked);
void onSettingsTriggeredFromToolbar();
// Input Recording
@@ -267,6 +267,7 @@ private:
const GameList::Entry* entry, std::optional<s32> save_slot = std::nullopt, std::optional<bool> fast_boot = std::nullopt);
void setGameListEntryCoverImage(const GameList::Entry* entry);
void clearGameListEntryPlayTime(const GameList::Entry* entry);
void goToWikiPage(const GameList::Entry* entry);
std::optional<bool> promptForResumeState(const QString& save_state_path);
void loadSaveStateSlot(s32 slot);

View File

@@ -210,7 +210,7 @@
<addaction name="separator"/>
<addaction name="actionToggleSoftwareRendering"/>
<addaction name="menuInputRecording"/>
<addaction name="actionToolsVideoCapture"/>
<addaction name="actionVideoCapture"/>
<addaction name="separator"/>
<addaction name="actionEnableSystemConsole"/>
<addaction name="actionEnableDebugConsole"/>
@@ -260,7 +260,9 @@
<addaction name="actionToolbarReset"/>
<addaction name="actionToolbarPause"/>
<addaction name="actionToolbarChangeDisc"/>
<addaction name="separator"/>
<addaction name="actionToolbarScreenshot"/>
<addaction name="actionVideoCapture"/>
<addaction name="separator"/>
<addaction name="actionToolbarLoadState"/>
<addaction name="actionToolbarSaveState"/>
@@ -1080,13 +1082,17 @@
<string>Recording Viewer</string>
</property>
</action>
<action name="actionToolsVideoCapture">
<action name="actionVideoCapture">
<property name="checkable">
<bool>true</bool>
</property>
<property name="text">
<string>Video Capture</string>
</property>
<property name="icon">
<iconset theme="camera-video">
<normaloff>.</normaloff>.</iconset>
</property>
</action>
<action name="actionEditCheats">
<property name="text">

View File

@@ -24,8 +24,11 @@
#include "SettingWidgetBinder.h"
#include "ui_USBBindingWidget_DrivingForce.h"
#include "ui_USBBindingWidget_Gametrak.h"
#include "ui_USBBindingWidget_GTForce.h"
#include "ui_USBBindingWidget_GunCon2.h"
#include "ui_USBBindingWidget_RealPlay.h"
#include "ui_USBBindingWidget_TranceVibrator.h"
ControllerBindingWidget::ControllerBindingWidget(QWidget* parent, ControllerSettingsWindow* dialog, u32 port)
: QWidget(parent)
@@ -963,6 +966,7 @@ QIcon USBDeviceWidget::getIcon() const
{"hidmouse", "mouse-line"}, // HID Mouse
{"RBDrumKit", "drum-line"}, // Rock Band Drum Kit
{"BuzzDevice", "buzz-controller-line"}, // Buzz Controller
{"TranceVibrator", "trance-vibrator-line"}, // Trance Vibrator
{"webcam", "eyetoy-line"}, // EyeToy
{"beatmania", "keyboard-2-line"}, // BeatMania Da Da Da!! (Konami Keyboard)
{"seamic", "seamic-line"}, // SEGA Seamic
@@ -1300,6 +1304,13 @@ void USBBindingWidget::bindWidgets(std::span<const InputBindingInfo> bindings)
widget->initialize(sif, bi.bind_type, getConfigSection(), getBindingKey(bi.name));
}
if (bi.bind_type == InputBindingInfo::Type::Motor)
{
InputVibrationBindingWidget* widget = findChild<InputVibrationBindingWidget*>(QString::fromUtf8(bi.name));
if (widget)
widget->setKey(getDialog(), getConfigSection(), getBindingKey(bi.name));
}
}
}
@@ -1322,11 +1333,26 @@ USBBindingWidget* USBBindingWidget::createInstance(
has_template = true;
}
}
else if (type == "Gametrak")
{
Ui::USBBindingWidget_Gametrak().setupUi(widget);
has_template = true;
}
else if (type == "guncon2")
{
Ui::USBBindingWidget_GunCon2().setupUi(widget);
has_template = true;
}
else if (type == "RealPlay")
{
Ui::USBBindingWidget_RealPlay().setupUi(widget);
has_template = true;
}
else if (type == "TranceVibrator")
{
Ui::USBBindingWidget_TranceVibrator().setupUi(widget);
has_template = true;
}
if (has_template)
widget->bindWidgets(bindings);

View File

@@ -35,10 +35,6 @@ GameSummaryWidget::GameSummaryWidget(const GameList::Entry* entry, SettingsWindo
m_ui.region->setItemIcon(i,
QIcon(QStringLiteral("%1/icons/flags/%2.png").arg(base_path).arg(GameList::RegionToString(static_cast<GameList::Region>(i)))));
}
for (int i = 1; i < m_ui.compatibility->count(); i++)
{
m_ui.compatibility->setItemIcon(i, QIcon(QStringLiteral("%1/icons/star-%2.png").arg(base_path).arg(i)));
}
m_entry_path = entry->path;
populateInputProfiles();
@@ -49,11 +45,13 @@ GameSummaryWidget::GameSummaryWidget(const GameList::Entry* entry, SettingsWindo
connect(m_ui.inputProfile, &QComboBox::currentIndexChanged, this, &GameSummaryWidget::onInputProfileChanged);
connect(m_ui.verify, &QAbstractButton::clicked, this, &GameSummaryWidget::onVerifyClicked);
connect(m_ui.searchHash, &QAbstractButton::clicked, this, &GameSummaryWidget::onSearchHashClicked);
connect(m_ui.checkWiki, &QAbstractButton::clicked, this, [this, entry]() { onCheckWikiClicked(entry); });
bool has_custom_title = false, has_custom_region = false;
GameList::CheckCustomAttributesForPath(m_entry_path, has_custom_title, has_custom_region);
m_ui.restoreTitle->setEnabled(has_custom_title);
m_ui.restoreRegion->setEnabled(has_custom_region);
m_ui.checkWiki->setEnabled(!entry->serial.empty());
}
GameSummaryWidget::~GameSummaryWidget() = default;
@@ -74,7 +72,17 @@ void GameSummaryWidget::populateDetails(const GameList::Entry* entry)
m_ui.crc->setText(QString::fromStdString(fmt::format("{:08X}", entry->crc)));
m_ui.type->setCurrentIndex(static_cast<int>(entry->type));
m_ui.region->setCurrentIndex(static_cast<int>(entry->region));
m_ui.compatibility->setCurrentIndex(static_cast<int>(entry->compatibility_rating));
//: First arg is a GameList compat; second is a string with space followed by star rating OR empty if Unknown compat
m_ui.compatibility->setText(tr("%0%1")
.arg(GameList::EntryCompatibilityRatingToString(entry->compatibility_rating))
.arg([entry]() {
if (entry->compatibility_rating == GameList::CompatibilityRating::Unknown)
return QStringLiteral("");
const qsizetype compatibility_value = static_cast<qsizetype>(entry->compatibility_rating);
//: First arg is filled-in stars for game compatibility; second is empty stars; should be swapped for RTL languages
return tr(" %0%1").arg(QStringLiteral("").repeated(compatibility_value - 1)).arg(QStringLiteral("").repeated(6 - compatibility_value));
}()));
int row = 0;
m_ui.detailsFormLayout->getWidgetPosition(m_ui.titleSort, &row, nullptr);
@@ -348,6 +356,11 @@ void GameSummaryWidget::onSearchHashClicked()
QtUtils::OpenURL(this, fmt::format("http://redump.org/discs/quicksearch/{}", m_redump_search_keyword).c_str());
}
void GameSummaryWidget::onCheckWikiClicked(const GameList::Entry* entry)
{
QtUtils::OpenURL(this, fmt::format("https://wiki.pcsx2.net/{}", entry->serial).c_str());
}
void GameSummaryWidget::setVerifyResult(QString error)
{
m_ui.verify->setVisible(false);

View File

@@ -28,6 +28,7 @@ private Q_SLOTS:
void onDiscPathBrowseClicked();
void onVerifyClicked();
void onSearchHashClicked();
void onCheckWikiClicked(const GameList::Entry* entry);
private:
void populateInputProfiles();

View File

@@ -104,11 +104,25 @@
</widget>
</item>
<item row="4" column="1">
<widget class="QLineEdit" name="serial">
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
<layout class="QHBoxLayout" name="horizontalLayout_8">
<item>
<widget class="QLineEdit" name="serial">
<property name="readOnly">
<bool>true</bool>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="checkWiki">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>Check Wiki</string>
</property>
</widget>
</item>
</layout>
</item>
<item row="5" column="0">
<widget class="QLabel" name="label_36">
@@ -363,54 +377,10 @@
</widget>
</item>
<item row="8" column="1">
<widget class="QComboBox" name="compatibility">
<property name="enabled">
<bool>false</bool>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="editable">
<widget class="QLineEdit" name="compatibility">
<property name="readOnly">
<bool>true</bool>
</property>
<item>
<property name="text">
<string>Unknown</string>
</property>
</item>
<item>
<property name="text">
<string>Not Bootable</string>
</property>
</item>
<item>
<property name="text">
<string>Reaches Intro</string>
</property>
</item>
<item>
<property name="text">
<string>Reaches Menu</string>
</property>
</item>
<item>
<property name="text">
<string>In-Game</string>
</property>
</item>
<item>
<property name="text">
<string>Playable</string>
</property>
</item>
<item>
<property name="text">
<string>Perfect</string>
</property>
</item>
</widget>
</item>
<item row="9" column="0">

View File

@@ -124,6 +124,7 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsWindow* dialog, QWidget*
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.osdShowSettings, "EmuCore/GS", "OsdShowSettings", false);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.osdShowInputs, "EmuCore/GS", "OsdShowInputs", false);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.osdShowFrameTimes, "EmuCore/GS", "OsdShowFrameTimes", false);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.osdShowVersion, "EmuCore/GS", "OsdShowVersion", false);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.warnAboutUnsafeSettings, "EmuCore", "WarnAboutUnsafeSettings", true);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.fxaa, "EmuCore/GS", "fxaa", false);
SettingWidgetBinder::BindWidgetToBoolSetting(sif, m_ui.shadeBoost, "EmuCore/GS", "ShadeBoost", false);
@@ -396,6 +397,7 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsWindow* dialog, QWidget*
&GraphicsSettingsWidget::onEnableAudioCaptureArgumentsChanged);
onCaptureContainerChanged();
onCaptureCodecChanged();
onEnableVideoCaptureChanged();
onEnableVideoCaptureArgumentsChanged();
onVideoCaptureAutoResolutionChanged();
@@ -718,8 +720,11 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsWindow* dialog, QWidget*
dialog->registerWidgetHelp(m_ui.osdShowInputs, tr("Show Inputs"), tr("Unchecked"),
tr("Shows the current controller state of the system in the bottom-left corner of the display."));
dialog->registerWidgetHelp(
m_ui.osdShowFrameTimes, tr("Show Frame Times"), tr("Unchecked"), tr("Displays a graph showing the average frametimes."));
dialog->registerWidgetHelp(m_ui.osdShowFrameTimes, tr("Show Frame Times"), tr("Unchecked"),
tr("Displays a graph showing the average frametimes."));
dialog->registerWidgetHelp(m_ui.osdShowVersion, tr("Show PCSX2 Version"), tr("Unchecked"),
tr("Shows the current PCSX2 version on the top-right corner of the display"));
dialog->registerWidgetHelp(m_ui.warnAboutUnsafeSettings, tr("Warn About Unsafe Settings"), tr("Checked"),
tr("Displays warnings when settings are enabled which may break games."));
@@ -731,6 +736,10 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsWindow* dialog, QWidget*
"<b>If unsure, leave it on default.<b>"));
dialog->registerWidgetHelp(m_ui.videoCaptureFormat, tr("Video Format"), tr("Default"), tr("Selects which Video Format to be used for Video Capture. If by chance the codec does not support the format, the first format available will be used. "
"<b>If unsure, leave it on default.<b>"));
dialog->registerWidgetHelp(m_ui.videoCaptureBitrate, tr("Video Bitrate"), tr("6000 kbps"), tr("Sets the video bitrate to be used. "
"Larger bitrate generally yields better video quality at the cost of larger resulting file size."));
@@ -779,7 +788,7 @@ GraphicsSettingsWidget::GraphicsSettingsWidget(SettingsWindow* dialog, QWidget*
dialog->registerWidgetHelp(m_ui.skipPresentingDuplicateFrames, tr("Skip Presenting Duplicate Frames"), tr("Unchecked"),
tr("Detects when idle frames are being presented in 25/30fps games, and skips presenting those frames. The frame is still "
"rendered, it just means the GPU has more time to complete it (this is NOT frame skipping). Can smooth our frame time "
"rendered, it just means the GPU has more time to complete it (this is NOT frame skipping). Can smooth out frame time "
"fluctuations when the CPU/GPU are near maximum utilization, but makes frame pacing more inconsistent and can increase "
"input lag."));
@@ -910,6 +919,7 @@ void GraphicsSettingsWidget::onCaptureContainerChanged()
SettingWidgetBinder::BindWidgetToStringSetting(
m_dialog->getSettingsInterface(), m_ui.videoCaptureCodec, "EmuCore/GS", "VideoCaptureCodec");
connect(m_ui.videoCaptureCodec, &QComboBox::currentIndexChanged, this, &GraphicsSettingsWidget::onCaptureCodecChanged);
m_ui.audioCaptureCodec->disconnect();
m_ui.audioCaptureCodec->clear();
@@ -925,6 +935,30 @@ void GraphicsSettingsWidget::onCaptureContainerChanged()
m_dialog->getSettingsInterface(), m_ui.audioCaptureCodec, "EmuCore/GS", "AudioCaptureCodec");
}
void GraphicsSettingsWidget::GraphicsSettingsWidget::onCaptureCodecChanged()
{
m_ui.videoCaptureFormat->disconnect();
m_ui.videoCaptureFormat->clear();
//: This string refers to a default pixel format
m_ui.videoCaptureFormat->addItem(tr("Default"), "");
const std::string codec(
m_dialog->getEffectiveStringValue("EmuCore/GS", "VideoCaptureCodec", ""));
if (!codec.empty())
{
for (const auto& [id, name] : GSCapture::GetVideoFormatList(codec.c_str()))
{
const QString qid(QString::number(id));
const QString qname(QString::fromStdString(name));
m_ui.videoCaptureFormat->addItem(qname, qid);
}
}
SettingWidgetBinder::BindWidgetToStringSetting(
m_dialog->getSettingsInterface(), m_ui.videoCaptureFormat, "EmuCore/GS", "VideoCaptureFormat");
}
void GraphicsSettingsWidget::onEnableVideoCaptureChanged()
{
const bool enabled = m_dialog->getEffectiveBoolValue("EmuCore/GS", "EnableVideoCapture", true);

View File

@@ -38,6 +38,7 @@ private Q_SLOTS:
void onTextureReplacementChanged();
void onShadeBoostChanged();
void onCaptureContainerChanged();
void onCaptureCodecChanged();
void onEnableVideoCaptureChanged();
void onEnableVideoCaptureArgumentsChanged();
void onVideoCaptureAutoResolutionChanged();

View File

@@ -1610,59 +1610,17 @@
</item>
<item row="1" column="0" colspan="2">
<layout class="QGridLayout" name="gridLayout_6">
<item row="3" column="1">
<widget class="QCheckBox" name="osdShowIndicators">
<property name="text">
<string>Show Indicators</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QCheckBox" name="osdShowResolution">
<property name="text">
<string>Show Resolution</string>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QCheckBox" name="osdShowInputs">
<property name="text">
<string>Show Inputs</string>
</property>
</widget>
</item>
<item row="2" column="1">
<widget class="QCheckBox" name="osdShowGPU">
<property name="text">
<string>Show GPU Usage</string>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QCheckBox" name="osdShowSettings">
<property name="text">
<string>Show Settings</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QCheckBox" name="osdShowFPS">
<property name="text">
<string>Show FPS</string>
</property>
</widget>
</item>
<item row="0" column="0">
<widget class="QCheckBox" name="osdShowMessages">
<item row="1" column="0">
<widget class="QCheckBox" name="osdShowVersion">
<property name="text">
<string>Show OSD Messages</string>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QCheckBox" name="osdShowGSStats">
<property name="text">
<string>Show Statistics</string>
<string>Show PCSX2 Version</string>
</property>
</widget>
</item>
@@ -1673,27 +1631,76 @@
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QCheckBox" name="osdShowSpeed">
<item row="3" column="1">
<widget class="QCheckBox" name="osdShowIndicators">
<property name="text">
<string>Show Speed Percentages</string>
<string>Show Indicators</string>
</property>
</widget>
</item>
<item row="5" column="1">
<item row="0" column="0">
<widget class="QCheckBox" name="osdShowMessages">
<property name="text">
<string>Show OSD Messages</string>
</property>
</widget>
</item>
<item row="7" column="0">
<widget class="QCheckBox" name="warnAboutUnsafeSettings">
<property name="text">
<string>Warn About Unsafe Settings</string>
</property>
</widget>
</item>
<item row="5" column="0">
<item row="2" column="1">
<widget class="QCheckBox" name="osdShowGPU">
<property name="text">
<string>Show GPU Usage</string>
</property>
</widget>
</item>
<item row="0" column="1">
<widget class="QCheckBox" name="osdShowResolution">
<property name="text">
<string>Show Resolution</string>
</property>
</widget>
</item>
<item row="6" column="1">
<widget class="QCheckBox" name="osdShowFrameTimes">
<property name="text">
<string>Show Frame Times</string>
</property>
</widget>
</item>
<item row="4" column="1">
<widget class="QCheckBox" name="osdShowGSStats">
<property name="text">
<string>Show Statistics</string>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QCheckBox" name="osdShowSpeed">
<property name="text">
<string>Show Speed Percentages</string>
</property>
</widget>
</item>
<item row="6" column="0">
<widget class="QCheckBox" name="osdShowInputs">
<property name="text">
<string>Show Inputs</string>
</property>
</widget>
</item>
<item row="4" column="0">
<widget class="QCheckBox" name="osdShowSettings">
<property name="text">
<string>Show Settings</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
@@ -1840,13 +1847,23 @@
<widget class="QComboBox" name="videoCaptureCodec"/>
</item>
<item row="1" column="0">
<widget class="QLabel" name="videoCaptureFomatLabel">
<property name="text">
<string>Format:</string>
</property>
</widget>
</item>
<item row="1" column="1">
<widget class="QComboBox" name="videoCaptureFormat"/>
</item>
<item row="2" column="0">
<widget class="QLabel" name="videoCaptureBitrateLabel">
<property name="text">
<string>Bitrate:</string>
</property>
</widget>
</item>
<item row="1" column="1">
<item row="2" column="1">
<widget class="QSpinBox" name="videoCaptureBitrate">
<property name="suffix">
<string extracomment="Unit that will appear next to a number. Alter the space or whatever is needed before the text depending on your language."> kbps</string>
@@ -1862,14 +1879,14 @@
</property>
</widget>
</item>
<item row="2" column="0">
<item row="3" column="0">
<widget class="QLabel" name="videoCaptureResolutionLabel">
<property name="text">
<string>Resolution:</string>
</property>
</widget>
</item>
<item row="2" column="1">
<item row="3" column="1">
<layout class="QHBoxLayout" name="horizontalLayout_10" stretch="1,0,1,0">
<item>
<widget class="QSpinBox" name="videoCaptureWidth">
@@ -1919,14 +1936,14 @@
</item>
</layout>
</item>
<item row="3" column="0" colspan="2">
<item row="4" column="0" colspan="2">
<widget class="QCheckBox" name="enableVideoCaptureArguments">
<property name="text">
<string>Extra Arguments</string>
</property>
</widget>
</item>
<item row="4" column="0" colspan="2">
<item row="5" column="0" colspan="2">
<widget class="QLineEdit" name="videoCaptureArguments"/>
</item>
</layout>

View File

@@ -39,6 +39,8 @@ const char* InterfaceSettingsWidget::THEME_NAMES[] = {
QT_TRANSLATE_NOOP("InterfaceSettingsWidget", "Ruby (Black/Red) [Dark]"),
//: Ignore what Crowdin says in this string about "[Light]/[Dark]" being untouchable here, these are not variables in this case and must be translated.
QT_TRANSLATE_NOOP("InterfaceSettingsWidget", "Sapphire (Black/Blue) [Dark]"),
//: Ignore what Crowdin says in this string about "[Light]/[Dark]" being untouchable here, these are not variables in this case and must be translated.
QT_TRANSLATE_NOOP("InterfaceSettingsWidget", "Emerald (Black/Green) [Dark]"),
//: "Custom.qss" must be kept as-is.
QT_TRANSLATE_NOOP("InterfaceSettingsWidget", "Custom.qss [Drop in PCSX2 Folder]"),
nullptr};
@@ -61,6 +63,7 @@ const char* InterfaceSettingsWidget::THEME_VALUES[] = {
"CobaltSky",
"Ruby",
"Sapphire",
"Emerald",
"Custom",
nullptr};

View File

@@ -0,0 +1,436 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>USBBindingWidget_Gametrak</class>
<widget class="QWidget" name="USBBindingWidget_Gametrak">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>1100</width>
<height>500</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<layout class="QGridLayout" name="gridLayout">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item row="0" column="0">
<spacer name="horizontalSpacer0">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</spacer>
</item>
<item row="0" column="1">
<layout class="QVBoxLayout" name="verticalLayout1">
<item>
<widget class="QGroupBox" name="groupBox1">
<property name="title">
<string>Left Hand</string>
</property>
<layout class="QGridLayout" name="gridLayout1">
<item row="0" column="0">
<widget class="QGroupBox" name="groupBox1_X">
<property name="title">
<string>X Axis</string>
</property>
<layout class="QGridLayout" name="gridLayout1_X">
<property name="leftMargin">
<number>6</number>
</property>
<property name="topMargin">
<number>6</number>
</property>
<property name="rightMargin">
<number>6</number>
</property>
<property name="bottomMargin">
<number>6</number>
</property>
<item row="0" column="0">
<widget class="InputBindingWidget" name="LeftX">
<property name="minimumSize">
<size>
<width>130</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>130</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string>PushButton</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label1_X">
<property name="text">
<string>Left=0 / Right=0x3ff</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item row="1" column="0">
<widget class="QGroupBox" name="groupBox1_Y">
<property name="title">
<string>Y Axis</string>
</property>
<layout class="QGridLayout" name="gridLayout1_Y">
<property name="leftMargin">
<number>6</number>
</property>
<property name="topMargin">
<number>6</number>
</property>
<property name="rightMargin">
<number>6</number>
</property>
<property name="bottomMargin">
<number>6</number>
</property>
<item row="0" column="0">
<widget class="InputBindingWidget" name="LeftY">
<property name="minimumSize">
<size>
<width>130</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>130</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string>PushButton</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label1_Y">
<property name="text">
<string>Back=0 / Front=0x3ff</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item row="2" column="0">
<widget class="QGroupBox" name="groupBox1_Z">
<property name="title">
<string>Z Axis</string>
</property>
<layout class="QGridLayout" name="gridLayout1_Z">
<property name="leftMargin">
<number>6</number>
</property>
<property name="topMargin">
<number>6</number>
</property>
<property name="rightMargin">
<number>6</number>
</property>
<property name="bottomMargin">
<number>6</number>
</property>
<item row="0" column="0">
<widget class="InputBindingWidget" name="LeftZ">
<property name="minimumSize">
<size>
<width>130</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>130</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string>PushButton</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label1_Z">
<property name="text">
<string>Top=0 / Bottom=0xfff</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</item>
<item row="0" column="2">
<layout class="QVBoxLayout" name="verticalLayout2">
<item>
<widget class="QGroupBox" name="groupBox2">
<property name="title">
<string>Foot Pedal</string>
</property>
<layout class="QGridLayout" name="gridLayout2">
<property name="leftMargin">
<number>6</number>
</property>
<property name="topMargin">
<number>6</number>
</property>
<property name="rightMargin">
<number>6</number>
</property>
<property name="bottomMargin">
<number>6</number>
</property>
<item row="0" column="0">
<widget class="InputBindingWidget" name="FootPedal">
<property name="minimumSize">
<size>
<width>130</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>130</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string>PushButton</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</item>
<item row="0" column="3">
<layout class="QVBoxLayout" name="verticalLayout3">
<item>
<widget class="QGroupBox" name="groupBox3">
<property name="title">
<string>Right Hand</string>
</property>
<layout class="QGridLayout" name="gridLayout3">
<item row="0" column="0">
<widget class="QGroupBox" name="groupBox3_X">
<property name="title">
<string>X Axis</string>
</property>
<layout class="QGridLayout" name="gridLayout3_X">
<property name="leftMargin">
<number>6</number>
</property>
<property name="topMargin">
<number>6</number>
</property>
<property name="rightMargin">
<number>6</number>
</property>
<property name="bottomMargin">
<number>6</number>
</property>
<item row="0" column="0">
<widget class="InputBindingWidget" name="RightX">
<property name="minimumSize">
<size>
<width>130</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>130</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string>PushButton</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label3_X">
<property name="text">
<string>Left=0 / Right=0x3ff</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item row="1" column="0">
<widget class="QGroupBox" name="groupBox3_Y">
<property name="title">
<string>Y Axis</string>
</property>
<layout class="QGridLayout" name="gridLayout3_Y">
<property name="leftMargin">
<number>6</number>
</property>
<property name="topMargin">
<number>6</number>
</property>
<property name="rightMargin">
<number>6</number>
</property>
<property name="bottomMargin">
<number>6</number>
</property>
<item row="0" column="0">
<widget class="InputBindingWidget" name="RightY">
<property name="minimumSize">
<size>
<width>130</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>130</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string>PushButton</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label3_Y">
<property name="text">
<string>Back=0 / Front=0x3ff</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item row="2" column="0">
<widget class="QGroupBox" name="groupBox3_Z">
<property name="title">
<string>Z Axis</string>
</property>
<layout class="QGridLayout" name="gridLayout3_Z">
<property name="leftMargin">
<number>6</number>
</property>
<property name="topMargin">
<number>6</number>
</property>
<property name="rightMargin">
<number>6</number>
</property>
<property name="bottomMargin">
<number>6</number>
</property>
<item row="0" column="0">
<widget class="InputBindingWidget" name="RightZ">
<property name="minimumSize">
<size>
<width>130</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>130</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string>PushButton</string>
</property>
</widget>
</item>
<item row="1" column="0">
<widget class="QLabel" name="label3_Z">
<property name="text">
<string>Top=0 / Bottom=0xfff</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</item>
<item row="0" column="4">
<spacer name="horizontalSpacer4">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</spacer>
</item>
<item row="1" column="1" colspan="3">
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
</spacer>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>InputBindingWidget</class>
<extends>QPushButton</extends>
<header>Settings/InputBindingWidget.h</header>
</customwidget>
</customwidgets>
<resources>
<include location="../resources/resources.qrc"/>
</resources>
<connections/>
</ui>

View File

@@ -0,0 +1,506 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>USBBindingWidget_RealPlay</class>
<widget class="QWidget" name="USBBindingWidget_RealPlay">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>1100</width>
<height>500</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<layout class="QGridLayout" name="gridLayout">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item row="0" column="2">
<widget class="QGroupBox" name="groupBoxDPadUp">
<property name="title">
<string>D-Pad Up</string>
</property>
<layout class="QGridLayout" name="gridLayoutDPadUp">
<property name="leftMargin">
<number>6</number>
</property>
<property name="topMargin">
<number>6</number>
</property>
<property name="rightMargin">
<number>6</number>
</property>
<property name="bottomMargin">
<number>6</number>
</property>
<item row="0" column="0">
<widget class="InputBindingWidget" name="DPadUp">
<property name="minimumSize">
<size>
<width>130</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>130</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string>PushButton</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item row="2" column="2">
<widget class="QGroupBox" name="groupBoxDPadDown">
<property name="title">
<string>D-Pad Down</string>
</property>
<layout class="QGridLayout" name="gridLayoutDPadDown">
<property name="leftMargin">
<number>6</number>
</property>
<property name="topMargin">
<number>6</number>
</property>
<property name="rightMargin">
<number>6</number>
</property>
<property name="bottomMargin">
<number>6</number>
</property>
<item row="0" column="0">
<widget class="InputBindingWidget" name="DPadDown">
<property name="minimumSize">
<size>
<width>130</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>130</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string>PushButton</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item row="1" column="1">
<widget class="QGroupBox" name="groupBoxDPadLeft">
<property name="title">
<string>D-Pad Left</string>
</property>
<layout class="QGridLayout" name="gridLayoutDPadLeft">
<property name="leftMargin">
<number>6</number>
</property>
<property name="topMargin">
<number>6</number>
</property>
<property name="rightMargin">
<number>6</number>
</property>
<property name="bottomMargin">
<number>6</number>
</property>
<item row="0" column="0">
<widget class="InputBindingWidget" name="DPadLeft">
<property name="minimumSize">
<size>
<width>130</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>130</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string>PushButton</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item row="1" column="3">
<widget class="QGroupBox" name="groupBoxDPadRight">
<property name="title">
<string>D-Pad Right</string>
</property>
<layout class="QGridLayout" name="gridLayoutDPadRight">
<property name="leftMargin">
<number>6</number>
</property>
<property name="topMargin">
<number>6</number>
</property>
<property name="rightMargin">
<number>6</number>
</property>
<property name="bottomMargin">
<number>6</number>
</property>
<item row="0" column="0">
<widget class="InputBindingWidget" name="DPadRight">
<property name="minimumSize">
<size>
<width>130</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>130</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string>PushButton</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item row="0" column="6">
<widget class="QGroupBox" name="groupBoxBtnRed">
<property name="title">
<string>Red</string>
</property>
<layout class="QGridLayout" name="gridLayoutBtnRed">
<property name="leftMargin">
<number>6</number>
</property>
<property name="topMargin">
<number>6</number>
</property>
<property name="rightMargin">
<number>6</number>
</property>
<property name="bottomMargin">
<number>6</number>
</property>
<item row="0" column="0">
<widget class="InputBindingWidget" name="Red">
<property name="minimumSize">
<size>
<width>130</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>130</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string>PushButton</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item row="2" column="6">
<widget class="QGroupBox" name="groupBoxBtnGreen">
<property name="title">
<string>Green</string>
</property>
<layout class="QGridLayout" name="gridLayoutBtnGreen">
<property name="leftMargin">
<number>6</number>
</property>
<property name="topMargin">
<number>6</number>
</property>
<property name="rightMargin">
<number>6</number>
</property>
<property name="bottomMargin">
<number>6</number>
</property>
<item row="0" column="0">
<widget class="InputBindingWidget" name="Green">
<property name="minimumSize">
<size>
<width>130</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>130</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string>PushButton</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item row="1" column="5">
<widget class="QGroupBox" name="groupBoxBtnYellow">
<property name="title">
<string>Yellow</string>
</property>
<layout class="QGridLayout" name="gridLayoutBtnYellow">
<property name="leftMargin">
<number>6</number>
</property>
<property name="topMargin">
<number>6</number>
</property>
<property name="rightMargin">
<number>6</number>
</property>
<property name="bottomMargin">
<number>6</number>
</property>
<item row="0" column="0">
<widget class="InputBindingWidget" name="Yellow">
<property name="minimumSize">
<size>
<width>130</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>130</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string>PushButton</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item row="1" column="7">
<widget class="QGroupBox" name="groupBoxBtnBlue">
<property name="title">
<string>Blue</string>
</property>
<layout class="QGridLayout" name="gridLayoutBtnBlue">
<property name="leftMargin">
<number>6</number>
</property>
<property name="topMargin">
<number>6</number>
</property>
<property name="rightMargin">
<number>6</number>
</property>
<property name="bottomMargin">
<number>6</number>
</property>
<item row="0" column="0">
<widget class="InputBindingWidget" name="Blue">
<property name="minimumSize">
<size>
<width>130</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>130</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string>PushButton</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item row="3" column="3">
<widget class="QGroupBox" name="groupBoxAccelX">
<property name="title">
<string>Accel X</string>
</property>
<layout class="QGridLayout" name="gridLayoutAccelX">
<property name="leftMargin">
<number>6</number>
</property>
<property name="topMargin">
<number>6</number>
</property>
<property name="rightMargin">
<number>6</number>
</property>
<property name="bottomMargin">
<number>6</number>
</property>
<item row="0" column="0">
<widget class="InputBindingWidget" name="AccelX">
<property name="minimumSize">
<size>
<width>130</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>130</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string>PushButton</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item row="3" column="4">
<widget class="QGroupBox" name="groupBoxAccelY">
<property name="title">
<string>Accel Y</string>
</property>
<layout class="QGridLayout" name="gridLayoutAccelY">
<property name="leftMargin">
<number>6</number>
</property>
<property name="topMargin">
<number>6</number>
</property>
<property name="rightMargin">
<number>6</number>
</property>
<property name="bottomMargin">
<number>6</number>
</property>
<item row="0" column="0">
<widget class="InputBindingWidget" name="AccelY">
<property name="minimumSize">
<size>
<width>130</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>130</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string>PushButton</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item row="3" column="5">
<widget class="QGroupBox" name="groupBoxAccelZ">
<property name="title">
<string>Accel Z</string>
</property>
<layout class="QGridLayout" name="gridLayoutAccelZ">
<property name="leftMargin">
<number>6</number>
</property>
<property name="topMargin">
<number>6</number>
</property>
<property name="rightMargin">
<number>6</number>
</property>
<property name="bottomMargin">
<number>6</number>
</property>
<item row="0" column="0">
<widget class="InputBindingWidget" name="AccelZ">
<property name="minimumSize">
<size>
<width>130</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>130</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string>PushButton</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item row="0" column="0" rowspan="4">
<spacer name="horizontalSpacer0">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</spacer>
</item>
<item row="0" column="8" rowspan="4">
<spacer name="horizontalSpacer8">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</spacer>
</item>
<item row="4" column="1" colspan="7">
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
</spacer>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>InputBindingWidget</class>
<extends>QPushButton</extends>
<header>Settings/InputBindingWidget.h</header>
</customwidget>
</customwidgets>
<resources>
<include location="../resources/resources.qrc"/>
</resources>
<connections/>
</ui>

View File

@@ -0,0 +1,116 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>USBBindingWidget_TranceVibrator</class>
<widget class="QWidget" name="USBBindingWidget_TranceVibrator">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>1100</width>
<height>500</height>
</rect>
</property>
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>1100</width>
<height>500</height>
</size>
</property>
<layout class="QGridLayout" name="gridLayout_1">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<number>0</number>
</property>
<item row="0" column="0">
<spacer name="horizontalSpacer0">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</spacer>
</item>
<item row="0" column="1">
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QGroupBox" name="groupBox">
<property name="title">
<string>Motor</string>
</property>
<layout class="QGridLayout" name="gridLayout_2">
<property name="leftMargin">
<number>6</number>
</property>
<property name="topMargin">
<number>6</number>
</property>
<property name="rightMargin">
<number>6</number>
</property>
<property name="bottomMargin">
<number>6</number>
</property>
<item row="0" column="0">
<widget class="InputVibrationBindingWidget" name="Motor">
<property name="minimumSize">
<size>
<width>100</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>16777215</width>
<height>16777215</height>
</size>
</property>
<property name="text">
<string notr="true">PushButton</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</item>
<item row="0" column="2">
<spacer name="horizontalSpacer1">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
</spacer>
</item>
<item row="1" column="1">
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
</spacer>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>InputVibrationBindingWidget</class>
<extends>QPushButton</extends>
<header>Settings/InputBindingWidget.h</header>
</customwidget>
</customwidgets>
<resources>
<include location="../resources/resources.qrc"/>
</resources>
<connections/>
</ui>

View File

@@ -108,28 +108,28 @@ void QtHost::SetStyleFromSettings()
const QColor blue(198, 238, 255);
const QColor blue2(0, 88, 208);
QPalette darkPalette;
darkPalette.setColor(QPalette::Window, darkGray);
darkPalette.setColor(QPalette::WindowText, Qt::white);
darkPalette.setColor(QPalette::Base, black);
darkPalette.setColor(QPalette::AlternateBase, darkGray);
darkPalette.setColor(QPalette::ToolTipBase, blue2);
darkPalette.setColor(QPalette::ToolTipText, Qt::white);
darkPalette.setColor(QPalette::Text, Qt::white);
darkPalette.setColor(QPalette::Button, darkGray);
darkPalette.setColor(QPalette::ButtonText, Qt::white);
darkPalette.setColor(QPalette::Link, blue);
darkPalette.setColor(QPalette::Highlight, blue2);
darkPalette.setColor(QPalette::HighlightedText, Qt::white);
darkPalette.setColor(QPalette::PlaceholderText, QColor(Qt::white).darker());
QPalette darkBluePalette;
darkBluePalette.setColor(QPalette::Window, darkGray);
darkBluePalette.setColor(QPalette::WindowText, Qt::white);
darkBluePalette.setColor(QPalette::Base, black);
darkBluePalette.setColor(QPalette::AlternateBase, darkGray);
darkBluePalette.setColor(QPalette::ToolTipBase, blue2);
darkBluePalette.setColor(QPalette::ToolTipText, Qt::white);
darkBluePalette.setColor(QPalette::Text, Qt::white);
darkBluePalette.setColor(QPalette::Button, darkGray);
darkBluePalette.setColor(QPalette::ButtonText, Qt::white);
darkBluePalette.setColor(QPalette::Link, blue);
darkBluePalette.setColor(QPalette::Highlight, blue2);
darkBluePalette.setColor(QPalette::HighlightedText, Qt::white);
darkBluePalette.setColor(QPalette::PlaceholderText, QColor(Qt::white).darker());
darkPalette.setColor(QPalette::Active, QPalette::Button, darkGray);
darkPalette.setColor(QPalette::Disabled, QPalette::ButtonText, gray);
darkPalette.setColor(QPalette::Disabled, QPalette::WindowText, gray);
darkPalette.setColor(QPalette::Disabled, QPalette::Text, gray);
darkPalette.setColor(QPalette::Disabled, QPalette::Light, darkGray);
darkBluePalette.setColor(QPalette::Active, QPalette::Button, darkGray);
darkBluePalette.setColor(QPalette::Disabled, QPalette::ButtonText, gray);
darkBluePalette.setColor(QPalette::Disabled, QPalette::WindowText, gray);
darkBluePalette.setColor(QPalette::Disabled, QPalette::Text, gray);
darkBluePalette.setColor(QPalette::Disabled, QPalette::Light, darkGray);
qApp->setPalette(darkPalette);
qApp->setPalette(darkBluePalette);
}
else if (theme == "GreyMatter")
{
@@ -143,28 +143,28 @@ void QtHost::SetStyleFromSettings()
const QColor gray(111, 111, 111);
const QColor blue(198, 238, 255);
QPalette darkPalette;
darkPalette.setColor(QPalette::Window, darkGray);
darkPalette.setColor(QPalette::WindowText, Qt::white);
darkPalette.setColor(QPalette::Base, lighterGray);
darkPalette.setColor(QPalette::AlternateBase, darkGray);
darkPalette.setColor(QPalette::ToolTipBase, darkGray);
darkPalette.setColor(QPalette::ToolTipText, Qt::white);
darkPalette.setColor(QPalette::Text, Qt::white);
darkPalette.setColor(QPalette::Button, lighterGray);
darkPalette.setColor(QPalette::ButtonText, Qt::white);
darkPalette.setColor(QPalette::Link, blue);
darkPalette.setColor(QPalette::Highlight, lighterGray.lighter());
darkPalette.setColor(QPalette::HighlightedText, Qt::white);
darkPalette.setColor(QPalette::PlaceholderText, QColor(Qt::white).darker());
QPalette greyMatterPalette;
greyMatterPalette.setColor(QPalette::Window, darkGray);
greyMatterPalette.setColor(QPalette::WindowText, Qt::white);
greyMatterPalette.setColor(QPalette::Base, lighterGray);
greyMatterPalette.setColor(QPalette::AlternateBase, darkGray);
greyMatterPalette.setColor(QPalette::ToolTipBase, darkGray);
greyMatterPalette.setColor(QPalette::ToolTipText, Qt::white);
greyMatterPalette.setColor(QPalette::Text, Qt::white);
greyMatterPalette.setColor(QPalette::Button, lighterGray);
greyMatterPalette.setColor(QPalette::ButtonText, Qt::white);
greyMatterPalette.setColor(QPalette::Link, blue);
greyMatterPalette.setColor(QPalette::Highlight, lighterGray.lighter());
greyMatterPalette.setColor(QPalette::HighlightedText, Qt::white);
greyMatterPalette.setColor(QPalette::PlaceholderText, QColor(Qt::white).darker());
darkPalette.setColor(QPalette::Active, QPalette::Button, lighterGray);
darkPalette.setColor(QPalette::Disabled, QPalette::ButtonText, gray.lighter());
darkPalette.setColor(QPalette::Disabled, QPalette::WindowText, gray.lighter());
darkPalette.setColor(QPalette::Disabled, QPalette::Text, gray.lighter());
darkPalette.setColor(QPalette::Disabled, QPalette::Light, darkGray);
greyMatterPalette.setColor(QPalette::Active, QPalette::Button, lighterGray);
greyMatterPalette.setColor(QPalette::Disabled, QPalette::ButtonText, gray.lighter());
greyMatterPalette.setColor(QPalette::Disabled, QPalette::WindowText, gray.lighter());
greyMatterPalette.setColor(QPalette::Disabled, QPalette::Text, gray.lighter());
greyMatterPalette.setColor(QPalette::Disabled, QPalette::Light, darkGray);
qApp->setPalette(darkPalette);
qApp->setPalette(greyMatterPalette);
}
else if (theme == "UntouchedLagoon")
{
@@ -178,27 +178,27 @@ void QtHost::SetStyleFromSettings()
const QColor tameTeal(160, 190, 185);
const QColor grayBlue(160, 180, 190);
QPalette standardPalette;
standardPalette.setColor(QPalette::Window, tameTeal);
standardPalette.setColor(QPalette::WindowText, black.lighter());
standardPalette.setColor(QPalette::Base, grayBlue);
standardPalette.setColor(QPalette::AlternateBase, tameTeal);
standardPalette.setColor(QPalette::ToolTipBase, tameTeal);
standardPalette.setColor(QPalette::ToolTipText, grayBlue);
standardPalette.setColor(QPalette::Text, black);
standardPalette.setColor(QPalette::Button, tameTeal);
standardPalette.setColor(QPalette::ButtonText, black);
standardPalette.setColor(QPalette::Link, black.lighter());
standardPalette.setColor(QPalette::Highlight, teal);
standardPalette.setColor(QPalette::HighlightedText, grayBlue.lighter());
QPalette untouchedLagoonPalette;
untouchedLagoonPalette.setColor(QPalette::Window, tameTeal);
untouchedLagoonPalette.setColor(QPalette::WindowText, black.lighter());
untouchedLagoonPalette.setColor(QPalette::Base, grayBlue);
untouchedLagoonPalette.setColor(QPalette::AlternateBase, tameTeal);
untouchedLagoonPalette.setColor(QPalette::ToolTipBase, tameTeal);
untouchedLagoonPalette.setColor(QPalette::ToolTipText, grayBlue);
untouchedLagoonPalette.setColor(QPalette::Text, black);
untouchedLagoonPalette.setColor(QPalette::Button, tameTeal);
untouchedLagoonPalette.setColor(QPalette::ButtonText, black);
untouchedLagoonPalette.setColor(QPalette::Link, black.lighter());
untouchedLagoonPalette.setColor(QPalette::Highlight, teal);
untouchedLagoonPalette.setColor(QPalette::HighlightedText, grayBlue.lighter());
standardPalette.setColor(QPalette::Active, QPalette::Button, tameTeal);
standardPalette.setColor(QPalette::Disabled, QPalette::ButtonText, darkteal);
standardPalette.setColor(QPalette::Disabled, QPalette::WindowText, darkteal.lighter());
standardPalette.setColor(QPalette::Disabled, QPalette::Text, darkteal.lighter());
standardPalette.setColor(QPalette::Disabled, QPalette::Light, tameTeal);
untouchedLagoonPalette.setColor(QPalette::Active, QPalette::Button, tameTeal);
untouchedLagoonPalette.setColor(QPalette::Disabled, QPalette::ButtonText, darkteal);
untouchedLagoonPalette.setColor(QPalette::Disabled, QPalette::WindowText, darkteal.lighter());
untouchedLagoonPalette.setColor(QPalette::Disabled, QPalette::Text, darkteal.lighter());
untouchedLagoonPalette.setColor(QPalette::Disabled, QPalette::Light, tameTeal);
qApp->setPalette(standardPalette);
qApp->setPalette(untouchedLagoonPalette);
}
else if (theme == "BabyPastel")
{
@@ -214,27 +214,27 @@ void QtHost::SetStyleFromSettings()
const QColor congoPink(255, 127, 121);
const QColor blue(221, 225, 239);
QPalette standardPalette;
standardPalette.setColor(QPalette::Window, pink);
standardPalette.setColor(QPalette::WindowText, black);
standardPalette.setColor(QPalette::Base, brightPink);
standardPalette.setColor(QPalette::AlternateBase, blue);
standardPalette.setColor(QPalette::ToolTipBase, pink);
standardPalette.setColor(QPalette::ToolTipText, brightPink);
standardPalette.setColor(QPalette::Text, black);
standardPalette.setColor(QPalette::Button, pink);
standardPalette.setColor(QPalette::ButtonText, black);
standardPalette.setColor(QPalette::Link, black);
standardPalette.setColor(QPalette::Highlight, congoPink);
standardPalette.setColor(QPalette::HighlightedText, black);
QPalette babyPastelPalette;
babyPastelPalette.setColor(QPalette::Window, pink);
babyPastelPalette.setColor(QPalette::WindowText, black);
babyPastelPalette.setColor(QPalette::Base, brightPink);
babyPastelPalette.setColor(QPalette::AlternateBase, blue);
babyPastelPalette.setColor(QPalette::ToolTipBase, pink);
babyPastelPalette.setColor(QPalette::ToolTipText, brightPink);
babyPastelPalette.setColor(QPalette::Text, black);
babyPastelPalette.setColor(QPalette::Button, pink);
babyPastelPalette.setColor(QPalette::ButtonText, black);
babyPastelPalette.setColor(QPalette::Link, black);
babyPastelPalette.setColor(QPalette::Highlight, congoPink);
babyPastelPalette.setColor(QPalette::HighlightedText, black);
standardPalette.setColor(QPalette::Active, QPalette::Button, pink);
standardPalette.setColor(QPalette::Disabled, QPalette::ButtonText, redpinkish);
standardPalette.setColor(QPalette::Disabled, QPalette::WindowText, redpinkish);
standardPalette.setColor(QPalette::Disabled, QPalette::Text, redpinkish);
standardPalette.setColor(QPalette::Disabled, QPalette::Light, gray);
babyPastelPalette.setColor(QPalette::Active, QPalette::Button, pink);
babyPastelPalette.setColor(QPalette::Disabled, QPalette::ButtonText, redpinkish);
babyPastelPalette.setColor(QPalette::Disabled, QPalette::WindowText, redpinkish);
babyPastelPalette.setColor(QPalette::Disabled, QPalette::Text, redpinkish);
babyPastelPalette.setColor(QPalette::Disabled, QPalette::Light, gray);
qApp->setPalette(standardPalette);
qApp->setPalette(babyPastelPalette);
}
else if (theme == "PizzaBrown")
{
@@ -250,26 +250,27 @@ void QtHost::SetStyleFromSettings()
const QColor comp(248, 230, 213);
const QColor highlight(188, 100, 60);
QPalette standardPalette;
standardPalette.setColor(QPalette::Window, main);
standardPalette.setColor(QPalette::WindowText, Qt::black);
standardPalette.setColor(QPalette::Base, comp);
standardPalette.setColor(QPalette::AlternateBase, extr);
standardPalette.setColor(QPalette::ToolTipBase, comp);
standardPalette.setColor(QPalette::ToolTipText, Qt::black);
standardPalette.setColor(QPalette::Text, Qt::black);
standardPalette.setColor(QPalette::Button, extr);
standardPalette.setColor(QPalette::ButtonText, 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);
standardPalette.setColor(QPalette::Disabled, QPalette::ButtonText, gray.darker());
standardPalette.setColor(QPalette::Disabled, QPalette::WindowText, gray.darker());
standardPalette.setColor(QPalette::Disabled, QPalette::Text, Qt::gray);
standardPalette.setColor(QPalette::Disabled, QPalette::Light, gray.lighter());
QPalette pizzaPalette;
pizzaPalette.setColor(QPalette::Window, main);
pizzaPalette.setColor(QPalette::WindowText, Qt::black);
pizzaPalette.setColor(QPalette::Base, comp);
pizzaPalette.setColor(QPalette::AlternateBase, extr);
pizzaPalette.setColor(QPalette::ToolTipBase, comp);
pizzaPalette.setColor(QPalette::ToolTipText, Qt::black);
pizzaPalette.setColor(QPalette::Text, Qt::black);
pizzaPalette.setColor(QPalette::Button, extr);
pizzaPalette.setColor(QPalette::ButtonText, Qt::black);
pizzaPalette.setColor(QPalette::Link, highlight.darker());
pizzaPalette.setColor(QPalette::Highlight, highlight);
pizzaPalette.setColor(QPalette::HighlightedText, Qt::white);
pizzaPalette.setColor(QPalette::Active, QPalette::Button, extr);
pizzaPalette.setColor(QPalette::Disabled, QPalette::ButtonText, gray.darker());
pizzaPalette.setColor(QPalette::Disabled, QPalette::WindowText, gray.darker());
pizzaPalette.setColor(QPalette::Disabled, QPalette::Text, Qt::gray);
pizzaPalette.setColor(QPalette::Disabled, QPalette::Light, gray.lighter());
qApp->setPalette(standardPalette);
qApp->setPalette(pizzaPalette);
}
else if (theme == "PCSX2Blue")
{
@@ -283,27 +284,27 @@ void QtHost::SetStyleFromSettings()
const QColor blue(106, 156, 255);
const QColor lightBlue(130, 155, 241);
QPalette standardPalette;
standardPalette.setColor(QPalette::Window, blue2.lighter());
standardPalette.setColor(QPalette::WindowText, blackish);
standardPalette.setColor(QPalette::Base, lightBlue);
standardPalette.setColor(QPalette::AlternateBase, blue2.lighter());
standardPalette.setColor(QPalette::ToolTipBase, blue2);
standardPalette.setColor(QPalette::ToolTipText, Qt::white);
standardPalette.setColor(QPalette::Text, blackish);
standardPalette.setColor(QPalette::Button, blue);
standardPalette.setColor(QPalette::ButtonText, blackish);
standardPalette.setColor(QPalette::Link, darkBlue);
standardPalette.setColor(QPalette::Highlight, Qt::white);
standardPalette.setColor(QPalette::HighlightedText, blackish);
QPalette pcsx2BluePalette;
pcsx2BluePalette.setColor(QPalette::Window, blue2.lighter());
pcsx2BluePalette.setColor(QPalette::WindowText, blackish);
pcsx2BluePalette.setColor(QPalette::Base, lightBlue);
pcsx2BluePalette.setColor(QPalette::AlternateBase, blue2.lighter());
pcsx2BluePalette.setColor(QPalette::ToolTipBase, blue2);
pcsx2BluePalette.setColor(QPalette::ToolTipText, Qt::white);
pcsx2BluePalette.setColor(QPalette::Text, blackish);
pcsx2BluePalette.setColor(QPalette::Button, blue);
pcsx2BluePalette.setColor(QPalette::ButtonText, blackish);
pcsx2BluePalette.setColor(QPalette::Link, darkBlue);
pcsx2BluePalette.setColor(QPalette::Highlight, Qt::white);
pcsx2BluePalette.setColor(QPalette::HighlightedText, blackish);
standardPalette.setColor(QPalette::Active, QPalette::Button, blue);
standardPalette.setColor(QPalette::Disabled, QPalette::ButtonText, darkBlue);
standardPalette.setColor(QPalette::Disabled, QPalette::WindowText, darkBlue);
standardPalette.setColor(QPalette::Disabled, QPalette::Text, darkBlue);
standardPalette.setColor(QPalette::Disabled, QPalette::Light, darkBlue);
pcsx2BluePalette.setColor(QPalette::Active, QPalette::Button, blue);
pcsx2BluePalette.setColor(QPalette::Disabled, QPalette::ButtonText, darkBlue);
pcsx2BluePalette.setColor(QPalette::Disabled, QPalette::WindowText, darkBlue);
pcsx2BluePalette.setColor(QPalette::Disabled, QPalette::Text, darkBlue);
pcsx2BluePalette.setColor(QPalette::Disabled, QPalette::Light, darkBlue);
qApp->setPalette(standardPalette);
qApp->setPalette(pcsx2BluePalette);
}
else if (theme == "ScarletDevilRed")
{
@@ -315,27 +316,27 @@ void QtHost::SetStyleFromSettings()
const QColor purplishRed(120, 45, 69);
const QColor brightRed(200, 45, 69);
QPalette darkPalette;
darkPalette.setColor(QPalette::Window, darkRed);
darkPalette.setColor(QPalette::WindowText, Qt::white);
darkPalette.setColor(QPalette::Base, purplishRed);
darkPalette.setColor(QPalette::AlternateBase, darkRed);
darkPalette.setColor(QPalette::ToolTipBase, darkRed);
darkPalette.setColor(QPalette::ToolTipText, Qt::white);
darkPalette.setColor(QPalette::Text, Qt::white);
darkPalette.setColor(QPalette::Button, purplishRed.darker());
darkPalette.setColor(QPalette::ButtonText, Qt::white);
darkPalette.setColor(QPalette::Link, brightRed);
darkPalette.setColor(QPalette::Highlight, brightRed);
darkPalette.setColor(QPalette::HighlightedText, Qt::white);
QPalette scarletDevilPalette;
scarletDevilPalette.setColor(QPalette::Window, darkRed);
scarletDevilPalette.setColor(QPalette::WindowText, Qt::white);
scarletDevilPalette.setColor(QPalette::Base, purplishRed);
scarletDevilPalette.setColor(QPalette::AlternateBase, darkRed);
scarletDevilPalette.setColor(QPalette::ToolTipBase, darkRed);
scarletDevilPalette.setColor(QPalette::ToolTipText, Qt::white);
scarletDevilPalette.setColor(QPalette::Text, Qt::white);
scarletDevilPalette.setColor(QPalette::Button, purplishRed.darker());
scarletDevilPalette.setColor(QPalette::ButtonText, Qt::white);
scarletDevilPalette.setColor(QPalette::Link, brightRed);
scarletDevilPalette.setColor(QPalette::Highlight, brightRed);
scarletDevilPalette.setColor(QPalette::HighlightedText, Qt::white);
darkPalette.setColor(QPalette::Active, QPalette::Button, purplishRed.darker());
darkPalette.setColor(QPalette::Disabled, QPalette::ButtonText, brightRed);
darkPalette.setColor(QPalette::Disabled, QPalette::WindowText, brightRed);
darkPalette.setColor(QPalette::Disabled, QPalette::Text, brightRed);
darkPalette.setColor(QPalette::Disabled, QPalette::Light, darkRed);
scarletDevilPalette.setColor(QPalette::Active, QPalette::Button, purplishRed.darker());
scarletDevilPalette.setColor(QPalette::Disabled, QPalette::ButtonText, brightRed);
scarletDevilPalette.setColor(QPalette::Disabled, QPalette::WindowText, brightRed);
scarletDevilPalette.setColor(QPalette::Disabled, QPalette::Text, brightRed);
scarletDevilPalette.setColor(QPalette::Disabled, QPalette::Light, darkRed);
qApp->setPalette(darkPalette);
qApp->setPalette(scarletDevilPalette);
}
else if (theme == "VioletAngelPurple")
{
@@ -347,27 +348,27 @@ void QtHost::SetStyleFromSettings()
const QColor darkerPurple(90, 30, 105);
const QColor nauticalPurple(110, 30, 125);
QPalette darkPalette;
darkPalette.setColor(QPalette::Window, blackishblue);
darkPalette.setColor(QPalette::WindowText, Qt::white);
darkPalette.setColor(QPalette::Base, nauticalPurple);
darkPalette.setColor(QPalette::AlternateBase, blackishblue);
darkPalette.setColor(QPalette::ToolTipBase, nauticalPurple);
darkPalette.setColor(QPalette::ToolTipText, Qt::white);
darkPalette.setColor(QPalette::Text, Qt::white);
darkPalette.setColor(QPalette::Button, nauticalPurple.darker());
darkPalette.setColor(QPalette::ButtonText, Qt::white);
darkPalette.setColor(QPalette::Link, darkerPurple.lighter());
darkPalette.setColor(QPalette::Highlight, darkerPurple.lighter());
darkPalette.setColor(QPalette::HighlightedText, Qt::white);
QPalette violetAngelPalette;
violetAngelPalette.setColor(QPalette::Window, blackishblue);
violetAngelPalette.setColor(QPalette::WindowText, Qt::white);
violetAngelPalette.setColor(QPalette::Base, nauticalPurple);
violetAngelPalette.setColor(QPalette::AlternateBase, blackishblue);
violetAngelPalette.setColor(QPalette::ToolTipBase, nauticalPurple);
violetAngelPalette.setColor(QPalette::ToolTipText, Qt::white);
violetAngelPalette.setColor(QPalette::Text, Qt::white);
violetAngelPalette.setColor(QPalette::Button, nauticalPurple.darker());
violetAngelPalette.setColor(QPalette::ButtonText, Qt::white);
violetAngelPalette.setColor(QPalette::Link, darkerPurple.lighter());
violetAngelPalette.setColor(QPalette::Highlight, darkerPurple.lighter());
violetAngelPalette.setColor(QPalette::HighlightedText, Qt::white);
darkPalette.setColor(QPalette::Active, QPalette::Button, nauticalPurple.darker());
darkPalette.setColor(QPalette::Disabled, QPalette::ButtonText, darkerPurple.lighter());
darkPalette.setColor(QPalette::Disabled, QPalette::WindowText, darkerPurple.lighter());
darkPalette.setColor(QPalette::Disabled, QPalette::Text, darkerPurple.darker());
darkPalette.setColor(QPalette::Disabled, QPalette::Light, nauticalPurple);
violetAngelPalette.setColor(QPalette::Active, QPalette::Button, nauticalPurple.darker());
violetAngelPalette.setColor(QPalette::Disabled, QPalette::ButtonText, darkerPurple.lighter());
violetAngelPalette.setColor(QPalette::Disabled, QPalette::WindowText, darkerPurple.lighter());
violetAngelPalette.setColor(QPalette::Disabled, QPalette::Text, darkerPurple.darker());
violetAngelPalette.setColor(QPalette::Disabled, QPalette::Light, nauticalPurple);
qApp->setPalette(darkPalette);
qApp->setPalette(violetAngelPalette);
}
else if (theme == "CobaltSky")
{
@@ -383,27 +384,27 @@ void QtHost::SetStyleFromSettings()
const QColor highlight(36, 93, 218);
const QColor link(0, 202, 255);
QPalette darkPalette;
darkPalette.setColor(QPalette::Window, royalBlue);
darkPalette.setColor(QPalette::WindowText, Qt::white);
darkPalette.setColor(QPalette::Base, royalBlue.lighter());
darkPalette.setColor(QPalette::AlternateBase, darkishBlue);
darkPalette.setColor(QPalette::ToolTipBase, darkishBlue);
darkPalette.setColor(QPalette::ToolTipText, Qt::white);
darkPalette.setColor(QPalette::Text, Qt::white);
darkPalette.setColor(QPalette::Button, lighterBlue);
darkPalette.setColor(QPalette::ButtonText, Qt::white);
darkPalette.setColor(QPalette::Link, link);
darkPalette.setColor(QPalette::Highlight, highlight);
darkPalette.setColor(QPalette::HighlightedText, Qt::white);
QPalette cobaltSkyPalette;
cobaltSkyPalette.setColor(QPalette::Window, royalBlue);
cobaltSkyPalette.setColor(QPalette::WindowText, Qt::white);
cobaltSkyPalette.setColor(QPalette::Base, royalBlue.lighter());
cobaltSkyPalette.setColor(QPalette::AlternateBase, darkishBlue);
cobaltSkyPalette.setColor(QPalette::ToolTipBase, darkishBlue);
cobaltSkyPalette.setColor(QPalette::ToolTipText, Qt::white);
cobaltSkyPalette.setColor(QPalette::Text, Qt::white);
cobaltSkyPalette.setColor(QPalette::Button, lighterBlue);
cobaltSkyPalette.setColor(QPalette::ButtonText, Qt::white);
cobaltSkyPalette.setColor(QPalette::Link, link);
cobaltSkyPalette.setColor(QPalette::Highlight, highlight);
cobaltSkyPalette.setColor(QPalette::HighlightedText, Qt::white);
darkPalette.setColor(QPalette::Active, QPalette::Button, lighterBlue);
darkPalette.setColor(QPalette::Disabled, QPalette::ButtonText, gray);
darkPalette.setColor(QPalette::Disabled, QPalette::WindowText, gray);
darkPalette.setColor(QPalette::Disabled, QPalette::Text, gray);
darkPalette.setColor(QPalette::Disabled, QPalette::Light, gray);
cobaltSkyPalette.setColor(QPalette::Active, QPalette::Button, lighterBlue);
cobaltSkyPalette.setColor(QPalette::Disabled, QPalette::ButtonText, gray);
cobaltSkyPalette.setColor(QPalette::Disabled, QPalette::WindowText, gray);
cobaltSkyPalette.setColor(QPalette::Disabled, QPalette::Text, gray);
cobaltSkyPalette.setColor(QPalette::Disabled, QPalette::Light, gray);
qApp->setPalette(darkPalette);
qApp->setPalette(cobaltSkyPalette);
}
else if (theme == "Ruby")
{
@@ -415,27 +416,27 @@ void QtHost::SetStyleFromSettings()
const QColor slate(18, 18, 18);
const QColor rubyish(172, 21, 31);
QPalette darkPalette;
darkPalette.setColor(QPalette::Window, slate);
darkPalette.setColor(QPalette::WindowText, Qt::white);
darkPalette.setColor(QPalette::Base, slate.lighter());
darkPalette.setColor(QPalette::AlternateBase, slate.lighter());
darkPalette.setColor(QPalette::ToolTipBase, slate);
darkPalette.setColor(QPalette::ToolTipText, Qt::white);
darkPalette.setColor(QPalette::Text, Qt::white);
darkPalette.setColor(QPalette::Button, slate);
darkPalette.setColor(QPalette::ButtonText, Qt::white);
darkPalette.setColor(QPalette::Link, Qt::white);
darkPalette.setColor(QPalette::Highlight, rubyish);
darkPalette.setColor(QPalette::HighlightedText, Qt::white);
QPalette rubyPalette;
rubyPalette.setColor(QPalette::Window, slate);
rubyPalette.setColor(QPalette::WindowText, Qt::white);
rubyPalette.setColor(QPalette::Base, slate.lighter());
rubyPalette.setColor(QPalette::AlternateBase, slate.lighter());
rubyPalette.setColor(QPalette::ToolTipBase, slate);
rubyPalette.setColor(QPalette::ToolTipText, Qt::white);
rubyPalette.setColor(QPalette::Text, Qt::white);
rubyPalette.setColor(QPalette::Button, slate);
rubyPalette.setColor(QPalette::ButtonText, Qt::white);
rubyPalette.setColor(QPalette::Link, Qt::white);
rubyPalette.setColor(QPalette::Highlight, rubyish);
rubyPalette.setColor(QPalette::HighlightedText, Qt::white);
darkPalette.setColor(QPalette::Active, QPalette::Button, slate);
darkPalette.setColor(QPalette::Disabled, QPalette::ButtonText, gray);
darkPalette.setColor(QPalette::Disabled, QPalette::WindowText, gray);
darkPalette.setColor(QPalette::Disabled, QPalette::Text, gray);
darkPalette.setColor(QPalette::Disabled, QPalette::Light, slate.lighter());
rubyPalette.setColor(QPalette::Active, QPalette::Button, slate);
rubyPalette.setColor(QPalette::Disabled, QPalette::ButtonText, gray);
rubyPalette.setColor(QPalette::Disabled, QPalette::WindowText, gray);
rubyPalette.setColor(QPalette::Disabled, QPalette::Text, gray);
rubyPalette.setColor(QPalette::Disabled, QPalette::Light, slate.lighter());
qApp->setPalette(darkPalette);
qApp->setPalette(rubyPalette);
}
else if (theme == "Sapphire")
{
@@ -447,27 +448,59 @@ void QtHost::SetStyleFromSettings()
const QColor slate(18, 18, 18);
const QColor persianBlue(32, 35, 204);
QPalette darkPalette;
darkPalette.setColor(QPalette::Window, slate);
darkPalette.setColor(QPalette::WindowText, Qt::white);
darkPalette.setColor(QPalette::Base, slate.lighter());
darkPalette.setColor(QPalette::AlternateBase, slate.lighter());
darkPalette.setColor(QPalette::ToolTipBase, slate);
darkPalette.setColor(QPalette::ToolTipText, Qt::white);
darkPalette.setColor(QPalette::Text, Qt::white);
darkPalette.setColor(QPalette::Button, slate);
darkPalette.setColor(QPalette::ButtonText, Qt::white);
darkPalette.setColor(QPalette::Link, Qt::white);
darkPalette.setColor(QPalette::Highlight, persianBlue);
darkPalette.setColor(QPalette::HighlightedText, Qt::white);
QPalette sapphirePalette;
sapphirePalette.setColor(QPalette::Window, slate);
sapphirePalette.setColor(QPalette::WindowText, Qt::white);
sapphirePalette.setColor(QPalette::Base, slate.lighter());
sapphirePalette.setColor(QPalette::AlternateBase, slate.lighter());
sapphirePalette.setColor(QPalette::ToolTipBase, slate);
sapphirePalette.setColor(QPalette::ToolTipText, Qt::white);
sapphirePalette.setColor(QPalette::Text, Qt::white);
sapphirePalette.setColor(QPalette::Button, slate);
sapphirePalette.setColor(QPalette::ButtonText, Qt::white);
sapphirePalette.setColor(QPalette::Link, Qt::white);
sapphirePalette.setColor(QPalette::Highlight, persianBlue);
sapphirePalette.setColor(QPalette::HighlightedText, Qt::white);
darkPalette.setColor(QPalette::Active, QPalette::Button, slate);
darkPalette.setColor(QPalette::Disabled, QPalette::ButtonText, gray);
darkPalette.setColor(QPalette::Disabled, QPalette::WindowText, gray);
darkPalette.setColor(QPalette::Disabled, QPalette::Text, gray);
darkPalette.setColor(QPalette::Disabled, QPalette::Light, slate.lighter());
sapphirePalette.setColor(QPalette::Active, QPalette::Button, slate);
sapphirePalette.setColor(QPalette::Disabled, QPalette::ButtonText, gray);
sapphirePalette.setColor(QPalette::Disabled, QPalette::WindowText, gray);
sapphirePalette.setColor(QPalette::Disabled, QPalette::Text, gray);
sapphirePalette.setColor(QPalette::Disabled, QPalette::Light, slate.lighter());
qApp->setPalette(darkPalette);
qApp->setPalette(sapphirePalette);
}
else if (theme == "Emerald")
{
// Custom palette by RedDevilus, Black as main color and Blue as complimentary.
// Alternative dark (black) theme.
qApp->setStyle(QStyleFactory::create("Fusion"));
const QColor gray(128, 128, 128);
const QColor slate(18, 18, 18);
const QColor evergreenEmerald(15, 81, 59);
QPalette emeraldPalette;
emeraldPalette.setColor(QPalette::Window, slate);
emeraldPalette.setColor(QPalette::WindowText, Qt::white);
emeraldPalette.setColor(QPalette::Base, slate.lighter());
emeraldPalette.setColor(QPalette::AlternateBase, slate.lighter());
emeraldPalette.setColor(QPalette::ToolTipBase, slate);
emeraldPalette.setColor(QPalette::ToolTipText, Qt::white);
emeraldPalette.setColor(QPalette::Text, Qt::white);
emeraldPalette.setColor(QPalette::Button, slate);
emeraldPalette.setColor(QPalette::ButtonText, Qt::white);
emeraldPalette.setColor(QPalette::Link, Qt::white);
emeraldPalette.setColor(QPalette::Highlight, evergreenEmerald);
emeraldPalette.setColor(QPalette::HighlightedText, Qt::white);
emeraldPalette.setColor(QPalette::Active, QPalette::Button, slate);
emeraldPalette.setColor(QPalette::Disabled, QPalette::ButtonText, gray);
emeraldPalette.setColor(QPalette::Disabled, QPalette::WindowText, gray);
emeraldPalette.setColor(QPalette::Disabled, QPalette::Text, gray);
emeraldPalette.setColor(QPalette::Disabled, QPalette::Light, slate.lighter());
qApp->setPalette(emeraldPalette);
}
else if (theme == "Custom")
{

File diff suppressed because it is too large Load Diff

View File

@@ -395,9 +395,6 @@
</QtUi>
</ItemGroup>
<ItemGroup>
<QtUi Include="Settings\USBBindingWidget_GunCon2.ui">
<FileType>Document</FileType>
</QtUi>
<QtUi Include="SetupWizardDialog.ui">
<FileType>Document</FileType>
</QtUi>
@@ -422,9 +419,21 @@
<QtUi Include="Settings\USBBindingWidget_DrivingForce.ui">
<FileType>Document</FileType>
</QtUi>
<QtUi Include="Settings\USBBindingWidget_Gametrak.ui">
<FileType>Document</FileType>
</QtUi>
<QtUi Include="Settings\USBBindingWidget_GTForce.ui">
<FileType>Document</FileType>
</QtUi>
<QtUi Include="Settings\USBBindingWidget_GunCon2.ui">
<FileType>Document</FileType>
</QtUi>
<QtUi Include="Settings\USBBindingWidget_RealPlay.ui">
<FileType>Document</FileType>
</QtUi>
<QtUi Include="Settings\USBBindingWidget_TranceVibrator.ui">
<FileType>Document</FileType>
</QtUi>
<QtUi Include="Settings\USBDeviceWidget.ui">
<FileType>Document</FileType>
</QtUi>

View File

@@ -660,12 +660,21 @@
<QtUi Include="Settings\USBBindingWidget_DrivingForce.ui">
<Filter>Settings</Filter>
</QtUi>
<QtUi Include="Settings\USBBindingWidget_Gametrak.ui">
<Filter>Settings</Filter>
</QtUi>
<QtUi Include="Settings\USBBindingWidget_GTForce.ui">
<Filter>Settings</Filter>
</QtUi>
<QtUi Include="Settings\USBBindingWidget_GunCon2.ui">
<Filter>Settings</Filter>
</QtUi>
<QtUi Include="Settings\USBBindingWidget_RealPlay.ui">
<Filter>Settings</Filter>
</QtUi>
<QtUi Include="Settings\USBBindingWidget_TranceVibrator.ui">
<Filter>Settings</Filter>
</QtUi>
<QtUi Include="Settings\AudioExpansionSettingsDialog.ui">
<Filter>Settings</Filter>
</QtUi>

View File

@@ -0,0 +1,7 @@
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Transformed by: SVG Repo Mixer Tools -->
<svg width="256px" height="256px" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" fill="#000000" class="bi bi-camera-video">
<g id="SVGRepo_bgCarrier" stroke-width="0"/>
<g id="SVGRepo_tracerCarrier" stroke-linecap="round" stroke-linejoin="round"/>

After

Width:  |  Height:  |  Size: 782 B

View File

@@ -0,0 +1,19 @@
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 -10 100 110" >
<g>
<path
fill="none"
stroke="black"
stroke-width="8"
stroke-miterlimit="5"
d="m 0 50
l 20,0
l 7.5,20
l 15,-45
l 15,55
l 15,-65
l 7.5,35
l 20,0" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 332 B

View File

@@ -0,0 +1,7 @@
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Transformed by: SVG Repo Mixer Tools -->
<svg width="256px" height="256px" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg" fill="#ffffff" class="bi bi-camera-video">
<g id="SVGRepo_bgCarrier" stroke-width="0"/>
<g id="SVGRepo_tracerCarrier" stroke-linecap="round" stroke-linejoin="round"/>

After

Width:  |  Height:  |  Size: 782 B

View File

@@ -0,0 +1,19 @@
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 -10 100 110" >
<g>
<path
fill="none"
stroke="white"
stroke-width="8"
stroke-miterlimit="5"
d="m 0 50
l 20,0
l 7.5,20
l 15,-45
l 15,55
l 15,-65
l 7.5,35
l 20,0" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 332 B

View File

@@ -9,16 +9,17 @@
<file>icons/black/svg/band-aid-line.svg</file>
<file>icons/black/svg/brush-line.svg</file>
<file>icons/black/svg/buzz-controller-line.svg</file>
<file>icons/black/svg/camera-video.svg</file>
<file>icons/black/svg/cheats-line.svg</file>
<file>icons/black/svg/checkbox-multiple-blank-line.svg</file>
<file>icons/black/svg/chip-line.svg</file>
<file>icons/black/svg/close-line.svg</file>
<file>icons/black/svg/controller-line.svg</file>
<file>icons/black/svg/controller-strike-line.svg</file>
<file>icons/black/svg/debugger-line.svg</file>
<file>icons/black/svg/debug-step-into-line.svg</file>
<file>icons/black/svg/debug-step-out-line.svg</file>
<file>icons/black/svg/debug-step-over-line.svg</file>
<file>icons/black/svg/debugger-line.svg</file>
<file>icons/black/svg/delete-back-2-line.svg</file>
<file>icons/black/svg/disc-2-line.svg</file>
<file>icons/black/svg/disc-eject-line.svg</file>
@@ -82,6 +83,7 @@
<file>icons/black/svg/shut-down-line.svg</file>
<file>icons/black/svg/singstar-line.svg</file>
<file>icons/black/svg/tools-line.svg</file>
<file>icons/black/svg/trance-vibrator-line.svg</file>
<file>icons/black/svg/trash-fill.svg</file>
<file>icons/black/svg/trophy-line.svg</file>
<file>icons/black/svg/tv-2-line.svg</file>
@@ -105,16 +107,17 @@
<file>icons/white/svg/band-aid-line.svg</file>
<file>icons/white/svg/brush-line.svg</file>
<file>icons/white/svg/buzz-controller-line.svg</file>
<file>icons/white/svg/camera-video.svg</file>
<file>icons/white/svg/cheats-line.svg</file>
<file>icons/white/svg/checkbox-multiple-blank-line.svg</file>
<file>icons/white/svg/chip-line.svg</file>
<file>icons/white/svg/close-line.svg</file>
<file>icons/white/svg/controller-line.svg</file>
<file>icons/white/svg/controller-strike-line.svg</file>
<file>icons/white/svg/debugger-line.svg</file>
<file>icons/white/svg/debug-step-into-line.svg</file>
<file>icons/white/svg/debug-step-out-line.svg</file>
<file>icons/white/svg/debug-step-over-line.svg</file>
<file>icons/white/svg/debugger-line.svg</file>
<file>icons/white/svg/delete-back-2-line.svg</file>
<file>icons/white/svg/disc-2-line.svg</file>
<file>icons/white/svg/disc-eject-line.svg</file>
@@ -178,6 +181,7 @@
<file>icons/white/svg/shut-down-line.svg</file>
<file>icons/white/svg/singstar-line.svg</file>
<file>icons/white/svg/tools-line.svg</file>
<file>icons/white/svg/trance-vibrator-line.svg</file>
<file>icons/white/svg/trash-fill.svg</file>
<file>icons/white/svg/trophy-line.svg</file>
<file>icons/white/svg/tv-2-line.svg</file>

View File

@@ -1052,8 +1052,8 @@ void Achievements::DisplayHardcoreDeferredMessage()
if (VMManager::HasValidVM() && EmuConfig.Achievements.HardcoreMode && !s_hardcore_mode &&
ImGuiManager::InitializeFullscreenUI())
{
ImGuiFullscreen::ShowToast(
std::string(), TRANSLATE_STR("Achievements", "Hardcore mode will be enabled on system reset."),
Host::AddIconOSDMessage(
"hardcore_on_reset", ICON_PF_DUMBELL, TRANSLATE_STR("Achievements", "Hardcore mode will be enabled on system reset."),
Host::OSD_WARNING_DURATION);
}
});
@@ -1343,9 +1343,8 @@ void Achievements::HandleServerDisconnectedEvent(const rc_client_event_t* event)
MTGS::RunOnGSThread([]() {
if (ImGuiManager::InitializeFullscreenUI())
{
ImGuiFullscreen::ShowToast(TRANSLATE_STR("Achievements", "Achievements Disconnected"),
TRANSLATE_STR("Achievements", "An unlock request could not be completed. We will keep retrying to submit this request."),
Host::OSD_ERROR_DURATION);
ImGuiFullscreen::AddNotification("achievements_disconnect", Host::OSD_ERROR_DURATION, TRANSLATE_STR("Achievements", "Achievements Disconnected"),
TRANSLATE_STR("Achievements", "An unlock request could not be completed. We will keep retrying to submit this request."), s_game_icon);
}
});
}
@@ -1357,8 +1356,8 @@ void Achievements::HandleServerReconnectedEvent(const rc_client_event_t* event)
MTGS::RunOnGSThread([]() {
if (ImGuiManager::InitializeFullscreenUI())
{
ImGuiFullscreen::ShowToast(TRANSLATE_STR("Achievements", "Achievements Reconnected"),
TRANSLATE_STR("Achievements", "All pending unlock requests have completed."), Host::OSD_INFO_DURATION);
ImGuiFullscreen::AddNotification("achievements_reconnect", Host::OSD_INFO_DURATION, TRANSLATE_STR("Achievements", "Achievements Reconnected"),
TRANSLATE_STR("Achievements", "All pending unlock requests have completed."), s_game_icon);
}
});
}
@@ -1445,7 +1444,7 @@ void Achievements::SetHardcoreMode(bool enabled, bool force_display_message)
MTGS::RunOnGSThread([enabled]() {
if (ImGuiManager::InitializeFullscreenUI())
{
ImGuiFullscreen::ShowToast(std::string(),
Host::AddIconOSDMessage("hardcore_status", ICON_PF_DUMBELL,
enabled ? TRANSLATE_STR("Achievements", "Hardcore mode is now enabled.") :
TRANSLATE_STR("Achievements", "Hardcore mode is now disabled."),
Host::OSD_INFO_DURATION);
@@ -1858,7 +1857,7 @@ void Achievements::ConfirmHardcoreModeDisableAsync(const char* trigger, std::fun
MTGS::RunOnGSThread([trigger = TinyString(trigger), callback = std::move(callback)]() {
if (!FullscreenUI::Initialize())
{
Host::AddOSDMessage(fmt::format(TRANSLATE_FS("Cannot {} while hardcode mode is active.", trigger)),
Host::AddOSDMessage(fmt::format(TRANSLATE_FS("Cannot {} while hardcore mode is active.", trigger)),
Host::OSD_WARNING_DURATION);
callback(false);
return;
@@ -2931,7 +2930,8 @@ void Achievements::LeaderboardFetchNearbyCallback(
if (result != RC_OK)
{
ImGuiFullscreen::ShowToast(TRANSLATE("Achievements", "Leaderboard download failed"), error_message);
ImGuiFullscreen::AddNotification("leaderboard_dl_fail", Host::OSD_INFO_DURATION,
TRANSLATE("Achievements", "Leaderboard Download Failed"), error_message, s_game_icon);
CloseLeaderboard();
return;
}
@@ -2950,7 +2950,8 @@ void Achievements::LeaderboardFetchAllCallback(
if (result != RC_OK)
{
ImGuiFullscreen::ShowToast(TRANSLATE("Achievements", "Leaderboard download failed"), error_message);
ImGuiFullscreen::AddNotification("leaderboard_dl_fail", Host::OSD_INFO_DURATION,
TRANSLATE("Achievements", "Leaderboard Download Failed"), error_message, s_game_icon);
CloseLeaderboard();
return;
}

View File

@@ -383,10 +383,13 @@ set(pcsx2USBSources
USB/usb-mic/usb-mic-singstar.cpp
USB/usb-msd/usb-msd.cpp
USB/usb-pad/lg/lg_ff.cpp
USB/usb-pad/usb-gametrak.cpp
USB/usb-pad/usb-realplay.cpp
USB/usb-pad/usb-pad-ff.cpp
USB/usb-pad/usb-pad-sdl-ff.cpp
USB/usb-pad/usb-pad.cpp
USB/usb-pad/usb-seamic.cpp
USB/usb-pad/usb-trance-vibrator.cpp
USB/usb-pad/usb-turntable.cpp
USB/usb-printer/usb-printer.cpp
)
@@ -417,8 +420,11 @@ set(pcsx2USBHeaders
USB/usb-mic/usb-mic-singstar.h
USB/usb-msd/usb-msd.h
USB/usb-pad/lg/lg_ff.h
USB/usb-pad/usb-gametrak.h
USB/usb-pad/usb-realplay.h
USB/usb-pad/usb-pad-sdl-ff.h
USB/usb-pad/usb-pad.h
USB/usb-pad/usb-trance-vibrator.h
USB/usb-printer/usb-printer.h
)

View File

@@ -621,6 +621,7 @@ struct Pcsx2Config
OsdShowSettings : 1,
OsdShowInputs : 1,
OsdShowFrameTimes : 1,
OsdShowVersion : 1,
HWSpinGPUForReadbacks : 1,
HWSpinCPUForReadbacks : 1,
GPUPaletteConversion : 1,
@@ -730,6 +731,7 @@ struct Pcsx2Config
std::string CaptureContainer = DEFAULT_CAPTURE_CONTAINER;
std::string VideoCaptureCodec;
std::string VideoCaptureFormat;
std::string VideoCaptureParameters;
std::string AudioCaptureCodec;
std::string AudioCaptureParameters;

View File

@@ -96,10 +96,10 @@ namespace PacketReader::IP
{
//If buffer & data point to the same location
//Then no copy is needed
if (data == buffer)
if (data == &buffer[*offset])
return;
memcpy(buffer, data, length);
memcpy(&buffer[*offset], data, length);
*offset += length;
}
virtual IP_Payload* Clone() const

View File

@@ -15,8 +15,11 @@
#endif
#include <algorithm>
#include <bit>
#include <thread>
#include <errno.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
@@ -35,36 +38,38 @@ using namespace PacketReader::IP::ICMP;
using namespace std::chrono_literals;
/* Ping is kindof annoying to do crossplatform
All platforms restrict raw sockets
Windows provides an api for ICMP
ICMP_ECHO_REPLY should always be used, ignore ICMP_ECHO_REPLY32
IP_OPTION_INFORMATION should always be used, ignore IP_OPTION_INFORMATION32
Linux
We have access to raw sockets via CAP_NET_RAW (for pcap)
However we may be missing that cap on some builds
Linux has socket(PF_INET, SOCK_DGRAM, IPPROTO_ICMP), used similar to raw sockets but for ICMP only
Auto filters responses
Requires net.ipv4.ping_group_range sysctl, default off on alot of distros
Timeouts reported via sock_extended_err control messages (with IP_RECVERR socket option set)
Mac
Raw sockets restricted
Mac has socket(PF_INET, SOCK_DGRAM, IPPROTO_ICMP)
No restriction to using it
Implementation differs, is more versatile than linux
Does not auto filter responses
Timeouts reported as a normal packet
FreeBSD
Raw sockets restricted
No unprivilaged ICMP sockets
Timeouts reported as a normal packet??
Ping cli
Present for all platforms, but command args differ
/*
* Ping is kindof annoying to do crossplatform
* All platforms restrict raw sockets
*
* Windows provides an api for ICMP
* ICMP_ECHO_REPLY should always be used, ignore ICMP_ECHO_REPLY32
* IP_OPTION_INFORMATION should always be used, ignore IP_OPTION_INFORMATION32
*
* Linux
* We have access to raw sockets via CAP_NET_RAW (for pcap)
* However we may be missing that cap on some builds
* Also hava socket(PF_INET, SOCK_DGRAM, IPPROTO_ICMP), used similarly to raw sockets, but for ICMP only
* Auto filters responses
* Requires net.ipv4.ping_group_range sysctl, default off on a lot of distros
* Timeouts reported via sock_extended_err control messages (with IP_RECVERR socket option set)
*
* Mac
* Raw sockets restricted
* Mac has socket(PF_INET, SOCK_DGRAM, IPPROTO_ICMP)
* No restriction to using it with ICMP_ECHO
* Implementation differs, is more versatile than linux
* Does not auto filter responses
* Timeouts reported as a normal packet
*
* FreeBSD
* Raw sockets restricted
* No unprivilaged ICMP sockets
* Timeouts reported as a normal packet??
*
* Ping cli
* Present for all platforms, but command args differ
* Not used here
*/
namespace Sessions
@@ -95,29 +100,36 @@ namespace Sessions
return;
}
//Allocate return buffer
//Documentation says + 8 to allow for an ICMP error message
//In testing, ICMP_ECHO_REPLY structure itself was returned with data set to null
/*
* Allocate response buffer
* Documentation says + 8 to allow for an ICMP error message
* In testing, ICMP_ECHO_REPLY structure itself was returned with data set to null
*/
icmpResponseBufferLen = sizeof(ICMP_ECHO_REPLY) + requestSize + 8;
icmpResponseBuffer = std::make_unique<u8[]>(icmpResponseBufferLen);
icmpResponseBuffer = std::make_unique<std::byte[]>(icmpResponseBufferLen);
#elif defined(__POSIX__)
{
/*
* Allocate response buffer
* Size needed depends on which socket protocol (ICMP or raw) we use aswell as os
*/
switch (icmpConnectionKind)
{
//Two different methods for raw/icmp sockets bettween the unix OSes
//Play it safe and only enable when we know which of the two methods we use
// Two different methods for raw/icmp sockets between the Unix OSes
// Play it safe and only enable when we know which of the two methods we use
#if defined(ICMP_SOCKETS_LINUX) || defined(ICMP_SOCKETS_BSD)
case (PingType::ICMP):
icmpSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_ICMP);
if (icmpSocket != -1)
{
#if defined(ICMP_SOCKETS_LINUX)
//Space for ICMP header, as MSG_ERRQUEUE returns what we sent
//An extra +8 required sometimes, for some reason?
// Only need space for ICMP header, as MSG_ERRQUEUE returns data we sent
// Testing found an extra + 8 was required sometimes, for some reason?
icmpResponseBufferLen = 8 + requestSize + 8;
#elif defined(ICMP_SOCKETS_BSD)
//Returned IP Header, ICMP Header & either data or failed ICMP packet
icmpResponseBufferLen = 20 + 8 + std::max(20 + 8, requestSize);
// Returned IP Header, ICMP Header & either data or failed ICMP packet
// Sometimes get full packet in ICMP error response
icmpResponseBufferLen = 20 + 8 + (20 + 8 + requestSize);
#endif
break;
}
@@ -132,16 +144,17 @@ namespace Sessions
if (icmpSocket != -1)
{
#if defined(ICMP_SOCKETS_LINUX)
//We get packet + header
// We get IP packet + ICMP header
icmpResponseBufferLen = 20 + 8 + requestSize;
#elif defined(ICMP_SOCKETS_BSD)
//As above, but we will also directly recive error ICMP messages
// As above, but we will also directly receive error ICMP messages
icmpResponseBufferLen = 20 + 8 + std::max(20 + 8, requestSize);
#endif
break;
}
DevCon.WriteLn("DEV9: ICMP: Failed To Open RAW Socket");
[[fallthrough]];
#endif
default:
@@ -149,11 +162,11 @@ namespace Sessions
return;
}
icmpResponseBuffer = std::make_unique<u8[]>(icmpResponseBufferLen);
icmpResponseBuffer = std::make_unique<std::byte[]>(icmpResponseBufferLen);
#endif
}
bool ICMP_Session::Ping::IsInitialised()
bool ICMP_Session::Ping::IsInitialised() const
{
#ifdef _WIN32
return icmpFile != INVALID_HANDLE_VALUE;
@@ -169,19 +182,29 @@ namespace Sessions
#endif
}
//Note, we can finish reading but have no data
// Returned PingResult.data is only valid when PingResult.type is 0
ICMP_Session::PingResult* ICMP_Session::Ping::Recv()
{
#ifdef _WIN32
if (WaitForSingleObject(icmpEvent, 0) == WAIT_OBJECT_0)
{
ResetEvent(icmpEvent);
//Prep buffer for reasing
[[maybe_unused]] int count = IcmpParseReplies(icmpResponseBuffer.get(), icmpResponseBufferLen);
pxAssert(count == 1);
ICMP_ECHO_REPLY* pingRet = (ICMP_ECHO_REPLY*)icmpResponseBuffer.get();
//Map status to ICMP type/code
const int count = IcmpParseReplies(icmpResponseBuffer.get(), icmpResponseBufferLen);
pxAssert(count <= 1);
// Timeout
if (count == 0)
{
result.type = -2;
result.code = 0;
return &result;
}
// Rely on implicit object creation
const ICMP_ECHO_REPLY* pingRet = reinterpret_cast<ICMP_ECHO_REPLY*>(icmpResponseBuffer.get());
// Map status to ICMP type/code
switch (pingRet->Status)
{
case (IP_SUCCESS):
@@ -208,21 +231,23 @@ namespace Sessions
result.type = 3;
result.code = 4;
break;
case (IP_BAD_ROUTE): //Bad source route
case (IP_BAD_ROUTE): // Bad source route
result.type = 3;
result.code = 5;
break;
case (IP_BAD_DESTINATION):
//I think this could be either
//Destination network unknown
//or
//Destination host unknown
//Use host unkown
/*
* I think this could be mapped to either
* Destination network unknown
* or
* Destination host unknown
* Lets map to host unknown
*/
result.type = 3;
result.code = 7;
break;
case (IP_REQ_TIMED_OUT):
//Return nothing
// Return nothing
result.type = -2;
result.code = 0;
break;
@@ -239,7 +264,7 @@ namespace Sessions
result.code = 0;
break;
//Unexpected Errors
// Unexpected errors
case (IP_BUF_TOO_SMALL):
case (IP_NO_RESOURCES):
case (IP_BAD_OPTION):
@@ -255,7 +280,7 @@ namespace Sessions
}
result.dataLength = pingRet->DataSize;
result.data = (u8*)pingRet->Data;
result.data = static_cast<u8*>(pingRet->Data);
result.address.integer = pingRet->Address;
return &result;
@@ -268,82 +293,30 @@ namespace Sessions
case (PingType::ICMP):
case (PingType::RAW):
{
int ret;
#if defined(ICMP_SOCKETS_BSD)
fd_set sReady;
fd_set sExcept;
timeval nowait{0};
FD_ZERO(&sReady);
FD_ZERO(&sExcept);
FD_SET(icmpSocket, &sReady);
FD_SET(icmpSocket, &sExcept);
ret = select(icmpSocket + 1, &sReady, nullptr, &sExcept, &nowait);
bool hasData;
if (ret == -1)
{
hasData = false;
Console.WriteLn("DEV9: ICMP: select failed. Error Code: %d", errno);
}
else if (FD_ISSET(icmpSocket, &sExcept))
{
hasData = false;
int error = 0;
socklen_t len = sizeof(error);
if (getsockopt(icmpSocket, SOL_SOCKET, SO_ERROR, (char*)&error, &len) < 0)
Console.Error("DEV9: ICMP: Unkown ICMP Connection Error (getsockopt Error: %d)", errno);
else
Console.Error("DEV9: ICMP: Recv Error: %d", error);
}
else
hasData = FD_ISSET(icmpSocket, &sReady);
if (hasData == false)
{
if (std::chrono::steady_clock::now() - icmpDeathClockStart > ICMP_TIMEOUT)
{
result.type = -2;
result.code = 0;
return &result;
}
else
return nullptr;
}
#endif
sockaddr endpoint{0};
sockaddr_in endpoint{};
iovec iov;
iov.iov_base = icmpResponseBuffer.get();
iov.iov_len = icmpResponseBufferLen;
#if defined(ICMP_SOCKETS_LINUX)
//Needs to hold cmsghdr + sock_extended_err + sockaddr_in
//for ICMP error responses (total 44 bytes)
//Unkown for other types of error
u8 cbuff[64];
// Needs to hold cmsghdr + sock_extended_err + sockaddr_in
// for ICMP error responses, this is a total of 44 bytes
// Unknown size needed for other error types
std::byte cbuff[64]{};
#endif
msghdr msg{0};
msghdr msg{};
msg.msg_name = &endpoint;
msg.msg_namelen = sizeof(endpoint);
msg.msg_iov = &iov;
msg.msg_iovlen = 1;
#if defined(ICMP_SOCKETS_LINUX)
ret = recvmsg(icmpSocket, &msg, MSG_DONTWAIT);
#elif defined(ICMP_SOCKETS_BSD)
ret = recvmsg(icmpSocket, &msg, 0);
#endif
int ret = recvmsg(icmpSocket, &msg, 0);
if (ret == -1)
{
int err = errno;
#if defined(ICMP_SOCKETS_LINUX)
if (err == EAGAIN || err == EWOULDBLOCK)
{
if (std::chrono::steady_clock::now() - icmpDeathClockStart > ICMP_TIMEOUT)
@@ -355,14 +328,16 @@ namespace Sessions
else
return nullptr;
}
#if defined(ICMP_SOCKETS_LINUX)
else
{
msg.msg_control = &cbuff;
msg.msg_controllen = sizeof(cbuff);
ret = recvmsg(icmpSocket, &msg, MSG_ERRQUEUE | MSG_DONTWAIT);
ret = recvmsg(icmpSocket, &msg, MSG_ERRQUEUE);
}
#endif
if (ret == -1)
#endif
{
Console.Error("DEV9: ICMP: RecvMsg Error: %d", err);
result.type = -1;
@@ -373,40 +348,59 @@ namespace Sessions
if (msg.msg_flags & MSG_TRUNC)
Console.Error("DEV9: ICMP: RecvMsg Truncated");
#if defined(ICMP_SOCKETS_LINUX)
if (msg.msg_flags & MSG_CTRUNC)
Console.Error("DEV9: ICMP: RecvMsg Control Truncated");
sock_extended_err* ex_err = nullptr;
// On Linux, ICMP errors are stored in control messages retrieved using MSG_ERRQUEUE
sock_extended_err* exErrorPtr = nullptr;
cmsghdr* cmsg;
/* Receive auxiliary data in msgh */
// Search though control messages, taking the latest mesage
// We should only have at most 1 message
for (cmsg = CMSG_FIRSTHDR(&msg); cmsg != NULL; cmsg = CMSG_NXTHDR(&msg, cmsg))
{
if (cmsg->cmsg_level == SOL_IP && cmsg->cmsg_type == IP_RECVERR)
{
ex_err = (sock_extended_err*)CMSG_DATA(cmsg);
pxAssert(!exErrorPtr);
exErrorPtr = reinterpret_cast<sock_extended_err*>(CMSG_DATA(cmsg));
continue;
}
pxAssert(false);
}
if (ex_err != nullptr)
if (exErrorPtr != nullptr)
{
if (ex_err->ee_origin == SO_EE_ORIGIN_ICMP)
{
result.type = ex_err->ee_type;
result.code = ex_err->ee_code;
/*
* The pointer returned cannot be assumed to be suitably aligned for accessing arbitrary payload data types
* So we would need to memcpy sock_extended_err
*/
sock_extended_err exError;
std::memcpy(&exError, exErrorPtr, sizeof(exError));
sockaddr_in* sockaddr = (sockaddr_in*)SO_EE_OFFENDER(ex_err);
result.address = *(IP_Address*)&sockaddr->sin_addr;
// Process the error
if (exError.ee_origin == SO_EE_ORIGIN_ICMP)
{
result.type = exError.ee_type;
result.code = exError.ee_code;
/*
* SO_EE_OFFENDER reads data relative to, but not necessarily included in struct sock_extended_err
* So we need to pass the original pointer provided to us from CMSG_DATA()
* However, the input pointer needs to be of type sock_extended_err*, hence the reinterpret_cast
* The pointer returned may not be suitably aligned (see CMSG_DATA), so we need to memcpy
*/
sockaddr_in errorEndpoint;
std::memcpy(&errorEndpoint, SO_EE_OFFENDER(exErrorPtr), sizeof(errorEndpoint));
result.address = std::bit_cast<IP_Address>(errorEndpoint.sin_addr);
return &result;
}
else
{
Console.Error("DEV9: ICMP: Recv Error %d", ex_err->ee_errno);
Console.Error("DEV9: ICMP: Recv error %d", exError.ee_errno);
result.type = -1;
result.code = ex_err->ee_errno;
result.code = exError.ee_errno;
return &result;
}
}
@@ -424,60 +418,66 @@ namespace Sessions
else
#endif
{
ip* ipHeader = (ip*)icmpResponseBuffer.get();
int headerLength = ipHeader->ip_hl << 2;
// Rely on implicit object creation
const ip* ipHeader = reinterpret_cast<ip*>(icmpResponseBuffer.get());
const int headerLength = ipHeader->ip_hl << 2;
pxAssert(headerLength == 20);
offset = headerLength;
#ifdef __APPLE__
//Apple (old BSD)'s raw IP sockets implementation converts the ip_len field to host byte order
//and additionally subtracts the header length.
//https://www.unix.com/man-page/mojave/4/ip/
// Apple (old BSD)'s raw IP sockets implementation converts the ip_len field to host byte order
// and additionally subtracts the header length.
// https://www.unix.com/man-page/mojave/4/ip/
length = ipHeader->ip_len;
#else
length = ntohs(ipHeader->ip_len) - headerLength;
#endif
}
ICMP_Packet icmp(&icmpResponseBuffer[offset], length);
// Rely on implicit object creation for u8
ICMP_Packet icmp(reinterpret_cast<u8*>(&icmpResponseBuffer[offset]), length);
PayloadPtr* icmpPayload = static_cast<PayloadPtr*>(icmp.GetPayload());
result.type = icmp.type;
result.code = icmp.code;
sockaddr_in* sockaddr = (sockaddr_in*)&endpoint;
result.address = *(IP_Address*)&sockaddr->sin_addr;
result.address = std::bit_cast<IP_Address>(endpoint.sin_addr);
if (icmp.type == 0)
{
//Check if response is to us
// Check if response is for us
if (icmpConnectionKind == PingType::RAW)
{
ICMP_HeaderDataIdentifier headerData(icmp.headerData);
const ICMP_HeaderDataIdentifier headerData(icmp.headerData);
if (headerData.identifier != icmpId)
return nullptr;
}
//While icmp (and its PayloadPtr) will be destroyed when leaving this function
//the data pointed to it persist in icmpResponseBuffer
// While icmp (and its PayloadPtr) will be destroyed when leaving this function
// the data it points to persists in icmpResponseBuffer
result.dataLength = icmpPayload->GetLength();
result.data = icmpPayload->data;
return &result;
}
#if defined(ICMP_SOCKETS_BSD)
// On BSD/Mac, ICMP errors are returned as normal packets
else if (icmp.type == 3 || icmp.type == 4 || icmp.type == 5 || icmp.type == 11)
{
//Check if response is to us
//We need to extract the sent header
// Extract the packet the ICMP message is responding to
IP_Packet ipPacket(icmpPayload->data, icmpPayload->GetLength(), true);
IP_PayloadPtr* ipPayload = static_cast<IP_PayloadPtr*>(ipPacket.GetPayload());
ICMP_Packet retIcmp(ipPayload->data, ipPayload->GetLength());
ICMP_HeaderDataIdentifier headerData(icmp.headerData);
if (ipPacket.protocol != static_cast<u8>(IP_Type::ICMP))
return nullptr;
IP_PayloadPtr* ipPayload = static_cast<IP_PayloadPtr*>(ipPacket.GetPayload());
ICMP_Packet icmpInner(ipPayload->data, ipPayload->GetLength());
// Check if response is for us
const ICMP_HeaderDataIdentifier headerData(icmpInner.headerData);
if (headerData.identifier != icmpId)
return nullptr;
//This response is for us
// This response is for us
return &result;
}
#endif
@@ -487,7 +487,7 @@ namespace Sessions
Console.Error("DEV9: ICMP: Unexpected packet");
pxAssert(false);
#endif
//Assume not for us
// Assume not for us
return nullptr;
}
}
@@ -503,25 +503,25 @@ namespace Sessions
bool ICMP_Session::Ping::Send(IP_Address parAdapterIP, IP_Address parDestIP, int parTimeToLive, PayloadPtr* parPayload)
{
#ifdef _WIN32
//Documentation is incorrect, IP_OPTION_INFORMATION is to be used regardless of platform
IP_OPTION_INFORMATION ipInfo{0};
// Documentation is incorrect, IP_OPTION_INFORMATION is to be used regardless of platform
IP_OPTION_INFORMATION ipInfo{};
ipInfo.Ttl = parTimeToLive;
DWORD ret;
if (parAdapterIP.integer != 0)
ret = IcmpSendEcho2Ex(icmpFile, icmpEvent, nullptr, nullptr, parAdapterIP.integer, parDestIP.integer, parPayload->data, parPayload->GetLength(), &ipInfo, icmpResponseBuffer.get(), icmpResponseBufferLen,
(DWORD)std::chrono::duration_cast<std::chrono::milliseconds>(ICMP_TIMEOUT).count());
static_cast<DWORD>(std::chrono::duration_cast<std::chrono::milliseconds>(ICMP_TIMEOUT).count()));
else
ret = IcmpSendEcho2(icmpFile, icmpEvent, nullptr, nullptr, parDestIP.integer, parPayload->data, parPayload->GetLength(), &ipInfo, icmpResponseBuffer.get(), icmpResponseBufferLen,
(DWORD)std::chrono::duration_cast<std::chrono::milliseconds>(ICMP_TIMEOUT).count());
static_cast<DWORD>(std::chrono::duration_cast<std::chrono::milliseconds>(ICMP_TIMEOUT).count()));
//Documentation states that IcmpSendEcho2 returns ERROR_IO_PENDING
//However, it actully returns zero, with the error set to ERROR_IO_PENDING
// Documentation states that IcmpSendEcho2 returns ERROR_IO_PENDING
// However, it actually returns zero, with the error set to ERROR_IO_PENDING
if (ret == 0)
ret = GetLastError();
if (ret != ERROR_IO_PENDING)
{
Console.Error("DEV9: ICMP: Failed to Send Echo, %d", GetLastError());
Console.Error("DEV9: ICMP: Failed to send echo, %d", GetLastError());
return false;
}
@@ -534,16 +534,16 @@ namespace Sessions
{
icmpDeathClockStart = std::chrono::steady_clock::now();
//broadcast and multicast mignt need extra setsockopts
//I don't think any game will broadcast/multicast ping
// Broadcast and multicast might need extra setsockopts calls
// I don't think any game will do a broadcast/multicast ping
if (parAdapterIP.integer != 0)
{
sockaddr_in endpoint{0};
sockaddr_in endpoint{};
endpoint.sin_family = AF_INET;
*(IP_Address*)&endpoint.sin_addr = parAdapterIP;
endpoint.sin_addr = std::bit_cast<in_addr>(parAdapterIP);
if (bind(icmpSocket, (const sockaddr*)&endpoint, sizeof(endpoint)) == -1)
if (bind(icmpSocket, reinterpret_cast<const sockaddr*>(&endpoint), sizeof(endpoint)) == -1)
{
Console.Error("DEV9: ICMP: Failed to bind socket. Error: %d", errno);
::close(icmpSocket);
@@ -553,8 +553,8 @@ namespace Sessions
}
#if defined(ICMP_SOCKETS_LINUX)
int value = 1;
if (setsockopt(icmpSocket, SOL_IP, IP_RECVERR, (char*)&value, sizeof(value)))
const int value = 1;
if (setsockopt(icmpSocket, SOL_IP, IP_RECVERR, reinterpret_cast<const char*>(&value), sizeof(value)))
{
Console.Error("DEV9: ICMP: Failed to setsockopt IP_RECVERR. Error: %d", errno);
::close(icmpSocket);
@@ -563,8 +563,8 @@ namespace Sessions
}
#endif
// TTL (Note multicast & regular ttl are seperate)
if (setsockopt(icmpSocket, IPPROTO_IP, IP_TTL, (const char*)&parTimeToLive, sizeof(parTimeToLive)) == -1)
// TTL (Note multicast & regular ttl are separate)
if (setsockopt(icmpSocket, IPPROTO_IP, IP_TTL, reinterpret_cast<const char*>(&parTimeToLive), sizeof(parTimeToLive)) == -1)
{
Console.Error("DEV9: ICMP: Failed to set TTL. Error: %d", errno);
::close(icmpSocket);
@@ -572,13 +572,23 @@ namespace Sessions
return false;
}
// Non-blocking
int blocking = 1;
if (ioctl(icmpSocket, FIONBIO, &blocking) == -1)
{
Console.Error("DEV9: ICMP: Failed to set non-blocking. Error: %d", errno);
::close(icmpSocket);
icmpSocket = -1;
return false;
}
#if defined(ICMP_SOCKETS_LINUX)
if (icmpConnectionKind == PingType::ICMP)
{
//We get assigned a port
sockaddr_in endpoint{0};
// We get assigned a port/Id
sockaddr_in endpoint{};
socklen_t endpointsize = sizeof(endpoint);
if (getsockname(icmpSocket, (sockaddr*)&endpoint, &endpointsize) == -1)
if (getsockname(icmpSocket, reinterpret_cast<sockaddr*>(&endpoint), &endpointsize) == -1)
{
Console.Error("DEV9: ICMP: Failed to get id. Error: %d", errno);
::close(icmpSocket);
@@ -591,15 +601,15 @@ namespace Sessions
else
#endif
{
//Use time, in ms, as id
icmpId = (u16)std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()).count();
// Use time, in ms, as id
icmpId = static_cast<u16>(std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::system_clock::now().time_since_epoch()).count());
}
ICMP_Packet icmp(parPayload->Clone());
icmp.type = 8;
icmp.code = 0;
//We only send one icmp packet per identifier
// We only send one icmp packet per identifier
ICMP_HeaderDataIdentifier headerData(icmpId, 1);
headerData.WriteHeaderData(icmp.headerData);
@@ -609,17 +619,27 @@ namespace Sessions
int offset = 0;
icmp.WriteBytes(buffer.get(), &offset);
sockaddr_in endpoint{0};
sockaddr_in endpoint{};
endpoint.sin_family = AF_INET;
*(IP_Address*)&endpoint.sin_addr.s_addr = parDestIP;
endpoint.sin_addr = std::bit_cast<in_addr>(parDestIP);
const int ret = sendto(icmpSocket, buffer.get(), icmp.GetLength(), 0, (const sockaddr*)&endpoint, sizeof(endpoint));
if (ret == -1)
int ret = -1;
while (ret == -1)
{
Console.Error("DEV9: ICMP: Send Error %d", errno);
::close(icmpSocket);
icmpSocket = -1;
return false;
ret = sendto(icmpSocket, buffer.get(), icmp.GetLength(), 0, reinterpret_cast<const sockaddr*>(&endpoint), sizeof(endpoint));
if (ret == -1)
{
const int err = errno;
if (err == EAGAIN || err == EWOULDBLOCK)
std::this_thread::yield();
else
{
Console.Error("DEV9: ICMP: Send error %d", errno);
::close(icmpSocket);
icmpSocket = -1;
return false;
}
}
}
return true;
@@ -665,16 +685,15 @@ namespace Sessions
for (size_t i = 0; i < pings.size(); i++)
{
ICMP_Session::PingResult* pingRet = nullptr;
pingRet = pings[i]->Recv();
const ICMP_Session::PingResult* pingRet = pings[i]->Recv();
if (pingRet != nullptr)
{
Ping* ping = pings[i];
//Remove ping from list and unlock
std::unique_ptr<Ping> ping = std::move(pings[i]);
// Remove ping from list and unlock mutex
pings.erase(pings.begin() + i);
lock.unlock();
//Create return ICMP packet
// Create return ICMP packet
std::optional<ReceivedPayload> ret;
if (pingRet->type >= 0)
{
@@ -686,22 +705,19 @@ namespace Sessions
}
else
{
//We will copy the original packet back here
//Allocate fullsize buffer
u8* temp = new u8[ping->originalPacket->GetLength()];
//Allocate data
int responseSize = ping->originalPacket->GetHeaderLength() + 8;
// Copy the original packet into the returned ICMP packet
// Allocate fullsize buffer
std::vector<u8> temp = std::vector<u8>(ping->originalPacket->GetLength());
// Allocate returned ICMP payload
const int responseSize = ping->originalPacket->GetHeaderLength() + 8;
data = new PayloadData(responseSize);
//Write packet back into bytes
// Write packet into buffer
int offset = 0;
ping->originalPacket->WriteBytes(temp, &offset);
ping->originalPacket->WriteBytes(temp.data(), &offset);
//Copy only needed bytes
memcpy(data->data.get(), temp, responseSize);
//cleanup
delete[] temp;
// Copy only needed bytes
memcpy(data->data.get(), temp.data(), responseSize);
}
std::unique_ptr<ICMP_Packet> pRet = std::make_unique<ICMP_Packet>(data);
@@ -716,16 +732,13 @@ namespace Sessions
else
DevCon.WriteLn("DEV9: ICMP: ICMP timeout");
//free ping
delete ping;
if (ret.has_value())
DevCon.WriteLn("DEV9: ICMP: Return Ping");
if (--open == 0)
RaiseEventConnectionClosed();
if (ret.has_value())
DevCon.WriteLn("DEV9: ICMP: Return Ping");
//Return packet
// Return packet
return ret;
}
}
@@ -741,7 +754,7 @@ namespace Sessions
return false;
}
//Note, expects caller to set ipTimeToLive before calling
// Expects caller to set ipTimeToLive before calling
bool ICMP_Session::Send(PacketReader::IP::IP_Payload* payload, IP_Packet* packet)
{
IP_PayloadPtr* ipPayload = static_cast<IP_PayloadPtr*>(payload);
@@ -751,16 +764,19 @@ namespace Sessions
switch (icmp.type)
{
case 3: //Port Closed
case 3: // Port Closed
switch (icmp.code)
{
case 3:
{
Console.Error("DEV9: ICMP: Recived Packet Rejected, Port Closed");
//RE:Outbreak Hackfix
//TODO, check if still needed
Console.Error("DEV9: ICMP: Received Packet Rejected, Port Closed");
/*
* RE:Outbreak Hackfix
* ICMP port closed messages has an extra 4 bytes of padding before the packet copy
* this can be tested by trying to connect without using the resurrection server DNS
* turbo mode may be needed to trigger the bug, depending on the DNS server's latency
*/
std::unique_ptr<IP_Packet> retPkt;
if ((icmpPayload->data[0] & 0xF0) == (4 << 4))
retPkt = std::make_unique<IP_Packet>(icmpPayload->data, icmpPayload->GetLength(), true);
@@ -776,20 +792,20 @@ namespace Sessions
retPkt = std::make_unique<IP_Packet>(&icmpPayload->data[off], icmpPayload->GetLength(), true);
}
IP_Address srvIP = retPkt->sourceIP;
u8 prot = retPkt->protocol;
const IP_Address srvIP = retPkt->sourceIP;
const u8 prot = retPkt->protocol;
u16 srvPort = 0;
u16 ps2Port = 0;
switch (prot)
{
case (u8)IP_Type::TCP:
case (u8)IP_Type::UDP:
//Read ports directly from the payload
//both UDP and TCP have the same locations for ports
case static_cast<u8>(IP_Type::TCP):
case static_cast<u8>(IP_Type::UDP):
// Read ports directly from the payload
// both UDP and TCP have the same locations for ports
IP_PayloadPtr* payload = static_cast<IP_PayloadPtr*>(retPkt->GetPayload());
int offset = 0;
NetLib::ReadUInt16(payload->data, &offset, &srvPort); //src
NetLib::ReadUInt16(payload->data, &offset, &ps2Port); //dst
NetLib::ReadUInt16(payload->data, &offset, &srvPort); // src
NetLib::ReadUInt16(payload->data, &offset, &ps2Port); // dst
}
ConnectionKey Key{};
@@ -798,7 +814,7 @@ namespace Sessions
Key.ps2Port = ps2Port;
Key.srvPort = srvPort;
//is from Normal Port?
// Is from Normal Port?
BaseSession* s = nullptr;
connections->TryGetValue(Key, &s);
@@ -809,7 +825,7 @@ namespace Sessions
break;
}
//Is from Fixed Port?
// Is from Fixed Port?
Key.ip = {};
Key.srvPort = 0;
connections->TryGetValue(Key, &s);
@@ -827,18 +843,17 @@ namespace Sessions
Console.Error("DEV9: ICMP: Unsupported ICMP Code For Destination Unreachable %d", icmp.code);
}
break;
case 8: //Echo
case 8: // Echo
{
DevCon.WriteLn("DEV9: ICMP: Send Ping");
open++;
Ping* ping = new Ping(icmpPayload->GetLength());
std::unique_ptr<Ping> ping = std::make_unique<Ping>(icmpPayload->GetLength());
if (!ping->IsInitialised())
{
if (--open == 0)
RaiseEventConnectionClosed();
delete ping;
return false;
}
@@ -846,18 +861,17 @@ namespace Sessions
{
if (--open == 0)
RaiseEventConnectionClosed();
delete ping;
return false;
}
memcpy(ping->headerData, icmp.headerData, 4);
//Need to copy IP_Packet, original is stack allocated
// Need to copy IP_Packet, original is stack allocated
ping->originalPacket = std::make_unique<IP_Packet>(*packet);
{
std::scoped_lock lock(ping_mutex);
pings.push_back(ping);
pings.push_back(std::move(ping));
}
break;
@@ -876,10 +890,8 @@ namespace Sessions
ICMP_Session::~ICMP_Session()
{
// Cleanup
std::scoped_lock lock(ping_mutex);
//Cleanup
for (size_t i = 0; i < pings.size(); i++)
delete pings[i];
pings.clear();
}
} // namespace Sessions

View File

@@ -47,30 +47,29 @@ namespace Sessions
static PingType icmpConnectionKind;
//Sockets
// Sockets
int icmpSocket{-1};
std::chrono::steady_clock::time_point icmpDeathClockStart;
u16 icmpId;
#endif
//Return buffers
// Return buffers
PingResult result{};
int icmpResponseBufferLen{0};
std::unique_ptr<u8[]> icmpResponseBuffer;
std::unique_ptr<std::byte[]> icmpResponseBuffer;
public:
Ping(int requestSize);
bool IsInitialised();
bool IsInitialised() const;
PingResult* Recv();
bool Send(PacketReader::IP::IP_Address parAdapterIP, PacketReader::IP::IP_Address parDestIP, int parTimeToLive, PacketReader::PayloadPtr* parPayload);
~Ping();
};
SimpleQueue<PacketReader::IP::ICMP::ICMP_Packet*> _recvBuff;
std::mutex ping_mutex;
std::vector<Ping*> pings;
std::vector<std::unique_ptr<Ping>> pings;
ThreadSafeMap<Sessions::ConnectionKey, Sessions::BaseSession*>* connections;
std::atomic<int> open{0};

View File

@@ -1054,6 +1054,7 @@ static void HotkeyToggleOSD()
GSConfig.OsdShowSettings ^= EmuConfig.GS.OsdShowSettings;
GSConfig.OsdShowInputs ^= EmuConfig.GS.OsdShowInputs;
GSConfig.OsdShowFrameTimes ^= EmuConfig.GS.OsdShowFrameTimes;
GSConfig.OsdShowVersion ^= EmuConfig.GS.OsdShowVersion;
}
BEGIN_HOTKEY_LIST(g_gs_hotkeys){"Screenshot", TRANSLATE_NOOP("Hotkeys", "Graphics"),

View File

@@ -42,6 +42,8 @@ extern "C" {
#include "libavutil/dict.h"
#include "libavutil/opt.h"
#include "libavutil/version.h"
#include "libavutil/channel_layout.h"
#include "libavutil/pixdesc.h"
#include "libswscale/swscale.h"
#include "libswscale/version.h"
#include "libswresample/swresample.h"
@@ -88,7 +90,8 @@ extern "C" {
#else
#define AVUTIL_57_IMPORTS(X) \
X(av_channel_layout_default) \
X(av_channel_layout_copy)
X(av_channel_layout_copy) \
X(av_opt_set_chlayout)
#endif
#define VISIT_AVUTIL_IMPORTS(X) \
@@ -115,7 +118,8 @@ extern "C" {
X(av_hwframe_transfer_data) \
X(av_hwframe_get_buffer) \
X(av_buffer_ref) \
X(av_buffer_unref)
X(av_buffer_unref) \
X(av_get_pix_fmt_name)
#define VISIT_SWSCALE_IMPORTS(X) \
X(sws_getCachedContext) \
@@ -291,11 +295,13 @@ bool GSCapture::LoadFFmpeg(bool report_errors)
{
Host::ReportErrorAsync(TRANSLATE_SV("GSCapture","Failed to load FFmpeg"),
fmt::format(TRANSLATE_FS("GSCapture","You may be missing one or more files, or are using the incorrect version. This build of PCSX2 requires:\n"
" libavcodec: {}\n"
" libavformat: {}\n"
" libavutil: {}\n"
" libswscale: {}\n"
" libswresample: {}\n"), LIBAVCODEC_VERSION_MAJOR, LIBAVFORMAT_VERSION_MAJOR, LIBAVUTIL_VERSION_MAJOR,
" libavcodec: {}\n"
" libavformat: {}\n"
" libavutil: {}\n"
" libswscale: {}\n"
" libswresample: {}\n\n"
"Please see our official documentation for more information."),
LIBAVCODEC_VERSION_MAJOR, LIBAVFORMAT_VERSION_MAJOR, LIBAVUTIL_VERSION_MAJOR,
LIBSWSCALE_VERSION_MAJOR, LIBSWRESAMPLE_VERSION_MAJOR));
}
@@ -445,23 +451,30 @@ bool GSCapture::BeginCapture(float fps, GSVector2i recommendedResolution, float
wrap_av_reduce(&s_video_codec_context->time_base.num, &s_video_codec_context->time_base.den, 10000,
static_cast<s64>(static_cast<double>(fps) * 10000.0), std::numeric_limits<s32>::max());
// Default to YUV 4:2:0 if the codec doesn't specify a pixel format.
AVPixelFormat sw_pix_fmt = AV_PIX_FMT_YUV420P;
// Default to NV12 if not overridden by the user
const AVPixelFormat preferred_sw_pix_fmt = GSConfig.VideoCaptureFormat.empty() ? AV_PIX_FMT_NV12 : static_cast<AVPixelFormat>(std::stoi(GSConfig.VideoCaptureFormat));
AVPixelFormat sw_pix_fmt = preferred_sw_pix_fmt;
if (vcodec->pix_fmts)
{
// Prefer YUV420 given the choice, but otherwise fall back to whatever it supports.
sw_pix_fmt = vcodec->pix_fmts[0];
for (u32 i = 0; vcodec->pix_fmts[i] != AV_PIX_FMT_NONE; i++)
{
if (vcodec->pix_fmts[i] == AV_PIX_FMT_YUV420P)
if (vcodec->pix_fmts[i] == preferred_sw_pix_fmt)
{
sw_pix_fmt = vcodec->pix_fmts[i];
break;
}
}
}
if (sw_pix_fmt == AV_PIX_FMT_VAAPI)
sw_pix_fmt = AV_PIX_FMT_NV12;
s_video_codec_context->pix_fmt = sw_pix_fmt;
if (preferred_sw_pix_fmt != sw_pix_fmt)
Console.Warning("GSCapture: preferred pixel format (%d) was unsupported by the codec. Using (%d) instead.", preferred_sw_pix_fmt, sw_pix_fmt);
// Can we use hardware encoding?
const AVCodecHWConfig* hwconfig = wrap_avcodec_get_hw_config(vcodec, 0);
if (hwconfig && hwconfig->pix_fmt != AV_PIX_FMT_NONE && hwconfig->pix_fmt != sw_pix_fmt)
@@ -688,9 +701,16 @@ bool GSCapture::BeginCapture(float fps, GSVector2i recommendedResolution, float
return false;
}
#if LIBAVUTIL_VERSION_MAJOR >= 57
const AVChannelLayout layout = AV_CHANNEL_LAYOUT_STEREO;
wrap_av_opt_set_chlayout(s_swr_context, "in_chlayout", &layout, 0);
wrap_av_opt_set_chlayout(s_swr_context, "out_chlayout", &layout, 0);
#endif
wrap_av_opt_set_int(s_swr_context, "in_channel_count", AUDIO_CHANNELS, 0);
wrap_av_opt_set_int(s_swr_context, "in_sample_rate", sample_rate, 0);
wrap_av_opt_set_sample_fmt(s_swr_context, "in_sample_fmt", AV_SAMPLE_FMT_S16, 0);
wrap_av_opt_set_int(s_swr_context, "out_channel_count", AUDIO_CHANNELS, 0);
wrap_av_opt_set_int(s_swr_context, "out_sample_rate", sample_rate, 0);
wrap_av_opt_set_sample_fmt(s_swr_context, "out_sample_fmt", s_audio_codec_context->sample_fmt, 0);
@@ -1491,3 +1511,33 @@ GSCapture::CodecList GSCapture::GetAudioCodecList(const char* container)
{
return GetCodecListForContainer(container, AVMEDIA_TYPE_AUDIO);
}
GSCapture::FormatList GSCapture::GetVideoFormatList(const char* codec)
{
FormatList ret;
if (!LoadFFmpeg(false))
return ret;
const AVCodec* v_codec = wrap_avcodec_find_encoder_by_name(codec);
if (!v_codec)
{
Console.Error("(GetVideoFormatList) avcodec_find_encoder_by_name() failed");
return ret;
}
// rawvideo doesn't have a list of formats.
if(v_codec->pix_fmts == nullptr)
{
Console.Error("(GetVideoFormatList) v_codec->pix_fmts is null.");
return ret;
}
for (int i = 0; v_codec->pix_fmts[i] != AVPixelFormat::AV_PIX_FMT_NONE; i++)
{
ret.emplace_back(v_codec->pix_fmts[i], wrap_av_get_pix_fmt_name(v_codec->pix_fmts[i]));
}
return ret;
}

View File

@@ -37,4 +37,8 @@ namespace GSCapture
using CodecList = std::vector<CodecName>;
CodecList GetVideoCodecList(const char* container);
CodecList GetAudioCodecList(const char* container);
using FormatName = std::pair<int , std::string>; // id,name
using FormatList = std::vector<FormatName>;
FormatList GetVideoFormatList(const char* codec);
}; // namespace GSCapture

View File

@@ -4668,7 +4668,6 @@ void GSRendererHW::EmulateBlending(int rt_alpha_min, int rt_alpha_max, const boo
blend.op = GSDevice::OP_ADD;
// Render pass 2: Add or subtract result of render pass 1(Cd) from Cs.
m_conf.blend_second_pass.enable = true;
m_conf.blend_second_pass.blend_hw = 0;
m_conf.blend_second_pass.dither = dither * GSConfig.Dithering;
m_conf.blend_second_pass.blend = {true, blend_second_pass.src, GSDevice::CONST_ONE, blend_second_pass.op, GSDevice::CONST_ONE, GSDevice::CONST_ZERO, false, 0};
}
@@ -4743,8 +4742,12 @@ void GSRendererHW::EmulateBlending(int rt_alpha_min, int rt_alpha_max, const boo
m_conf.ps.blend_hw = static_cast<u8>(HWBlendType::SRC_DOUBLE);
}
if (m_conf.ps.blend_c == 2 && (m_conf.ps.blend_hw == 2 || m_conf.ps.blend_hw == 4 || m_conf.blend_second_pass.blend_hw == 2))
if (m_conf.ps.blend_c == 2 && (m_conf.ps.blend_hw == static_cast<u8>(HWBlendType::SRC_ALPHA_DST_FACTOR)
|| m_conf.ps.blend_hw == static_cast<u8>(HWBlendType::SRC_HALF_ONE_DST_FACTOR)
|| m_conf.blend_second_pass.blend_hw == static_cast<u8>(HWBlendType::SRC_ALPHA_DST_FACTOR)))
{
m_conf.cb_ps.TA_MaxDepth_Af.a = static_cast<float>(AFIX) / 128.0f;
}
const GSDevice::BlendFactor src_factor_alpha = m_conf.blend_second_pass.enable ? GSDevice::CONST_ZERO : GSDevice::CONST_ONE;
const GSDevice::BlendFactor dst_factor_alpha = m_conf.blend_second_pass.enable ? GSDevice::CONST_ONE : GSDevice::CONST_ZERO;

View File

@@ -640,7 +640,7 @@ bool GameDatabaseSchema::GameEntry::configMatchesHWFix(const Pcsx2Config::GSOpti
return (config.UpscaleMultiplier <= 1.0f || config.UserHacks_RoundSprite == value);
case GSHWFixId::NativeScaling:
return (static_cast<int>(config.UserHacks_NativeScaling) == value);
return (config.UpscaleMultiplier <= 1.0f || static_cast<int>(config.UserHacks_NativeScaling) == value);
case GSHWFixId::TexturePreloading:
return (static_cast<int>(config.TexturePreloading) <= value);

View File

@@ -117,14 +117,14 @@ const char* GameList::EntryCompatibilityRatingToString(CompatibilityRating ratin
// clang-format off
switch (rating)
{
case CompatibilityRating::Unknown: return "Unknown";
case CompatibilityRating::Nothing: return "Nothing";
case CompatibilityRating::Intro: return "Intro";
case CompatibilityRating::Menu: return "Menu";
case CompatibilityRating::InGame: return "InGame";
case CompatibilityRating::Playable: return "Playable";
case CompatibilityRating::Perfect: return "Perfect";
default: return "";
case CompatibilityRating::Unknown: return TRANSLATE("GameList", "Unknown");
case CompatibilityRating::Nothing: return TRANSLATE("GameList", "Nothing");
case CompatibilityRating::Intro: return TRANSLATE("GameList", "Intro");
case CompatibilityRating::Menu: return TRANSLATE("GameList", "Menu");
case CompatibilityRating::InGame: return TRANSLATE("GameList", "In-Game");
case CompatibilityRating::Playable: return TRANSLATE("GameList", "Playable");
case CompatibilityRating::Perfect: return TRANSLATE("GameList", "Perfect");
default: return "";
}
// clang-format on
}

View File

@@ -3123,6 +3123,9 @@ void FullscreenUI::DrawInterfaceSettingsPage()
FSUI_CSTR(
"Shows on-screen-display messages when events occur such as save states being created/loaded, screenshots being taken, etc."),
"EmuCore/GS", "OsdShowMessages", true);
DrawToggleSetting(bsi, FSUI_ICONSTR(ICON_FA_INFO, "Show PCSX2 Version"),
FSUI_CSTR("Shows the current PCSX2 version on the top-right corner of the display."), "EmuCore/GS",
"OsdShowVersion", false);
DrawToggleSetting(bsi, FSUI_ICONSTR(ICON_FA_TACHOMETER_ALT, "Show Speed"),
FSUI_CSTR("Shows the current emulation speed of the system in the top-right corner of the display as a percentage."), "EmuCore/GS",
"OsdShowSpeed", false);
@@ -3287,11 +3290,11 @@ void FullscreenUI::DrawEmulationSettingsPage()
MenuHeading(FSUI_CSTR("Speed Control"));
DrawFloatListSetting(bsi, FSUI_ICONSTR(ICON_FA_PLAY,"Normal Speed"), FSUI_CSTR("Sets the speed when running without fast forwarding."), "Framerate",
DrawFloatListSetting(bsi, FSUI_ICONSTR(ICON_FA_PLAY, "Normal Speed"), FSUI_CSTR("Sets the speed when running without fast forwarding."), "Framerate",
"NominalScalar", 1.00f, speed_entries, speed_values, std::size(speed_entries), true);
DrawFloatListSetting(bsi, FSUI_ICONSTR(ICON_FA_FAST_FORWARD,"Fast Forward Speed"), FSUI_CSTR("Sets the speed when using the fast forward hotkey."), "Framerate",
DrawFloatListSetting(bsi, FSUI_ICONSTR(ICON_FA_FAST_FORWARD, "Fast Forward Speed"), FSUI_CSTR("Sets the speed when using the fast forward hotkey."), "Framerate",
"TurboScalar", 2.00f, speed_entries, speed_values, std::size(speed_entries), true);
DrawFloatListSetting(bsi, FSUI_ICONSTR(ICON_PF_SLOW_MOTION,"Slow Motion Speed"), FSUI_CSTR("Sets the speed when using the slow motion hotkey."), "Framerate",
DrawFloatListSetting(bsi, FSUI_ICONSTR(ICON_PF_SLOW_MOTION, "Slow Motion Speed"), FSUI_CSTR("Sets the speed when using the slow motion hotkey."), "Framerate",
"SlomoScalar", 0.50f, speed_entries, speed_values, std::size(speed_entries), true);
MenuHeading(FSUI_CSTR("System Settings"));
@@ -3597,7 +3600,7 @@ void FullscreenUI::DrawGraphicsSettingsPage(SettingsInterface* bsi, bool show_ad
BeginMenuButtons();
MenuHeading(FSUI_CSTR("Renderer"));
DrawStringListSetting(bsi, FSUI_ICONSTR(ICON_FA_PAINT_BRUSH,"Renderer"), FSUI_CSTR("Selects the API used to render the emulated GS."), "EmuCore/GS",
DrawStringListSetting(bsi, FSUI_ICONSTR(ICON_FA_PAINT_BRUSH, "Renderer"), FSUI_CSTR("Selects the API used to render the emulated GS."), "EmuCore/GS",
"Renderer", "-1", s_renderer_names, s_renderer_values, std::size(s_renderer_names), true);
MenuHeading(FSUI_CSTR("Display"));
@@ -3950,7 +3953,7 @@ void FullscreenUI::DrawAudioSettingsPage()
DrawIntRangeSetting(bsi, FSUI_ICONSTR(ICON_FA_VOLUME_UP, "Output Volume"),
FSUI_CSTR("Controls the volume of the audio played on the host."), "SPU2/Output", "OutputVolume", 100,
0, 100, "%d%%");
DrawIntRangeSetting(bsi, FSUI_ICONSTR(ICON_FA_FAST_FORWARD,"Fast Forward Volume"),
DrawIntRangeSetting(bsi, FSUI_ICONSTR(ICON_FA_FAST_FORWARD, "Fast Forward Volume"),
FSUI_CSTR("Controls the volume of the audio played on the host when fast forwarding."), "SPU2/Output",
"FastForwardVolume", 100, 0, 100, "%d%%");
DrawToggleSetting(bsi, FSUI_ICONSTR(ICON_FA_VOLUME_MUTE, "Mute All Sound"),
@@ -6919,6 +6922,7 @@ TRANSLATE_NOOP("FullscreenUI", "On-Screen Display");
TRANSLATE_NOOP("FullscreenUI", "Determines how large the on-screen messages and monitor are.");
TRANSLATE_NOOP("FullscreenUI", "%d%%");
TRANSLATE_NOOP("FullscreenUI", "Shows on-screen-display messages when events occur such as save states being created/loaded, screenshots being taken, etc.");
TRANSLATE_NOOP("FullscreenUI", "Shows the current PCSX2 version on the top-right corner of the display.");
TRANSLATE_NOOP("FullscreenUI", "Shows the current emulation speed of the system in the top-right corner of the display as a percentage.");
TRANSLATE_NOOP("FullscreenUI", "Shows the number of video frames (or v-syncs) displayed per second by the system in the top-right corner of the display.");
TRANSLATE_NOOP("FullscreenUI", "Shows the CPU usage based on threads in the top-right corner of the display.");
@@ -7062,6 +7066,8 @@ TRANSLATE_NOOP("FullscreenUI", "When enabled GPU converts colormap-textures, oth
TRANSLATE_NOOP("FullscreenUI", "Upscaling Fixes");
TRANSLATE_NOOP("FullscreenUI", "Half Pixel Offset");
TRANSLATE_NOOP("FullscreenUI", "Adjusts vertices relative to upscaling.");
TRANSLATE_NOOP("FullscreenUI", "Native Scaling");
TRANSLATE_NOOP("FullscreenUI", "Attempt to do rescaling at native resolution.");
TRANSLATE_NOOP("FullscreenUI", "Round Sprite");
TRANSLATE_NOOP("FullscreenUI", "Adjusts sprite coordinates.");
TRANSLATE_NOOP("FullscreenUI", "Bilinear Upscale");
@@ -7407,20 +7413,22 @@ TRANSLATE_NOOP("FullscreenUI", "Blend (Bottom Field First, Half FPS)");
TRANSLATE_NOOP("FullscreenUI", "Adaptive (Top Field First)");
TRANSLATE_NOOP("FullscreenUI", "Adaptive (Bottom Field First)");
TRANSLATE_NOOP("FullscreenUI", "Native (PS2)");
TRANSLATE_NOOP("FullscreenUI", "1.25x Native");
TRANSLATE_NOOP("FullscreenUI", "1.5x Native");
TRANSLATE_NOOP("FullscreenUI", "1.75x Native");
TRANSLATE_NOOP("FullscreenUI", "2x Native (~720p)");
TRANSLATE_NOOP("FullscreenUI", "2.25x Native");
TRANSLATE_NOOP("FullscreenUI", "2.5x Native");
TRANSLATE_NOOP("FullscreenUI", "2.75x Native");
TRANSLATE_NOOP("FullscreenUI", "3x Native (~1080p)");
TRANSLATE_NOOP("FullscreenUI", "3.5x Native");
TRANSLATE_NOOP("FullscreenUI", "4x Native (~1440p/2K)");
TRANSLATE_NOOP("FullscreenUI", "5x Native (~1620p)");
TRANSLATE_NOOP("FullscreenUI", "6x Native (~2160p/4K)");
TRANSLATE_NOOP("FullscreenUI", "7x Native (~2520p)");
TRANSLATE_NOOP("FullscreenUI", "8x Native (~2880p)");
TRANSLATE_NOOP("FullscreenUI", "1.25x Native (~450px)");
TRANSLATE_NOOP("FullscreenUI", "1.5x Native (~540px)");
TRANSLATE_NOOP("FullscreenUI", "1.75x Native (~630px)");
TRANSLATE_NOOP("FullscreenUI", "2x Native (~720px/HD)");
TRANSLATE_NOOP("FullscreenUI", "2.5x Native (~900px/HD+)");
TRANSLATE_NOOP("FullscreenUI", "3x Native (~1080px/FHD)");
TRANSLATE_NOOP("FullscreenUI", "3.5x Native (~1260px)");
TRANSLATE_NOOP("FullscreenUI", "4x Native (~1440px/QHD)");
TRANSLATE_NOOP("FullscreenUI", "5x Native (~1800px/QHD+)");
TRANSLATE_NOOP("FullscreenUI", "6x Native (~2160px/4K UHD)");
TRANSLATE_NOOP("FullscreenUI", "7x Native (~2520px)");
TRANSLATE_NOOP("FullscreenUI", "8x Native (~2880px/5K UHD)");
TRANSLATE_NOOP("FullscreenUI", "9x Native (~3240px)");
TRANSLATE_NOOP("FullscreenUI", "10x Native (~3600px/6K UHD)");
TRANSLATE_NOOP("FullscreenUI", "11x Native (~3960px)");
TRANSLATE_NOOP("FullscreenUI", "12x Native (~4320px/8K UHD)");
TRANSLATE_NOOP("FullscreenUI", "Nearest");
TRANSLATE_NOOP("FullscreenUI", "Bilinear (Forced)");
TRANSLATE_NOOP("FullscreenUI", "Bilinear (PS2)");
@@ -7478,6 +7486,7 @@ TRANSLATE_NOOP("FullscreenUI", "Normal (Vertex)");
TRANSLATE_NOOP("FullscreenUI", "Special (Texture)");
TRANSLATE_NOOP("FullscreenUI", "Special (Texture - Aggressive)");
TRANSLATE_NOOP("FullscreenUI", "Align To Native");
TRANSLATE_NOOP("FullscreenUI", "Aggressive");
TRANSLATE_NOOP("FullscreenUI", "Half");
TRANSLATE_NOOP("FullscreenUI", "Force Bilinear");
TRANSLATE_NOOP("FullscreenUI", "Force Nearest");
@@ -7559,6 +7568,7 @@ TRANSLATE_NOOP("FullscreenUI", "Double-Click Toggles Fullscreen");
TRANSLATE_NOOP("FullscreenUI", "Hide Cursor In Fullscreen");
TRANSLATE_NOOP("FullscreenUI", "OSD Scale");
TRANSLATE_NOOP("FullscreenUI", "Show Messages");
TRANSLATE_NOOP("FullscreenUI", "Show PCSX2 Version");
TRANSLATE_NOOP("FullscreenUI", "Show Speed");
TRANSLATE_NOOP("FullscreenUI", "Show FPS");
TRANSLATE_NOOP("FullscreenUI", "Show CPU Usage");

View File

@@ -24,6 +24,7 @@
#include "SIO/Pad/PadBase.h"
#include "USB/USB.h"
#include "VMManager.h"
#include "svnrev.h"
#include "common/BitUtils.h"
#include "common/FileSystem.h"
@@ -121,6 +122,7 @@ __ri void ImGuiManager::DrawPerformanceOverlay(float& position_y, float scale, f
{
bool first = true;
const float speed = PerformanceMetrics::GetSpeed();
if (GSConfig.OsdShowFPS)
{
switch (PerformanceMetrics::GetInternalFPSMethod())
@@ -152,6 +154,16 @@ __ri void ImGuiManager::DrawPerformanceOverlay(float& position_y, float scale, f
else
text.append_format(" ({:.0f}%)", target_speed * 100.0f);
}
if (GSConfig.OsdShowVersion)
{
if (GSConfig.OsdShowFPS || GSConfig.OsdShowSpeed)
{
text.append_format(" | ");
}
text.append_format("PCSX2 {}", GIT_REV);
}
if (!text.empty())
{
ImU32 color;

View File

@@ -868,6 +868,19 @@ void InputManager::AddUSBBindings(SettingsInterface& si, u32 port)
}
break;
case InputBindingInfo::Type::Motor:
{
const std::vector<std::string> bindings(si.GetStringList(section.c_str(), bind_name.c_str()));
for (const std::string& binding : bindings)
{
PadVibrationBinding vib;
vib.pad_index = Pad::NUM_CONTROLLER_PORTS + port;
ParseBindingAndGetSource(binding, &vib.motors[0].binding, &vib.motors[0].source);
s_pad_vibration_array.push_back(std::move(vib));
}
}
break;
default:
break;
}
@@ -1219,6 +1232,11 @@ void InputManager::OnInputDeviceDisconnected(const InputBindingKey key, const st
// Vibration
// ------------------------------------------------------------------------
void InputManager::SetUSBVibrationIntensity(u32 port, float large_or_single_motor_intensity, float small_motor_intensity)
{
SetPadVibrationIntensity(Pad::NUM_CONTROLLER_PORTS + port, large_or_single_motor_intensity, small_motor_intensity);
}
void InputManager::SetPadVibrationIntensity(u32 pad_index, float large_or_single_motor_intensity, float small_motor_intensity)
{
for (PadVibrationBinding& pad : s_pad_vibration_array)
@@ -1605,7 +1623,10 @@ void InputManager::UpdateInputSourceState(SettingsInterface& si, std::unique_loc
{
if (s_input_sources[static_cast<u32>(type)])
{
settings_lock.unlock();
s_input_sources[static_cast<u32>(type)]->Shutdown();
settings_lock.lock();
s_input_sources[static_cast<u32>(type)].reset();
}
}

View File

@@ -270,6 +270,7 @@ namespace InputManager
/// Internal method used by pads to dispatch vibration updates to input sources.
/// Intensity is normalized from 0 to 1.
void SetUSBVibrationIntensity(u32 port, float large_or_single_motor_intensity, float small_motor_intensity);
void SetPadVibrationIntensity(u32 pad_index, float large_or_single_motor_intensity, float small_motor_intensity);
/// Zeros all vibration intensities. Call when pausing.

View File

@@ -39,18 +39,18 @@ void iopMemRelease()
// which is performed by MemInit and PsxMemInit()
void iopMemReset()
{
pxAssert( iopMem );
pxAssert(iopMem);
DbgCon.WriteLn("IOP resetting main memory...");
memset(psxMemWLUT, 0, 0x2000 * sizeof(uptr) * 2); // clears both allocations, RLUT and WLUT
memset(psxMemWLUT, 0, 0x2000 * sizeof(uptr) * 2); // clears both allocations, RLUT and WLUT
// Trick! We're accessing RLUT here through WLUT, since it's the non-const pointer.
// So the ones with a 0x2000 prefixed are RLUT tables.
// Map IOP main memory, which is Read/Write, and mirrored three times
// at 0x0, 0x8000, and 0xa000:
for (int i=0; i<0x0080; i++)
for (int i = 0; i < 0x0080; i++)
{
psxMemWLUT[i + 0x0000] = (uptr)&iopMem->Main[(i & 0x1f) << 16];
@@ -78,7 +78,7 @@ void iopMemReset()
psxMemWLUT[i + 0x2000 + 0x1e00] = (uptr)&eeMem->ROM1[i << 16];
}
for (int i = 0; i < 0x0008; i++)
for (int i = 0; i < 0x0040; i++)
{
psxMemWLUT[i + 0x2000 + 0x1e40] = (uptr)&eeMem->ROM2[i << 16];
}
@@ -318,7 +318,7 @@ void iopMemWrite16(u32 mem, u16 value)
default:
psxHu16(mem) = value;
break;
break;
}
} else
{
@@ -443,7 +443,7 @@ void iopMemWrite32(u32 mem, u32 value)
case 0x60:
psHu32(SBUS_F260) = 0;
return;
return;
}
#if PSX_EXTRALOGS
@@ -529,11 +529,11 @@ bool iopMemSafeWriteBytes(u32 mem, const void* src, u32 size)
std::string iopMemReadString(u32 mem, int maxlen)
{
std::string ret;
char c;
std::string ret;
char c;
while ((c = iopMemRead8(mem++)) && maxlen--)
ret.push_back(c);
while ((c = iopMemRead8(mem++)) && maxlen--)
ret.push_back(c);
return ret;
return ret;
}

View File

@@ -11,7 +11,7 @@ namespace Ps2MemSize
static constexpr u32 TotalRam = _1mb * 128;// 128 MB total memory.
static constexpr u32 Rom = _1mb * 4; // 4 MB main rom
static constexpr u32 Rom1 = _1mb * 4; // DVD player
static constexpr u32 Rom2 = 0x00080000; // Chinese rom extension
static constexpr u32 Rom2 = _1mb * 4; // Chinese rom extension
static constexpr u32 Hardware = _64kb;
static constexpr u32 Scratch = _16kb;

View File

@@ -629,6 +629,7 @@ Pcsx2Config::GSOptions::GSOptions()
OsdShowSettings = false;
OsdShowInputs = false;
OsdShowFrameTimes = false;
OsdShowVersion = false;
HWDownloadMode = GSHardwareDownloadMode::Enabled;
HWSpinGPUForReadbacks = false;
@@ -749,6 +750,7 @@ bool Pcsx2Config::GSOptions::OptionsAreEqual(const GSOptions& right) const
OpEqu(CaptureContainer) &&
OpEqu(VideoCaptureCodec) &&
OpEqu(VideoCaptureFormat) &&
OpEqu(VideoCaptureParameters) &&
OpEqu(AudioCaptureCodec) &&
OpEqu(AudioCaptureParameters) &&
@@ -833,6 +835,7 @@ void Pcsx2Config::GSOptions::LoadSave(SettingsWrapper& wrap)
SettingsWrapBitBool(OsdShowSettings);
SettingsWrapBitBool(OsdShowInputs);
SettingsWrapBitBool(OsdShowFrameTimes);
SettingsWrapBitBool(OsdShowVersion);
SettingsWrapBitBool(HWSpinGPUForReadbacks);
SettingsWrapBitBool(HWSpinCPUForReadbacks);
@@ -923,6 +926,7 @@ void Pcsx2Config::GSOptions::LoadSave(SettingsWrapper& wrap)
SettingsWrapEntryEx(CaptureContainer, "CaptureContainer");
SettingsWrapEntryEx(VideoCaptureCodec, "VideoCaptureCodec");
SettingsWrapEntryEx(VideoCaptureFormat, "VideoCaptureFormat");
SettingsWrapEntryEx(VideoCaptureParameters, "VideoCaptureParameters");
SettingsWrapEntryEx(AudioCaptureCodec, "AudioCaptureCodec");
SettingsWrapEntryEx(AudioCaptureParameters, "AudioCaptureParameters");

View File

@@ -97,24 +97,24 @@ void PadData::OverrideActualController() const
PadBase* pad = Pad::GetPad(m_ext_port);
pad->SetRawAnalogs(m_leftAnalog, m_rightAnalog);
pad->Set(PadDualshock2::Inputs::PAD_RIGHT, std::get<1>(m_right));
pad->Set(PadDualshock2::Inputs::PAD_LEFT, std::get<1>(m_left));
pad->Set(PadDualshock2::Inputs::PAD_UP, std::get<1>(m_up));
pad->Set(PadDualshock2::Inputs::PAD_DOWN, std::get<1>(m_down));
pad->SetRawPressureButton(PadDualshock2::Inputs::PAD_RIGHT, m_right);
pad->SetRawPressureButton(PadDualshock2::Inputs::PAD_LEFT, m_left);
pad->SetRawPressureButton(PadDualshock2::Inputs::PAD_UP, m_up);
pad->SetRawPressureButton(PadDualshock2::Inputs::PAD_DOWN, m_down);
pad->Set(PadDualshock2::Inputs::PAD_START, m_start);
pad->Set(PadDualshock2::Inputs::PAD_SELECT, m_select);
pad->Set(PadDualshock2::Inputs::PAD_R3, m_r3);
pad->Set(PadDualshock2::Inputs::PAD_L3, m_l3);
pad->Set(PadDualshock2::Inputs::PAD_SQUARE, std::get<1>(m_square));
pad->Set(PadDualshock2::Inputs::PAD_CROSS, std::get<1>(m_cross));
pad->Set(PadDualshock2::Inputs::PAD_CIRCLE, std::get<1>(m_circle));
pad->Set(PadDualshock2::Inputs::PAD_TRIANGLE, std::get<1>(m_triangle));
pad->SetRawPressureButton(PadDualshock2::Inputs::PAD_SQUARE, m_square);
pad->SetRawPressureButton(PadDualshock2::Inputs::PAD_CROSS, m_cross);
pad->SetRawPressureButton(PadDualshock2::Inputs::PAD_CIRCLE, m_circle);
pad->SetRawPressureButton(PadDualshock2::Inputs::PAD_TRIANGLE, m_triangle);
pad->Set(PadDualshock2::Inputs::PAD_R1, std::get<1>(m_r1));
pad->Set(PadDualshock2::Inputs::PAD_L1, std::get<1>(m_l1));
pad->Set(PadDualshock2::Inputs::PAD_R2, std::get<1>(m_r2));
pad->Set(PadDualshock2::Inputs::PAD_L2, std::get<1>(m_l2));
pad->SetRawPressureButton(PadDualshock2::Inputs::PAD_R1, m_r1);
pad->SetRawPressureButton(PadDualshock2::Inputs::PAD_L1, m_l1);
pad->SetRawPressureButton(PadDualshock2::Inputs::PAD_R2, m_r2);
pad->SetRawPressureButton(PadDualshock2::Inputs::PAD_L2, m_l2);
}
void addButtonInfoToString(std::string label, std::string& str, std::tuple<bool, u8> buttonInfo)

View File

@@ -39,6 +39,7 @@ public: // Public members
virtual void Set(u32 index, float value) = 0;
virtual void SetRawAnalogs(const std::tuple<u8, u8> left, const std::tuple<u8, u8> right) = 0;
virtual void SetRawPressureButton(u32 index, const std::tuple<bool, u8> value) = 0;
virtual void SetAxisScale(float deadzone, float scale) = 0;
virtual float GetVibrationScale(u32 motor) const = 0;
virtual void SetVibrationScale(u32 motor, float scale) = 0;

View File

@@ -560,29 +560,6 @@ void PadDualshock2::Set(u32 index, float value)
return;
}
// Since we reordered the buttons for better UI, we need to remap them here.
static constexpr std::array<u8, Inputs::LENGTH> bitmaskMapping = {{
12, // PAD_UP
13, // PAD_RIGHT
14, // PAD_DOWN
15, // PAD_LEFT
4, // PAD_TRIANGLE
5, // PAD_CIRCLE
6, // PAD_CROSS
7, // PAD_SQUARE
8, // PAD_SELECT
11, // PAD_START
2, // PAD_L1
0, // PAD_L2
3, // PAD_R1
1, // PAD_R2
9, // PAD_L3
10, // PAD_R3
16, // PAD_ANALOG
17, // PAD_PRESSURE
// remainder are analogs and not used here
}};
if (IsAnalogKey(index))
{
this->rawInputs[index] = static_cast<u8>(std::clamp(value * this->axisScale * 255.0f, 0.0f, 255.0f));
@@ -742,6 +719,20 @@ void PadDualshock2::SetRawAnalogs(const std::tuple<u8, u8> left, const std::tupl
this->analogs.ry = std::get<1>(right);
}
void PadDualshock2::SetRawPressureButton(u32 index, const std::tuple<bool, u8> value)
{
this->rawInputs[index] = std::get<1>(value);
if (std::get<0>(value))
{
this->buttons &= ~(1u << bitmaskMapping[index]);
}
else
{
this->buttons |= (1u << bitmaskMapping[index]);
}
}
void PadDualshock2::SetAxisScale(float deadzone, float scale)
{
this->axisDeadzone = deadzone;

View File

@@ -85,6 +85,29 @@ private:
// Used to store the last vibration mapping request the PS2 made for the large motor.
u8 largeMotorLastConfig = 0xff;
// Since we reordered the buttons for better UI, we need to remap them here.
static constexpr std::array<u8, Inputs::LENGTH> bitmaskMapping = {{
12, // PAD_UP
13, // PAD_RIGHT
14, // PAD_DOWN
15, // PAD_LEFT
4, // PAD_TRIANGLE
5, // PAD_CIRCLE
6, // PAD_CROSS
7, // PAD_SQUARE
8, // PAD_SELECT
11, // PAD_START
2, // PAD_L1
0, // PAD_L2
3, // PAD_R1
1, // PAD_R2
9, // PAD_L3
10, // PAD_R3
16, // PAD_ANALOG
17, // PAD_PRESSURE
// remainder are analogs and not used here
}};
void ConfigLog();
u8 Mystery(u8 commandByte);
@@ -117,6 +140,7 @@ public:
const Pad::ControllerInfo& GetInfo() const override;
void Set(u32 index, float value) override;
void SetRawAnalogs(const std::tuple<u8, u8> left, const std::tuple<u8, u8> right) override;
void SetRawPressureButton(u32 index, const std::tuple<bool, u8> value) override;
void SetAxisScale(float deadzone, float scale) override;
float GetVibrationScale(u32 motor) const override;
void SetVibrationScale(u32 motor, float scale) override;

View File

@@ -318,6 +318,20 @@ void PadGuitar::SetRawAnalogs(const std::tuple<u8, u8> left, const std::tuple<u8
{
}
void PadGuitar::SetRawPressureButton(u32 index, const std::tuple<bool, u8> value)
{
this->rawInputs[index] = std::get<1>(value);
if (std::get<0>(value))
{
this->buttons &= ~(1u << bitmaskMapping[index]);
}
else
{
this->buttons |= (1u << bitmaskMapping[index]);
}
}
void PadGuitar::SetAxisScale(float deadzone, float scale)
{
this->whammyDeadzone = deadzone;

View File

@@ -37,6 +37,20 @@ private:
float whammyDeadzone = 0.0f;
float buttonDeadzone = 0.0f; // Button deadzone is still a good idea, in case a host analog stick is bound to a guitar button
// Since we reordered the buttons for better UI, we need to remap them here.
static constexpr std::array<u8, Inputs::LENGTH> bitmaskMapping = {{
12, // STRUM_UP
14, // STRUM_DOWN
8, // SELECT
11, // START
1, // GREEN
5, // RED
4, // YELLOW
6, // BLUE
7, // ORANGE
0 // TILT
}};
void ConfigLog();
u8 Mystery(u8 commandByte);
@@ -58,6 +72,7 @@ public:
const Pad::ControllerInfo& GetInfo() const override;
void Set(u32 index, float value) override;
void SetRawAnalogs(const std::tuple<u8, u8> left, const std::tuple<u8, u8> right) override;
void SetRawPressureButton(u32 index, const std::tuple<bool, u8> value) override;
void SetAxisScale(float deadzone, float scale) override;
float GetVibrationScale(u32 motor) const override;
void SetVibrationScale(u32 motor, float scale) override;

View File

@@ -36,6 +36,11 @@ void PadNotConnected::SetRawAnalogs(const std::tuple<u8, u8> left, const std::tu
}
void PadNotConnected::SetRawPressureButton(u32 index, const std::tuple<bool, u8> value)
{
}
void PadNotConnected::SetAxisScale(float deadzone, float scale)
{

View File

@@ -15,6 +15,7 @@ public:
const Pad::ControllerInfo& GetInfo() const override;
void Set(u32 index, float value) override;
void SetRawAnalogs(const std::tuple<u8, u8> left, const std::tuple<u8, u8> right) override;
void SetRawPressureButton(u32 index, const std::tuple<bool, u8> value) override;
void SetAxisScale(float deadzone, float scale) override;
float GetVibrationScale(u32 motor) const override;
void SetVibrationScale(u32 motor, float scale) override;

View File

@@ -376,21 +376,6 @@ void PadPopn::Set(u32 index, float value)
return;
}
// Since we reordered the buttons for better UI, we need to remap them here.
static constexpr std::array<u8, Inputs::LENGTH> bitmaskMapping = {{
5, // PAD_YELLOW_LEFT
12, // PAD_YELLOW_RIGHT
6, // PAD_BLUE_LEFT
7, // PAD_BLUE_RIGHT
4, // PAD_WHITE_LEFT
0, // PAD_WHITE_RIGHT
3, // PAD_GREEN_LEFT
1, // PAD_GREEN_RIGHT
2, // PAD_RED
11, // PAD_START
8, // PAD_SELECT
}};
this->rawInputs[index] = static_cast<u8>(std::clamp(value * 255.0f, 0.0f, 255.0f));
if (value)
@@ -407,6 +392,20 @@ void PadPopn::SetRawAnalogs(const std::tuple<u8, u8> left, const std::tuple<u8,
{
}
void PadPopn::SetRawPressureButton(u32 index, const std::tuple<bool, u8> value)
{
this->rawInputs[index] = std::get<1>(value);
if (std::get<0>(value))
{
this->buttons &= ~(1u << bitmaskMapping[index]);
}
else
{
this->buttons |= (1u << bitmaskMapping[index]);
}
}
void PadPopn::SetAxisScale(float deadzone, float scale)
{
}

View File

@@ -59,6 +59,21 @@ private:
bool commandStage = false;
u32 responseBytes = 0;
// Since we reordered the buttons for better UI, we need to remap them here.
static constexpr std::array<u8, Inputs::LENGTH> bitmaskMapping = {{
5, // PAD_YELLOW_LEFT
12, // PAD_YELLOW_RIGHT
6, // PAD_BLUE_LEFT
7, // PAD_BLUE_RIGHT
4, // PAD_WHITE_LEFT
0, // PAD_WHITE_RIGHT
3, // PAD_GREEN_LEFT
1, // PAD_GREEN_RIGHT
2, // PAD_RED
11, // PAD_START
8, // PAD_SELECT
}};
void ConfigLog();
u8 Mystery(u8 commandByte);
@@ -81,6 +96,7 @@ public:
const Pad::ControllerInfo& GetInfo() const override;
void Set(u32 index, float value) override;
void SetRawAnalogs(const std::tuple<u8, u8> left, const std::tuple<u8, u8> right) override;
void SetRawPressureButton(u32 index, const std::tuple<bool, u8> value) override;
void SetAxisScale(float deadzone, float scale) override;
float GetVibrationScale(u32 motor) const override;
void SetVibrationScale(u32 motor, float scale) override;

View File

@@ -3,11 +3,14 @@
#include "deviceproxy.h"
#include "usb-eyetoy/usb-eyetoy-webcam.h"
#include "usb-pad/usb-gametrak.h"
#include "usb-pad/usb-realplay.h"
#include "usb-hid/usb-hid.h"
#include "usb-mic/usb-headset.h"
#include "usb-mic/usb-mic-singstar.h"
#include "usb-msd/usb-msd.h"
#include "usb-pad/usb-pad.h"
#include "usb-pad/usb-trance-vibrator.h"
#include "usb-pad/usb-turntable.h"
#include "usb-printer/usb-printer.h"
#include "usb-lightgun/guncon2.h"
@@ -74,10 +77,13 @@ void RegisterDevice::Register()
inst.Add(DEVTYPE_BUZZ, new usb_pad::BuzzDevice());
inst.Add(DEVTYPE_EYETOY, new usb_eyetoy::EyeToyWebCamDevice());
inst.Add(DEVTYPE_BEATMANIA_DADADA, new usb_hid::BeatManiaDevice());
inst.Add(DEVTYPE_TRANCE_VIBRATOR, new usb_pad::TranceVibratorDevice());
inst.Add(DEVTYPE_SEGA_SEAMIC, new usb_pad::SeamicDevice());
inst.Add(DEVTYPE_PRINTER, new usb_printer::PrinterDevice());
inst.Add(DEVTYPE_KEYBOARDMANIA, new usb_pad::KeyboardmaniaDevice());
inst.Add(DEVTYPE_GUNCON2, new usb_lightgun::GunCon2Device());
inst.Add(DEVTYPE_GAMETRAK, new usb_pad::GametrakDevice());
inst.Add(DEVTYPE_REALPLAY, new usb_pad::RealPlayDevice());
}
void RegisterDevice::Unregister()

View File

@@ -35,11 +35,14 @@ enum DeviceType : s32
DEVTYPE_BUZZ,
DEVTYPE_EYETOY,
DEVTYPE_BEATMANIA_DADADA,
DEVTYPE_TRANCE_VIBRATOR,
DEVTYPE_SEGA_SEAMIC,
DEVTYPE_PRINTER,
DEVTYPE_KEYBOARDMANIA,
DEVTYPE_GUNCON2,
DEVTYPE_DJ
DEVTYPE_DJ,
DEVTYPE_GAMETRAK,
DEVTYPE_REALPLAY,
};
class DeviceProxy

View File

@@ -0,0 +1,408 @@
// SPDX-FileCopyrightText: 2002-2024 PCSX2 Dev Team
// SPDX-License-Identifier: LGPL-3.0+
#include "Host.h"
#include "Input/InputManager.h"
#include "StateWrapper.h"
#include "USB/USB.h"
#include "USB/deviceproxy.h"
#include "USB/qemu-usb/USBinternal.h"
#include "USB/qemu-usb/desc.h"
#include "USB/usb-pad/usb-gametrak.h"
#include "USB/usb-pad/usb-pad.h"
#include <common/Console.h>
namespace usb_pad
{
static const USBDescStrings desc_strings = {
"",
"In2Games Ltd.",
"Game-Trak V1.3"};
static uint8_t dev_descriptor[] = {
0x12, // bLength
0x01, // bDescriptorType (Device)
0x10, 0x01, // bcdUSB 1.10
0x00, // bDeviceClass (Use class information in the Interface Descriptors)
0x00, // bDeviceSubClass
0x00, // bDeviceProtocol
0x08, // bMaxPacketSize0 8
0xB7, 0x14, // idVendor 0x14B7
0x82, 0x09, // idProduct 0x0982
0x01, 0x00, // bcdDevice 0.01
0x01, // iManufacturer (String Index)
0x02, // iProduct (String Index)
0x00, // iSerialNumber (String Index)
0x01, // bNumConfigurations 1
};
static const uint8_t config_descriptor[] = {
0x09, // bLength
0x02, // bDescriptorType (Configuration)
0x22, 0x00, // wTotalLength 34
0x01, // bNumInterfaces 1
0x01, // bConfigurationValue
0x00, // iConfiguration (String Index)
0x80, // bmAttributes
0x0A, // bMaxPower 20mA
0x09, // bLength
0x04, // bDescriptorType (Interface)
0x00, // bInterfaceNumber 0
0x00, // bAlternateSetting
0x01, // bNumEndpoints 1
0x03, // bInterfaceClass
0x00, // bInterfaceSubClass
0x00, // bInterfaceProtocol
0x00, // iInterface (String Index)
0x09, // bLength
0x21, // bDescriptorType (HID)
0x01, 0x01, // bcdHID 1.01
0x00, // bCountryCode
0x01, // bNumDescriptors
0x22, // bDescriptorType[0] (HID)
0x7A, 0x00, // wDescriptorLength[0] 122
0x07, // bLength
0x05, // bDescriptorType (Endpoint)
0x81, // bEndpointAddress (IN/D2H)
0x03, // bmAttributes (Interrupt)
0x10, 0x00, // wMaxPacketSize 16
0x0A, // bInterval 10 (unit depends on device speed)
};
static const uint8_t hid_report_descriptor[] = {
0x05, 0x01, // Usage Page (Generic Desktop Ctrls)
0x09, 0x04, // Usage (Joystick)
0xA1, 0x01, // Collection (Application)
0x09, 0x01, // Usage (Pointer)
0xA1, 0x00, // Collection (Physical)
0x09, 0x30, // Usage (X)
0x09, 0x31, // Usage (Y)
0x09, 0x32, // Usage (Z)
0x09, 0x33, // Usage (Rx)
0x09, 0x34, // Usage (Ry)
0x09, 0x35, // Usage (Rz)
0x16, 0x00, 0x00, // Logical Minimum (0)
0x26, 0xFF, 0x0F, // Logical Maximum (4095)
0x36, 0x00, 0x00, // Physical Minimum (0)
0x46, 0xFF, 0x0F, // Physical Maximum (4095)
0x66, 0x00, 0x00, // Unit (None)
0x75, 0x10, // Report Size (16)
0x95, 0x06, // Report Count (6)
0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0xC0, // End Collection
0x09, 0x39, // Usage (Hat switch)
0x15, 0x01, // Logical Minimum (1)
0x25, 0x08, // Logical Maximum (8)
0x35, 0x00, // Physical Minimum (0)
0x46, 0x3B, 0x01, // Physical Maximum (315)
0x65, 0x14, // Unit (System: English Rotation, Length: Centimeter)
0x75, 0x04, // Report Size (4)
0x95, 0x01, // Report Count (1)
0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x05, 0x09, // Usage Page (Button)
0x19, 0x01, // Usage Minimum (0x01)
0x29, 0x0C, // Usage Maximum (0x0C)
0x15, 0x00, // Logical Minimum (0)
0x25, 0x01, // Logical Maximum (1)
0x75, 0x01, // Report Size (1)
0x95, 0x0C, // Report Count (12)
0x55, 0x00, // Unit Exponent (0)
0x65, 0x00, // Unit (None)
0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x75, 0x08, // Report Size (8)
0x95, 0x02, // Report Count (2)
0x81, 0x01, // Input (Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x05, 0x08, // Usage Page (LEDs)
0x09, 0x43, // Usage (Slow Blink On Time)
0x15, 0x00, // Logical Minimum (0)
0x26, 0xFF, 0x00, // Logical Maximum (255)
0x35, 0x00, // Physical Minimum (0)
0x46, 0xFF, 0x00, // Physical Maximum (255)
0x75, 0x08, // Report Size (8)
0x95, 0x01, // Report Count (1)
0x91, 0x82, // Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Volatile)
0x09, 0x44, // Usage (Slow Blink Off Time)
0x91, 0x82, // Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Volatile)
0x09, 0x45, // Usage (Fast Blink On Time)
0x91, 0x82, // Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Volatile)
0x09, 0x46, // Usage (Fast Blink Off Time)
0x91, 0x82, // Output (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Volatile)
0xC0, // End Collection
};
GametrakState::GametrakState(u32 port_)
: port(port_)
{
}
GametrakState::~GametrakState() = default;
static u32 gametrak_compute_key(u32* key)
{
u32 ret = 0;
ret = *key << 2 & 0xFC0000;
ret |= *key << 17 & 0x020000;
ret ^= *key << 16 & 0xFE0000;
ret |= *key & 0x010000;
ret |= *key >> 9 & 0x007F7F;
ret |= *key << 7 & 0x008080;
*key = ret;
return ret >> 16;
};
static void gametrak_handle_control(USBDevice* dev, USBPacket* p,
int request, int value, int index, int length, uint8_t* data)
{
GametrakState* s = USB_CONTAINER_OF(dev, GametrakState, dev);
int ret = 0;
switch (request)
{
case InterfaceRequest | USB_REQ_GET_DESCRIPTOR:
switch (value >> 8)
{
case USB_DT_REPORT:
ret = sizeof(hid_report_descriptor);
memcpy(data, hid_report_descriptor, ret);
break;
}
break;
case SET_REPORT:
{
constexpr u8 secret[] = "Gametrak";
if (length == 8 && std::memcmp(data, secret, sizeof(secret)) == 0)
{
s->state = 0;
s->key = 0;
}
else if (length == 2)
{
if (data[0] == 0x45)
{
s->key = data[1] << 16;
}
if ((s->key >> 16) == data[1])
{
gametrak_compute_key(&s->key);
}
else
{
ERROR_LOG("gametrak error : own key = {}, recv key = {}", s->key >> 16, data[1]);
}
}
break;
}
case SET_IDLE:
break;
default:
ret = usb_desc_handle_control(dev, p, request, value, index, length, data);
if (ret >= 0)
{
return;
}
p->status = USB_RET_STALL;
break;
}
}
static void gametrak_handle_data(USBDevice* dev, USBPacket* p)
{
GametrakState* s = USB_CONTAINER_OF(dev, GametrakState, dev);
switch (p->pid)
{
case USB_TOKEN_IN:
if (p->ep->nr == 1)
{
pxAssert(p->buffer_size >= sizeof(s->data));
if (s->state == 0)
{
s->state = 1;
constexpr u8 secret[] = "Gametrak\0\0\0\0\0\0\0\0";
std::memcpy(p->buffer_ptr, secret, sizeof(secret));
}
else
{
s->data.k1 = s->key >> 16 & 1;
s->data.k2 = s->key >> 17 & 1;
s->data.k3 = s->key >> 18 & 1;
s->data.k4 = s->key >> 19 & 1;
s->data.k5 = s->key >> 20 & 1;
s->data.k6 = s->key >> 21 & 1;
auto time = std::chrono::steady_clock::now();
if (std::chrono::duration_cast<std::chrono::milliseconds>(time - s->last_log).count() > 500)
{
Log::Write(LOGLEVEL_INFO, Color_Green, "{} LX={} LY={} LZ={} RX={} RY={} RZ={} Btn={}",
__FUNCTION__,
(u16)s->data.left_x, (u16)s->data.left_y, (u16)s->data.left_z,
(u16)s->data.right_x, (u16)s->data.right_y, (u16)s->data.right_z,
(u8)s->data.button);
s->last_log = time;
}
std::memcpy(p->buffer_ptr, &s->data, sizeof(s->data));
}
p->actual_length += sizeof(s->data);
}
else
{
goto fail;
}
break;
case USB_TOKEN_OUT:
break;
default:
fail:
p->status = USB_RET_STALL;
break;
}
}
static void gametrak_unrealize(USBDevice* dev)
{
GametrakState* s = USB_CONTAINER_OF(dev, GametrakState, dev);
delete s;
}
const char* GametrakDevice::Name() const
{
return TRANSLATE_NOOP("USB", "Gametrak Device");
}
const char* GametrakDevice::TypeName() const
{
return "Gametrak";
}
USBDevice* GametrakDevice::CreateDevice(SettingsInterface& si, u32 port, u32 subtype) const
{
GametrakState* s = new GametrakState(port);
s->desc.full = &s->desc_dev;
s->desc.str = desc_strings;
if (usb_desc_parse_dev(dev_descriptor, sizeof(dev_descriptor), s->desc, s->desc_dev) < 0)
goto fail;
if (usb_desc_parse_config(config_descriptor, sizeof(config_descriptor), s->desc_dev) < 0)
goto fail;
s->dev.speed = USB_SPEED_FULL;
s->dev.klass.handle_attach = usb_desc_attach;
s->dev.klass.handle_reset = nullptr;
s->dev.klass.handle_control = gametrak_handle_control;
s->dev.klass.handle_data = gametrak_handle_data;
s->dev.klass.unrealize = gametrak_unrealize;
s->dev.klass.usb_desc = &s->desc;
s->dev.klass.product_desc = nullptr;
usb_desc_init(&s->dev);
usb_ep_init(&s->dev);
return &s->dev;
fail:
gametrak_unrealize(&s->dev);
return nullptr;
}
bool GametrakDevice::Freeze(USBDevice* dev, StateWrapper& sw) const
{
GametrakState* s = USB_CONTAINER_OF(dev, GametrakState, dev);
if (!sw.DoMarker("GametrakDevice"))
return false;
sw.Do(&s->state);
sw.Do(&s->key);
return !sw.HasError();
}
float GametrakDevice::GetBindingValue(const USBDevice* dev, u32 bind_index) const
{
GametrakState* s = USB_CONTAINER_OF(dev, GametrakState, dev);
if (bind_index == CID_GT_BUTTON)
return s->data.button;
return 0.0f;
}
void GametrakDevice::SetBindingValue(USBDevice* dev, u32 bind_index, float value) const
{
GametrakState* s = USB_CONTAINER_OF(dev, GametrakState, dev);
switch (bind_index)
{
case CID_GT_BUTTON:
s->data.button = (value >= 0.5f);
break;
case CID_GT_LEFT_X:
s->data.left_x = static_cast<u16>(std::clamp<long>(std::lroundf(value * 2047.f), 0, 2047));
s->data.left_x = s->invert_x_axis ? 2047 - s->data.left_x : s->data.left_x;
break;
case CID_GT_LEFT_Y:
s->data.left_y = static_cast<u16>(std::clamp<long>(std::lroundf(value * 2047.f), 0, 2047));
s->data.left_y = s->invert_y_axis ? 2047 - s->data.left_y : s->data.left_y;
break;
case CID_GT_LEFT_Z:
s->data.left_z = static_cast<u32>(std::clamp<long>(std::lroundf(value * s->limit_z_axis), 0, s->limit_z_axis));
s->data.left_z = s->invert_z_axis ? s->limit_z_axis - s->data.left_z : s->data.left_z;
break;
case CID_GT_RIGHT_X:
s->data.right_x = static_cast<u16>(std::clamp<long>(std::lroundf(value * 2047.f), 0, 2047));
s->data.right_x = s->invert_x_axis ? 2047 - s->data.right_x : s->data.right_x;
break;
case CID_GT_RIGHT_Y:
s->data.right_y = static_cast<u16>(std::clamp<long>(std::lroundf(value * 2047.f), 0, 2047));
s->data.right_y = s->invert_y_axis ? 2047 - s->data.right_y : s->data.right_y;
break;
case CID_GT_RIGHT_Z:
s->data.right_z = static_cast<u32>(std::clamp<long>(std::lroundf(value * s->limit_z_axis), 0, s->limit_z_axis));
s->data.right_z = s->invert_z_axis ? s->limit_z_axis - s->data.right_z : s->data.right_z;
break;
default:
break;
}
}
void GametrakDevice::UpdateSettings(USBDevice* dev, SettingsInterface& si) const
{
GametrakState* s = USB_CONTAINER_OF(dev, GametrakState, dev);
s->invert_x_axis = USB::GetConfigBool(si, s->port, TypeName(), "invert_x_axis", false);
s->invert_y_axis = USB::GetConfigBool(si, s->port, TypeName(), "invert_y_axis", false);
s->invert_z_axis = USB::GetConfigBool(si, s->port, TypeName(), "invert_z_axis", false);
s->limit_z_axis = USB::GetConfigInt(si, s->port, TypeName(), "limit_z_axis", 4095);
}
std::span<const InputBindingInfo> GametrakDevice::Bindings(u32 subtype) const
{
static constexpr const InputBindingInfo bindings[] = {
{"FootPedal", TRANSLATE_NOOP("USB", "Foot Pedal"), nullptr, InputBindingInfo::Type::Button, CID_GT_BUTTON, GenericInputBinding::Cross},
{"LeftX", TRANSLATE_NOOP("USB", "Left X"), nullptr, InputBindingInfo::Type::Axis, CID_GT_LEFT_X, GenericInputBinding::Unknown},
{"LeftY", TRANSLATE_NOOP("USB", "Left Y"), nullptr, InputBindingInfo::Type::Axis, CID_GT_LEFT_Y, GenericInputBinding::Unknown},
{"LeftZ", TRANSLATE_NOOP("USB", "Left Z"), nullptr, InputBindingInfo::Type::Axis, CID_GT_LEFT_Z, GenericInputBinding::Unknown},
{"RightX", TRANSLATE_NOOP("USB", "Right X"), nullptr, InputBindingInfo::Type::Axis, CID_GT_RIGHT_X, GenericInputBinding::Unknown},
{"RightY", TRANSLATE_NOOP("USB", "Right Y"), nullptr, InputBindingInfo::Type::Axis, CID_GT_RIGHT_Y, GenericInputBinding::Unknown},
{"RightZ", TRANSLATE_NOOP("USB", "Right Z"), nullptr, InputBindingInfo::Type::Axis, CID_GT_RIGHT_Z, GenericInputBinding::Unknown},
};
return bindings;
}
std::span<const SettingInfo> GametrakDevice::Settings(u32 subtype) const
{
static constexpr const SettingInfo info[] = {
{SettingInfo::Type::Boolean, "invert_x_axis", TRANSLATE_NOOP("USB", "Invert X axis"), TRANSLATE_NOOP("USB", "Invert X axis"), "false"},
{SettingInfo::Type::Boolean, "invert_y_axis", TRANSLATE_NOOP("USB", "Invert Y axis"), TRANSLATE_NOOP("USB", "Invert Y axis"), "false"},
{SettingInfo::Type::Boolean, "invert_z_axis", TRANSLATE_NOOP("USB", "Invert Z axis"), TRANSLATE_NOOP("USB", "Invert Z axis"), "false"},
{SettingInfo::Type::Integer, "limit_z_axis", TRANSLATE_NOOP("USB", "Limit Z axis [100-4095]"),
TRANSLATE_NOOP("USB", "- 4095 for original Gametrak controllers\n- 1790 for standard gamepads"),
"4095", "100", "4095", "1", TRANSLATE_NOOP("USB", "%d"), nullptr, nullptr, 1.0f},
};
return info;
}
} // namespace usb_pad

View File

@@ -0,0 +1,86 @@
// SPDX-FileCopyrightText: 2002-2024 PCSX2 Dev Team
// SPDX-License-Identifier: LGPL-3.0+
#pragma once
#include "SaveState.h"
#include "USB/qemu-usb/desc.h"
#include <list>
#include <string>
namespace usb_pad
{
enum GametrakControlID
{
CID_GT_BUTTON,
CID_GT_LEFT_X,
CID_GT_LEFT_Y,
CID_GT_LEFT_Z,
CID_GT_RIGHT_X,
CID_GT_RIGHT_Y,
CID_GT_RIGHT_Z,
CID_GT_COUNT,
};
struct GametrakState
{
GametrakState(u32 port_);
~GametrakState();
USBDevice dev{};
USBDesc desc{};
USBDescDevice desc_dev{};
u32 port = 0;
u8 state = 0;
u32 key = 0;
// Settings
bool invert_x_axis = false;
bool invert_y_axis = false;
bool invert_z_axis = false;
u16 limit_z_axis = 0xfff;
std::chrono::steady_clock::time_point last_log;
#pragma pack(push, 1)
struct
{
u16 k1 : 1;
u16 left_x : 15;
u16 k2 : 1;
u16 left_y : 15;
u16 k3 : 1;
u16 left_z : 15;
u16 k4 : 1;
u16 right_x : 15;
u16 k5 : 1;
u16 right_y : 15;
u16 k6 : 1;
u16 right_z : 15;
u8 : 4;
u8 button : 1;
u8 : 3;
u8 : 8;
u8 : 8;
u8 : 8;
} data = {};
#pragma pack(pop)
};
class GametrakDevice final : public DeviceProxy
{
public:
const char* Name() const override;
const char* TypeName() const override;
float GetBindingValue(const USBDevice* dev, u32 bind_index) const override;
void SetBindingValue(USBDevice* dev, u32 bind_index, float value) const override;
bool Freeze(USBDevice* dev, StateWrapper& sw) const override;
void UpdateSettings(USBDevice* dev, SettingsInterface& si) const override;
std::span<const InputBindingInfo> Bindings(u32 subtype) const override;
std::span<const SettingInfo> Settings(u32 subtype) const override;
USBDevice* CreateDevice(SettingsInterface& si, u32 port, u32 subtype) const override;
};
} // namespace usb_pad

View File

@@ -0,0 +1,466 @@
// SPDX-FileCopyrightText: 2002-2024 PCSX2 Dev Team
// SPDX-License-Identifier: LGPL-3.0+
#include "Host.h"
#include "Input/InputManager.h"
#include "StateWrapper.h"
#include "USB/USB.h"
#include "USB/deviceproxy.h"
#include "USB/qemu-usb/USBinternal.h"
#include "USB/qemu-usb/desc.h"
#include "USB/usb-pad/usb-realplay.h"
#include "USB/usb-pad/usb-pad.h"
#include <common/Console.h>
namespace usb_pad
{
static const USBDescStrings desc_strings = {
"",
"In2Games",
"Real Play"};
static const uint8_t realplay_racing_dev_descriptor[] = {
0x12, // bLength
0x01, // bDescriptorType (Device)
0x00, 0x02, // bcdUSB 2.00
0x00, // bDeviceClass (Use class information in the Interface Descriptors)
0x00, // bDeviceSubClass
0x00, // bDeviceProtocol
0x40, // bMaxPacketSize0 64
0xB7, 0x14, // idVendor 0x14B7
0xB2, 0x09, // idProduct 0x09B2
0x00, 0x01, // bcdDevice 2.00
0x01, // iManufacturer (String Index)
0x02, // iProduct (String Index)
0x00, // iSerialNumber (String Index)
0x01, // bNumConfigurations 1
};
static const uint8_t realplay_sphere_dev_descriptor[] = {
0x12, // bLength
0x01, // bDescriptorType (Device)
0x00, 0x02, // bcdUSB 2.00
0x00, // bDeviceClass (Use class information in the Interface Descriptors)
0x00, // bDeviceSubClass
0x00, // bDeviceProtocol
0x40, // bMaxPacketSize0 64
0xB7, 0x14, // idVendor 0x14B7
0xB3, 0x09, // idProduct 0x09B3
0x00, 0x01, // bcdDevice 2.00
0x01, // iManufacturer (String Index)
0x02, // iProduct (String Index)
0x00, // iSerialNumber (String Index)
0x01, // bNumConfigurations 1
};
static const uint8_t realplay_golf_dev_descriptor[] = {
0x12, // bLength
0x01, // bDescriptorType (Device)
0x00, 0x02, // bcdUSB 2.00
0x00, // bDeviceClass (Use class information in the Interface Descriptors)
0x00, // bDeviceSubClass
0x00, // bDeviceProtocol
0x40, // bMaxPacketSize0 64
0xB7, 0x14, // idVendor 0x14B7
0xB5, 0x09, // idProduct 0x09B5
0x00, 0x01, // bcdDevice 2.00
0x01, // iManufacturer (String Index)
0x02, // iProduct (String Index)
0x00, // iSerialNumber (String Index)
0x01, // bNumConfigurations 1
};
static const uint8_t realplay_pool_dev_descriptor[] = {
0x12, // bLength
0x01, // bDescriptorType (Device)
0x00, 0x02, // bcdUSB 2.00
0x00, // bDeviceClass (Use class information in the Interface Descriptors)
0x00, // bDeviceSubClass
0x00, // bDeviceProtocol
0x40, // bMaxPacketSize0 64
0xB7, 0x14, // idVendor 0x14B7
0xB6, 0x09, // idProduct 0x09B6
0x00, 0x01, // bcdDevice 2.00
0x01, // iManufacturer (String Index)
0x02, // iProduct (String Index)
0x00, // iSerialNumber (String Index)
0x01, // bNumConfigurations 1
};
static const uint8_t config_descriptor[] = {
0x09, // bLength
0x02, // bDescriptorType (Configuration)
0x29, 0x00, // wTotalLength 41
0x01, // bNumInterfaces 1
0x01, // bConfigurationValue
0x00, // iConfiguration (String Index)
0x80, // bmAttributes
0x32, // bMaxPower 100mA
0x09, // bLength
0x04, // bDescriptorType (Interface)
0x00, // bInterfaceNumber 0
0x00, // bAlternateSetting
0x02, // bNumEndpoints 2
0x03, // bInterfaceClass
0x00, // bInterfaceSubClass
0x00, // bInterfaceProtocol
0x00, // iInterface (String Index)
0x09, // bLength
0x21, // bDescriptorType (HID)
0x11, 0x01, // bcdHID 1.11
0x00, // bCountryCode
0x01, // bNumDescriptors
0x22, // bDescriptorType[0] (HID)
0x85, 0x00, // wDescriptorLength[0] 133
0x07, // bLength
0x05, // bDescriptorType (Endpoint)
0x02, // bEndpointAddress (OUT/H2D)
0x03, // bmAttributes (Interrupt)
0x40, 0x00, // wMaxPacketSize 64
0x0A, // bInterval 10 (unit depends on device speed)
0x07, // bLength
0x05, // bDescriptorType (Endpoint)
0x81, // bEndpointAddress (IN/D2H)
0x03, // bmAttributes (Interrupt)
0x40, 0x00, // wMaxPacketSize 64
0x0A, // bInterval 10 (unit depends on device speed)
};
static const uint8_t hid_report_descriptor[] = {
0x05, 0x01, // Usage Page (Generic Desktop Ctrls)
0x09, 0x05, // Usage (Game Pad)
0xA1, 0x01, // Collection (Application)
0x15, 0x00, // Logical Minimum (0)
0x26, 0xFF, 0x0F, // Logical Maximum (4095)
0x35, 0x00, // Physical Minimum (0)
0x46, 0xFF, 0x0F, // Physical Maximum (4095)
0x09, 0x30, // Usage (X)
0x75, 0x0C, // Report Size (12)
0x95, 0x01, // Report Count (1)
0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x75, 0x01, // Report Size (1)
0x95, 0x04, // Report Count (4)
0x81, 0x03, // Input (Const,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x09, 0x31, // Usage (Y)
0x75, 0x0C, // Report Size (12)
0x95, 0x01, // Report Count (1)
0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x75, 0x01, // Report Size (1)
0x95, 0x04, // Report Count (4)
0x81, 0x03, // Input (Const,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x09, 0x32, // Usage (Z)
0x75, 0x0C, // Report Size (12)
0x95, 0x01, // Report Count (1)
0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x75, 0x01, // Report Size (1)
0x95, 0x04, // Report Count (4)
0x81, 0x03, // Input (Const,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x06, 0x00, 0xFF, // Usage Page (Vendor Defined 0xFF00)
0x09, 0x20, // Usage (0x20)
0x09, 0x21, // Usage (0x21)
0x09, 0x22, // Usage (0x22)
0x09, 0x23, // Usage (0x23)
0x09, 0x24, // Usage (0x24)
0x09, 0x25, // Usage (0x25)
0x09, 0x26, // Usage (0x26)
0x09, 0x27, // Usage (0x27)
0x26, 0xFF, 0x00, // Logical Maximum (255)
0x46, 0xFF, 0x00, // Physical Maximum (255)
0x75, 0x08, // Report Size (8)
0x95, 0x08, // Report Count (8)
0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x15, 0x00, // Logical Minimum (0)
0x25, 0x01, // Logical Maximum (1)
0x35, 0x00, // Physical Minimum (0)
0x45, 0x01, // Physical Maximum (1)
0x75, 0x01, // Report Size (1)
0x95, 0x08, // Report Count (8)
0x05, 0x09, // Usage Page (Button)
0x19, 0x01, // Usage Minimum (0x01)
0x29, 0x08, // Usage Maximum (0x08)
0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0x06, 0x00, 0xFF, // Usage Page (Vendor Defined 0xFF00)
0x09, 0x28, // Usage (0x28)
0x09, 0x29, // Usage (0x29)
0x09, 0x2A, // Usage (0x2A)
0x09, 0x2B, // Usage (0x2B)
0x26, 0xFF, 0x00, // Logical Maximum (255)
0x46, 0xFF, 0x00, // Physical Maximum (255)
0x75, 0x08, // Report Size (8)
0x95, 0x04, // Report Count (4)
0x81, 0x02, // Input (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position)
0xC0, // End Collection
};
RealPlayState::RealPlayState(u32 port_, u32 type_)
: port(port_)
, type(type_)
{
}
RealPlayState::~RealPlayState() = default;
static void realplay_handle_control(USBDevice* dev, USBPacket* p,
int request, int value, int index, int length, uint8_t* data)
{
int ret = 0;
switch (request)
{
case InterfaceRequest | USB_REQ_GET_DESCRIPTOR:
switch (value >> 8)
{
case USB_DT_REPORT:
ret = sizeof(hid_report_descriptor);
memcpy(data, hid_report_descriptor, ret);
break;
}
break;
case SET_REPORT:
break;
case SET_IDLE:
break;
default:
ret = usb_desc_handle_control(dev, p, request, value, index, length, data);
if (ret >= 0)
{
return;
}
p->status = USB_RET_STALL;
break;
}
}
static void realplay_handle_data(USBDevice* dev, USBPacket* p)
{
RealPlayState* s = USB_CONTAINER_OF(dev, RealPlayState, dev);
switch (p->pid)
{
case USB_TOKEN_IN:
if (p->ep->nr == 1)
{
pxAssert(p->buffer_size >= sizeof(s->data));
std::memcpy(p->buffer_ptr, &s->data, sizeof(s->data));
// simulate a slight move to avoid a game "protection" : controller disconnected
p->buffer_ptr[0] ^= s->state;
s->state ^= 1;
p->actual_length += sizeof(s->data);
}
else
{
goto fail;
}
break;
case USB_TOKEN_OUT:
break;
default:
fail:
p->status = USB_RET_STALL;
break;
}
}
static void realplay_unrealize(USBDevice* dev)
{
RealPlayState* s = USB_CONTAINER_OF(dev, RealPlayState, dev);
delete s;
}
const char* RealPlayDevice::Name() const
{
return TRANSLATE_NOOP("USB", "RealPlay Device");
}
const char* RealPlayDevice::TypeName() const
{
return "RealPlay";
}
USBDevice* RealPlayDevice::CreateDevice(SettingsInterface& si, u32 port, u32 type) const
{
RealPlayState* s = new RealPlayState(port, type);
s->desc.full = &s->desc_dev;
s->desc.str = desc_strings;
const uint8_t* dev_desc = nullptr;
int dev_desc_len = 0;
switch (s->type)
{
case REALPLAY_RACING:
dev_desc = realplay_racing_dev_descriptor;
dev_desc_len = sizeof(realplay_racing_dev_descriptor);
break;
case REALPLAY_SPHERE:
dev_desc = realplay_sphere_dev_descriptor;
dev_desc_len = sizeof(realplay_sphere_dev_descriptor);
break;
case REALPLAY_GOLF:
dev_desc = realplay_golf_dev_descriptor;
dev_desc_len = sizeof(realplay_golf_dev_descriptor);
break;
case REALPLAY_POOL:
dev_desc = realplay_pool_dev_descriptor;
dev_desc_len = sizeof(realplay_pool_dev_descriptor);
break;
default:
pxAssertMsg(false, "Unhandled type");
break;
}
if (usb_desc_parse_dev(dev_desc, dev_desc_len, s->desc, s->desc_dev) < 0)
goto fail;
if (usb_desc_parse_config(config_descriptor, sizeof(config_descriptor), s->desc_dev) < 0)
goto fail;
s->dev.speed = USB_SPEED_FULL;
s->dev.klass.handle_attach = usb_desc_attach;
s->dev.klass.handle_reset = nullptr;
s->dev.klass.handle_control = realplay_handle_control;
s->dev.klass.handle_data = realplay_handle_data;
s->dev.klass.unrealize = realplay_unrealize;
s->dev.klass.usb_desc = &s->desc;
s->dev.klass.product_desc = nullptr;
usb_desc_init(&s->dev);
usb_ep_init(&s->dev);
return &s->dev;
fail:
realplay_unrealize(&s->dev);
return nullptr;
}
bool RealPlayDevice::Freeze(USBDevice* dev, StateWrapper& sw) const
{
RealPlayState* s = USB_CONTAINER_OF(dev, RealPlayState, dev);
if (!sw.DoMarker("RealPlayDevice"))
return false;
sw.Do(&s->type);
sw.Do(&s->state);
return !sw.HasError();
}
float RealPlayDevice::GetBindingValue(const USBDevice* dev, u32 bind_index) const
{
RealPlayState* s = USB_CONTAINER_OF(dev, RealPlayState, dev);
switch (bind_index)
{
case CID_RP_DPAD_UP: return s->data.dpad_up;
case CID_RP_DPAD_DOWN: return s->data.dpad_down;
case CID_RP_DPAD_LEFT: return s->data.dpad_left;
case CID_RP_DPAD_RIGHT: return s->data.dpad_right;
case CID_RP_RED: return s->data.btn_red;
case CID_RP_GREEN: return s->data.btn_green;
case CID_RP_YELLOW: return s->data.btn_yellow;
case CID_RP_BLUE: return s->data.btn_blue;
default: return 0.0f;
}
}
void RealPlayDevice::SetBindingValue(USBDevice* dev, u32 bind_index, float value) const
{
RealPlayState* s = USB_CONTAINER_OF(dev, RealPlayState, dev);
switch (bind_index)
{
case CID_RP_DPAD_UP:
s->data.dpad_up = (value >= 0.5f);
break;
case CID_RP_DPAD_DOWN:
s->data.dpad_down = (value >= 0.5f);
break;
case CID_RP_DPAD_LEFT:
s->data.dpad_left = (value >= 0.5f);
break;
case CID_RP_DPAD_RIGHT:
s->data.dpad_right = (value >= 0.5f);
break;
case CID_RP_RED:
s->data.btn_red = (value >= 0.5f);
break;
case CID_RP_GREEN:
s->data.btn_green = (value >= 0.5f);
break;
case CID_RP_YELLOW:
s->data.btn_yellow = (value >= 0.5f);
break;
case CID_RP_BLUE:
s->data.btn_blue = (value >= 0.5f);
break;
case CID_RP_ACC_X:
s->data.acc_x = static_cast<u16>(std::clamp<long>(std::lroundf(value * 4095.f), 0, 4095));
s->data.acc_x = s->invert_x_axis ? 4095 - s->data.acc_x : s->data.acc_x;
break;
case CID_RP_ACC_Y:
s->data.acc_y = static_cast<u16>(std::clamp<long>(std::lroundf(value * 4095.f), 0, 4095));
s->data.acc_y = s->invert_x_axis ? 4095 - s->data.acc_y : s->data.acc_y;
break;
case CID_RP_ACC_Z:
s->data.acc_z = static_cast<u16>(std::clamp<long>(std::lroundf(value * 4095.f), 0, 4095));
s->data.acc_z = s->invert_x_axis ? 4095 - s->data.acc_z : s->data.acc_z;
break;
default:
break;
}
}
std::span<const char*> RealPlayDevice::SubTypes() const
{
static const char* subtypes[] = {
TRANSLATE_NOOP("USB", "RealPlay Racing"),
TRANSLATE_NOOP("USB", "RealPlay Sphere"),
TRANSLATE_NOOP("USB", "RealPlay Golf"),
TRANSLATE_NOOP("USB", "RealPlay Pool"),
};
return subtypes;
}
void RealPlayDevice::UpdateSettings(USBDevice* dev, SettingsInterface& si) const
{
RealPlayState* s = USB_CONTAINER_OF(dev, RealPlayState, dev);
s->invert_x_axis = USB::GetConfigBool(si, s->port, TypeName(), "invert_x_axis", false);
s->invert_y_axis = USB::GetConfigBool(si, s->port, TypeName(), "invert_y_axis", false);
s->invert_z_axis = USB::GetConfigBool(si, s->port, TypeName(), "invert_z_axis", false);
}
std::span<const InputBindingInfo> RealPlayDevice::Bindings(u32 subtype) const
{
static constexpr const InputBindingInfo bindings[] = {
{"DPadUp", TRANSLATE_NOOP("USB", "D-Pad Up"), nullptr, InputBindingInfo::Type::Button, CID_RP_DPAD_UP, GenericInputBinding::DPadUp},
{"DPadDown", TRANSLATE_NOOP("USB", "D-Pad Down"), nullptr, InputBindingInfo::Type::Button, CID_RP_DPAD_DOWN, GenericInputBinding::DPadDown},
{"DPadLeft", TRANSLATE_NOOP("USB", "D-Pad Left"), nullptr, InputBindingInfo::Type::Button, CID_RP_DPAD_LEFT, GenericInputBinding::DPadLeft},
{"DPadRight", TRANSLATE_NOOP("USB", "D-Pad Right"), nullptr, InputBindingInfo::Type::Button, CID_RP_DPAD_RIGHT, GenericInputBinding::DPadRight},
{"Red", TRANSLATE_NOOP("USB", "Red"), nullptr, InputBindingInfo::Type::Button, CID_RP_RED, GenericInputBinding::Triangle},
{"Green", TRANSLATE_NOOP("USB", "Green"), nullptr, InputBindingInfo::Type::Button, CID_RP_GREEN, GenericInputBinding::Cross},
{"Yellow", TRANSLATE_NOOP("USB", "Yellow"), nullptr, InputBindingInfo::Type::Button, CID_RP_YELLOW, GenericInputBinding::Square},
{"Blue", TRANSLATE_NOOP("USB", "Blue"), nullptr, InputBindingInfo::Type::Button, CID_RP_BLUE, GenericInputBinding::Circle},
{"AccelX", TRANSLATE_NOOP("USB", "Accel X"), nullptr, InputBindingInfo::Type::Axis, CID_RP_ACC_X, GenericInputBinding::Unknown},
{"AccelY", TRANSLATE_NOOP("USB", "Accel Y"), nullptr, InputBindingInfo::Type::Axis, CID_RP_ACC_Y, GenericInputBinding::Unknown},
{"AccelZ", TRANSLATE_NOOP("USB", "Accel Z"), nullptr, InputBindingInfo::Type::Axis, CID_RP_ACC_Z, GenericInputBinding::Unknown},
};
return bindings;
}
std::span<const SettingInfo> RealPlayDevice::Settings(u32 subtype) const
{
static constexpr const SettingInfo info[] = {
{SettingInfo::Type::Boolean, "invert_x_axis", TRANSLATE_NOOP("USB", "Invert X axis"), TRANSLATE_NOOP("USB", "Invert X axis"), "false"},
{SettingInfo::Type::Boolean, "invert_y_axis", TRANSLATE_NOOP("USB", "Invert Y axis"), TRANSLATE_NOOP("USB", "Invert Y axis"), "false"},
{SettingInfo::Type::Boolean, "invert_z_axis", TRANSLATE_NOOP("USB", "Invert Z axis"), TRANSLATE_NOOP("USB", "Invert Z axis"), "false"},
};
return info;
}
} // namespace usb_pad

View File

@@ -0,0 +1,92 @@
// SPDX-FileCopyrightText: 2002-2024 PCSX2 Dev Team
// SPDX-License-Identifier: LGPL-3.0+
#pragma once
#include "SaveState.h"
#include "USB/qemu-usb/desc.h"
#include <list>
#include <string>
namespace usb_pad
{
enum RealPlayControlID
{
CID_RP_DPAD_UP,
CID_RP_DPAD_DOWN,
CID_RP_DPAD_LEFT,
CID_RP_DPAD_RIGHT,
CID_RP_RED,
CID_RP_GREEN,
CID_RP_YELLOW,
CID_RP_BLUE,
CID_RP_ACC_X,
CID_RP_ACC_Y,
CID_RP_ACC_Z,
CID_RP_COUNT,
};
enum RealPlayType
{
REALPLAY_RACING,
REALPLAY_SPHERE,
REALPLAY_GOLF,
REALPLAY_POOL,
};
struct RealPlayState
{
RealPlayState(u32 port_, u32 type_);
~RealPlayState();
USBDevice dev{};
USBDesc desc{};
USBDescDevice desc_dev{};
u32 port = 0;
u32 type = 0;
u8 state = 0;
// Settings
bool invert_x_axis = false;
bool invert_y_axis = false;
bool invert_z_axis = false;
#pragma pack(push, 1)
struct
{
u16 acc_x;
u16 acc_y;
u16 acc_z;
u32 : 32;
u32 : 32;
u8 dpad_up : 1;
u8 dpad_down : 1;
u8 dpad_left : 1;
u8 dpad_right : 1;
u8 btn_red : 1;
u8 btn_green: 1;
u8 btn_yellow : 1;
u8 btn_blue : 1;
u32 : 32;
} data = {};
#pragma pack(pop)
};
class RealPlayDevice final : public DeviceProxy
{
public:
const char* Name() const override;
const char* TypeName() const override;
float GetBindingValue(const USBDevice* dev, u32 bind_index) const override;
void SetBindingValue(USBDevice* dev, u32 bind_index, float value) const override;
bool Freeze(USBDevice* dev, StateWrapper& sw) const override;
void UpdateSettings(USBDevice* dev, SettingsInterface& si) const override;
std::span<const char*> SubTypes() const override;
std::span<const InputBindingInfo> Bindings(u32 subtype) const override;
std::span<const SettingInfo> Settings(u32 subtype) const override;
USBDevice* CreateDevice(SettingsInterface& si, u32 port, u32 subtype) const override;
};
} // namespace usb_pad

View File

@@ -0,0 +1,185 @@
// SPDX-FileCopyrightText: 2002-2024 PCSX2 Dev Team
// SPDX-License-Identifier: LGPL-3.0+
#include "Host.h"
#include "Input/InputManager.h"
#include "StateWrapper.h"
#include "USB/USB.h"
#include "USB/deviceproxy.h"
#include "USB/qemu-usb/USBinternal.h"
#include "USB/qemu-usb/desc.h"
#include "USB/usb-pad/usb-trance-vibrator.h"
#include "USB/usb-pad/usb-pad.h"
#include <common/Console.h>
namespace usb_pad
{
static const USBDescStrings desc_strings = {
"",
"ASCII CORPORATION",
"ASCII Vib"};
static uint8_t dev_descriptor[] = {
0x12, // bLength
0x01, // bDescriptorType (Device)
0x00, 0x01, // bcdUSB 1.00
0x00, // bDeviceClass (Use class information in the Interface Descriptors)
0x00, // bDeviceSubClass
0x00, // bDeviceProtocol
0x08, // bMaxPacketSize0 8
0x49, 0x0B, // idVendor 0x0B49
0x4F, 0x06, // idProduct 0x064F
0x00, 0x01, // bcdDevice 2.00
0x01, // iManufacturer (String Index)
0x02, // iProduct (String Index)
0x00, // iSerialNumber (String Index)
0x01, // bNumConfigurations 1
};
static const uint8_t config_descriptor[] = {
0x09, // bLength
0x02, // bDescriptorType (Configuration)
0x22, 0x00, // wTotalLength 34
0x01, // bNumInterfaces 1
0x01, // bConfigurationValue
0x00, // iConfiguration (String Index)
0x80, // bmAttributes
0x31, // bMaxPower 98mA
0x09, // bLength
0x04, // bDescriptorType (Interface)
0x00, // bInterfaceNumber 0
0x00, // bAlternateSetting
0x01, // bNumEndpoints 1
0x00, // bInterfaceClass
0x00, // bInterfaceSubClass
0x00, // bInterfaceProtocol
0x00, // iInterface (String Index)
0x07, // bLength
0x05, // bDescriptorType (Endpoint)
0x81, // bEndpointAddress (IN/D2H)
0x03, // bmAttributes (Interrupt)
0x08, 0x00, // wMaxPacketSize 8
0x0A, // bInterval 10 (unit depends on device speed)
};
TranceVibratorState::TranceVibratorState(u32 port_)
: port(port_)
{
}
TranceVibratorState::~TranceVibratorState() = default;
static void trancevibrator_handle_control(USBDevice* dev, USBPacket* p,
int request, int value, int index, int length, uint8_t* data)
{
TranceVibratorState* s = USB_CONTAINER_OF(dev, TranceVibratorState, dev);
int ret = 0;
switch (request)
{
case InterfaceRequest | USB_REQ_GET_DESCRIPTOR:
break;
case SET_IDLE:
break;
case VendorDeviceOutRequest:
// Vibration = wValue
// LED1 = wIndex&1, LED2 = wIndex&2, LED3 = wIndex&4
InputManager::SetUSBVibrationIntensity(s->port, value & 0xff, 0);
break;
default:
ret = usb_desc_handle_control(dev, p, request, value, index, length, data);
if (ret >= 0)
{
return;
}
p->status = USB_RET_STALL;
break;
}
}
static void trancevibrator_handle_data(USBDevice* dev, USBPacket* p)
{
switch (p->pid)
{
case USB_TOKEN_IN:
break;
case USB_TOKEN_OUT:
break;
default:
p->status = USB_RET_STALL;
break;
}
}
static void trancevibrator_unrealize(USBDevice* dev)
{
TranceVibratorState* s = USB_CONTAINER_OF(dev, TranceVibratorState, dev);
delete s;
}
const char* TranceVibratorDevice::Name() const
{
return TRANSLATE_NOOP("USB", "Trance Vibrator (Rez)");
}
const char* TranceVibratorDevice::TypeName() const
{
return "TranceVibrator";
}
USBDevice* TranceVibratorDevice::CreateDevice(SettingsInterface& si, u32 port, u32 subtype) const
{
TranceVibratorState* s = new TranceVibratorState(port);
s->desc.full = &s->desc_dev;
s->desc.str = desc_strings;
if (usb_desc_parse_dev(dev_descriptor, sizeof(dev_descriptor), s->desc, s->desc_dev) < 0)
goto fail;
if (usb_desc_parse_config(config_descriptor, sizeof(config_descriptor), s->desc_dev) < 0)
goto fail;
s->dev.speed = USB_SPEED_FULL;
s->dev.klass.handle_attach = usb_desc_attach;
s->dev.klass.handle_reset = nullptr;
s->dev.klass.handle_control = trancevibrator_handle_control;
s->dev.klass.handle_data = trancevibrator_handle_data;
s->dev.klass.unrealize = trancevibrator_unrealize;
s->dev.klass.usb_desc = &s->desc;
s->dev.klass.product_desc = nullptr;
usb_desc_init(&s->dev);
usb_ep_init(&s->dev);
return &s->dev;
fail:
trancevibrator_unrealize(&s->dev);
return nullptr;
}
float TranceVibratorDevice::GetBindingValue(const USBDevice* dev, u32 bind_index) const
{
return 0.0f;
}
void TranceVibratorDevice::SetBindingValue(USBDevice* dev, u32 bind_index, float value) const
{
}
std::span<const InputBindingInfo> TranceVibratorDevice::Bindings(u32 subtype) const
{
static constexpr const InputBindingInfo bindings[] = {
{"Motor", TRANSLATE_NOOP("Pad", "Motor"), nullptr, InputBindingInfo::Type::Motor, 0, GenericInputBinding::LargeMotor},
};
return bindings;
}
std::span<const SettingInfo> TranceVibratorDevice::Settings(u32 subtype) const
{
return {};
}
} // namespace usb_pad

View File

@@ -0,0 +1,36 @@
// SPDX-FileCopyrightText: 2002-2024 PCSX2 Dev Team
// SPDX-License-Identifier: LGPL-3.0+
#pragma once
#include "SaveState.h"
#include "USB/qemu-usb/desc.h"
#include <list>
#include <string>
namespace usb_pad
{
struct TranceVibratorState
{
TranceVibratorState(u32 port_);
~TranceVibratorState();
USBDevice dev{};
USBDesc desc{};
USBDescDevice desc_dev{};
u32 port = 0;
};
class TranceVibratorDevice final : public DeviceProxy
{
public:
const char* Name() const override;
const char* TypeName() const override;
float GetBindingValue(const USBDevice* dev, u32 bind_index) const override;
void SetBindingValue(USBDevice* dev, u32 bind_index, float value) const override;
std::span<const InputBindingInfo> Bindings(u32 subtype) const override;
std::span<const SettingInfo> Settings(u32 subtype) const override;
USBDevice* CreateDevice(SettingsInterface& si, u32 port, u32 subtype) const override;
};
} // namespace usb_pad

View File

@@ -3612,7 +3612,7 @@ void VMManager::UpdateDiscordPresence(bool update_session_time)
rp.largeImageKey = "4k-pcsx2";
rp.largeImageText = "PCSX2 Emulator";
rp.startTimestamp = s_discord_presence_time_epoch;
rp.details = s_title.empty() ? "No Game Running" : s_title.c_str();
rp.details = s_title.empty() ? TRANSLATE("VMManager","No Game Running") : s_title.c_str();
std::string state_string;
if (Achievements::HasRichPresence())

View File

@@ -392,10 +392,13 @@
<ClCompile Include="USB\usb-mic\usb-mic-singstar.cpp" />
<ClCompile Include="USB\usb-msd\usb-msd.cpp" />
<ClCompile Include="USB\usb-pad\lg\lg_ff.cpp" />
<ClCompile Include="USB\usb-pad\usb-gametrak.cpp" />
<ClCompile Include="USB\usb-pad\usb-realplay.cpp" />
<ClCompile Include="USB\usb-pad\usb-pad-ff.cpp" />
<ClCompile Include="USB\usb-pad\usb-pad-sdl-ff.cpp" />
<ClCompile Include="USB\usb-pad\usb-pad.cpp" />
<ClCompile Include="USB\usb-pad\usb-seamic.cpp" />
<ClCompile Include="USB\usb-pad\usb-trance-vibrator.cpp" />
<ClCompile Include="USB\usb-pad\usb-turntable.cpp" />
<ClCompile Include="USB\usb-printer\usb-printer.cpp" />
<ClCompile Include="USB\USB.cpp" />
@@ -839,8 +842,11 @@
<ClInclude Include="USB\usb-mic\usb-mic-singstar.h" />
<ClInclude Include="USB\usb-msd\usb-msd.h" />
<ClInclude Include="USB\usb-pad\lg\lg_ff.h" />
<ClInclude Include="USB\usb-pad\usb-gametrak.h" />
<ClInclude Include="USB\usb-pad\usb-realplay.h" />
<ClInclude Include="USB\usb-pad\usb-pad-sdl-ff.h" />
<ClInclude Include="USB\usb-pad\usb-pad.h" />
<ClInclude Include="USB\usb-pad\usb-trance-vibrator.h" />
<ClInclude Include="USB\usb-pad\usb-turntable.h" />
<ClInclude Include="USB\usb-printer\usb-printer.h" />
<ClInclude Include="USB\USB.h" />

View File

@@ -1187,12 +1187,21 @@
<ClCompile Include="USB\usb-hid\usb-hid.cpp">
<Filter>System\Ps2\USB\usb-hid</Filter>
</ClCompile>
<ClCompile Include="USB\usb-pad\usb-gametrak.cpp">
<Filter>System\Ps2\USB\usb-pad</Filter>
</ClCompile>
<ClCompile Include="USB\usb-pad\usb-realplay.cpp">
<Filter>System\Ps2\USB\usb-pad</Filter>
</ClCompile>
<ClCompile Include="USB\usb-pad\usb-pad.cpp">
<Filter>System\Ps2\USB\usb-pad</Filter>
</ClCompile>
<ClCompile Include="USB\usb-pad\usb-seamic.cpp">
<Filter>System\Ps2\USB\usb-pad</Filter>
</ClCompile>
<ClCompile Include="USB\usb-pad\usb-trance-vibrator.cpp">
<Filter>System\Ps2\USB\usb-pad</Filter>
</ClCompile>
<ClCompile Include="USB\usb-pad\usb-turntable.cpp">
<Filter>System\Ps2\USB\usb-pad</Filter>
</ClCompile>
@@ -2121,9 +2130,18 @@
<ClInclude Include="USB\usb-hid\usb-hid.h">
<Filter>System\Ps2\USB\usb-hid</Filter>
</ClInclude>
<ClInclude Include="USB\usb-pad\usb-gametrak.h">
<Filter>System\Ps2\USB\usb-pad</Filter>
</ClInclude>
<ClInclude Include="USB\usb-pad\usb-realplay.h">
<Filter>System\Ps2\USB\usb-pad</Filter>
</ClInclude>
<ClInclude Include="USB\usb-pad\usb-pad.h">
<Filter>System\Ps2\USB\usb-pad</Filter>
</ClInclude>
<ClInclude Include="USB\usb-pad\usb-trance-vibrator.h">
<Filter>System\Ps2\USB\usb-pad</Filter>
</ClInclude>
<ClInclude Include="USB\usb-pad\usb-turntable.h">
<Filter>System\Ps2\USB\usb-pad</Filter>
</ClInclude>

View File

@@ -548,7 +548,7 @@ static void recReserveRAM()
recLUT_SetPage(recLUT, hwLUT, recROM1, 0xa000, i, i - 0x1e00);
}
for (int i = 0x1e40; i < 0x1e48; i++)
for (int i = 0x1e40; i < 0x1e80; i++)
{
recLUT_SetPage(recLUT, hwLUT, recROM2, 0x0000, i, i - 0x1e40);
recLUT_SetPage(recLUT, hwLUT, recROM2, 0x8000, i, i - 0x1e40);
@@ -691,7 +691,7 @@ static void recExecute()
if (!fastjmp_set(&m_SetJmp_StateCheck))
{
eeCpuExecuting = true;
((void(*)())EnterRecompiledCode)();
((void (*)())EnterRecompiledCode)();
// Generally unreachable code here ...
}
@@ -1544,7 +1544,7 @@ void dynarecMemcheck(size_t i)
auto mc = CBreakPoints::GetMemChecks(BREAKPOINT_EE)[i];
if(mc.hasCond)
if (mc.hasCond)
{
if (!mc.cond.Evaluate())
return;
@@ -1557,7 +1557,7 @@ void dynarecMemcheck(size_t i)
else
DevCon.WriteLn("Hit load breakpoint @0x%x", cpuRegs.pc);
}
CBreakPoints::SetBreakpointTriggered(true, BREAKPOINT_EE);
VMManager::SetPaused(true);
recExitExecution();

0
tools/generate_fullscreen_ui_translation_strings.py Normal file → Executable file
View File