removed rpcs3-qt ui

This commit is contained in:
DH 2025-10-04 12:14:45 +03:00
parent e87d8349ea
commit b1080c40de
319 changed files with 10 additions and 76903 deletions

View file

@ -1,27 +0,0 @@
#!/bin/sh -ex
# Pull all the submodules except llvm and opencv
# Note: Tried to use git submodule status, but it takes over 20 seconds
# shellcheck disable=SC2046
git submodule -q update --init --depth 1 $(awk '/path/ && !/llvm/ && !/opencv/ { print $3 }' .gitmodules)
CONFIGURE_ARGS="
-DWITH_LLVM=ON
-DUSE_SDL=OFF
-DUSE_PRECOMPILED_HEADERS=OFF
-DUSE_NATIVE_INSTRUCTIONS=OFF
-DUSE_SYSTEM_FFMPEG=ON
-DUSE_SYSTEM_CURL=ON
-DUSE_SYSTEM_LIBPNG=ON
-DUSE_SYSTEM_OPENCV=ON
"
# base Clang workaround (missing clang-scan-deps)
CONFIGURE_ARGS="$CONFIGURE_ARGS -DCMAKE_CXX_SCAN_FOR_MODULES=OFF"
# shellcheck disable=SC2086
cmake -B build -G Ninja $CONFIGURE_ARGS
cmake --build build
ccache --show-stats
ccache --zero-stats

View file

@ -1,50 +0,0 @@
#!/bin/sh -ex
git config --global --add safe.directory '*'
# Pull all the submodules except llvm and opencv
# shellcheck disable=SC2046
git submodule -q update --init $(awk '/path/ && !/llvm/ && !/opencv/ { print $3 }' .gitmodules)
if [ "$COMPILER" = "gcc" ]; then
export CC=gcc-14
export CXX=g++-14
else
export CC=clang
export CXX=clang++
export CFLAGS="$CFLAGS -fuse-ld=lld"
fi
cmake -B build \
-DCMAKE_INSTALL_PREFIX=/usr \
-DCMAKE_C_FLAGS="$CFLAGS" \
-DCMAKE_CXX_FLAGS="$CFLAGS" \
-DUSE_NATIVE_INSTRUCTIONS=OFF \
-DUSE_PRECOMPILED_HEADERS=OFF \
-DUSE_SYSTEM_CURL=ON \
-DUSE_SDL=OFF \
-DUSE_SYSTEM_FFMPEG=OFF \
-DUSE_SYSTEM_CURL=OFF \
-DUSE_SYSTEM_OPENAL=OFF \
-DUSE_SYSTEM_FFMPEG=OFF \
-DUSE_DISCORD_RPC=ON \
-DOpenGL_GL_PREFERENCE=LEGACY \
-DSTATIC_LINK_LLVM=ON \
-DBUILD_LLVM=on \
-DWITH_RPCSX=off \
-DWITH_RPCS3=on \
-DWITH_RPCS3_QT_UI=on \
-G Ninja
cmake --build build; build_status=$?;
shellcheck .ci/*.sh
# If it compiled succesfully let's deploy.
# Azure and Cirrus publish PRs as artifacts only.
{ [ "$CI_HAS_ARTIFACTS" = "true" ];
} && SHOULD_DEPLOY="true" || SHOULD_DEPLOY="false"
if [ "$build_status" -eq 0 ] && [ "$SHOULD_DEPLOY" = "true" ]; then
.ci/deploy-linux.sh "aarch64"
fi

View file

@ -1,51 +0,0 @@
#!/bin/sh -ex
git config --global --add safe.directory '*'
# Pull all the submodules except llvm and opencv
# Note: Tried to use git submodule status, but it takes over 20 seconds
# shellcheck disable=SC2046
git submodule -q update --init $(awk '/path/ && !/llvm/ && !/opencv/ { print $3 }' .gitmodules)
if [ "$COMPILER" = "gcc" ]; then
# These are set in the dockerfile
export CC=gcc-14
export CXX=g++-14
else
export CC=clang
export CXX=clang++
export LD=clang
export CFLAGS="$CFLAGS -fuse-ld=lld"
fi
cmake -B build \
-DCMAKE_INSTALL_PREFIX=/usr \
-DCMAKE_C_FLAGS="$CFLAGS" \
-DCMAKE_CXX_FLAGS="$CFLAGS" \
-DUSE_NATIVE_INSTRUCTIONS=OFF \
-DUSE_PRECOMPILED_HEADERS=OFF \
-DUSE_SDL=OFF \
-DUSE_SYSTEM_CURL=OFF \
-DUSE_SYSTEM_OPENAL=OFF \
-DUSE_SYSTEM_FFMPEG=OFF \
-DUSE_DISCORD_RPC=ON \
-DOpenGL_GL_PREFERENCE=LEGACY \
-DSTATIC_LINK_LLVM=ON \
-DBUILD_LLVM=on \
-DWITH_RPCSX=off \
-DWITH_RPCS3=on \
-DWITH_RPCS3_QT_UI=on \
-G Ninja
cmake --build build; build_status=$?;
shellcheck .ci/*.sh
# If it compiled succesfully let's deploy.
# Azure and Cirrus publish PRs as artifacts only.
{ [ "$CI_HAS_ARTIFACTS" = "true" ];
} && SHOULD_DEPLOY="true" || SHOULD_DEPLOY="false"
if [ "$build_status" -eq 0 ] && [ "$SHOULD_DEPLOY" = "true" ]; then
.ci/deploy-linux.sh "x86_64"
fi

View file

@ -1,160 +0,0 @@
#!/bin/sh -ex
# shellcheck disable=SC2086
brew_arm64_install_packages() {
for pkg in "$@"; do
echo "Fetching bottle for $pkg (arm64)..."
bottle_path="$("$BREW_ARM64_PATH/bin/brew" --cache --bottle-tag=arm64_sonoma "$pkg")"
if [ ! -f "$bottle_path" ]; then
if ! "$BREW_ARM64_PATH/bin/brew" fetch --force --verbose --debug --bottle-tag=arm64_sonoma "$pkg"; then
echo "Failed to fetch bottle for $pkg"
return 1
fi
bottle_path="$("$BREW_ARM64_PATH/bin/brew" --cache --bottle-tag=arm64_sonoma "$pkg")"
fi
echo "Installing $pkg (arm64)..."
"$BREW_ARM64_PATH/bin/brew" install --force --force-bottle --ignore-dependencies "$bottle_path" || true
done
}
export HOMEBREW_NO_AUTO_UPDATE=1
export HOMEBREW_NO_INSTALLED_DEPENDENTS_CHECK=1
export HOMEBREW_NO_INSTALL_CLEANUP=1
/usr/local/bin/brew update
sudo rm -rf /usr/local/Cellar/curl /usr/local/opt/curl
/usr/local/bin/brew install -f --overwrite curl
/usr/local/bin/brew uninstall -f --ignore-dependencies ffmpeg
/usr/local/bin/brew install -f --build-from-source ffmpeg@5 || true
/usr/local/bin/brew install -f --overwrite python || true
/usr/local/bin/brew link --overwrite python || true
/usr/local/bin/brew install -f --overwrite nasm ninja p7zip ccache pipenv #create-dmg
/usr/local/bin/brew link -f curl || true
/usr/local/bin/brew install llvm@$LLVM_COMPILER_VER glew cmake sdl3 vulkan-headers coreutils
/usr/local/bin/brew link -f llvm@$LLVM_COMPILER_VER ffmpeg@5 || true
export BREW_ARM64_PATH="/opt/homebrew1"
sudo mkdir -p "$BREW_ARM64_PATH"
sudo chmod 777 "$BREW_ARM64_PATH"
curl -L https://github.com/Homebrew/brew/tarball/master | tar xz --strip 1 -C "$BREW_ARM64_PATH"
#"$BREW_ARM64_PATH/bin/brew" update
# libvorbis requires Homebrew-installed curl, but we can't run it on x64, and we also need the aarch64 libs, so we swap the binary
brew_arm64_install_packages curl
mv /opt/homebrew1/opt/curl/bin/curl /opt/homebrew1/opt/curl/bin/curl.bak
ln -s /usr/local/opt/curl/bin/curl /opt/homebrew1/opt/curl/bin/curl
brew_arm64_install_packages 0mq aom aribb24 ca-certificates cjson dav1d ffmpeg@5 fontconfig freetype freetype2 gettext glew gmp gnutls lame libbluray libidn2 libnettle libogg libpng librist libsodium libsoxr libtasn libtasn1 libunistring libvmaf libvorbis libvpx libx11 libxau libxcb libxdmcp llvm@$LLVM_COMPILER_VER mbedtls molten-vk nettle opencore-amr openjpeg openssl opus p11-kit pkg-config pkgconfig pzstd rav1e sdl3 snappy speex srt svt-av1 theora vulkan-headers webp x264 x265 xz z3 zeromq zmq zstd
"$BREW_ARM64_PATH/bin/brew" link -f ffmpeg@5
ln -s "/opt/homebrew1/opt/llvm@$LLVM_COMPILER_VER/lib/unwind/libunwind.1.dylib" "/opt/homebrew1/opt/llvm@$LLVM_COMPILER_VER/lib/libunwind.1.dylib"
# moltenvk based on commit for 1.2.11 release
wget https://raw.githubusercontent.com/Homebrew/homebrew-core/6bfc8950c696d1f952425e8af2a6248603dc0df9/Formula/m/molten-vk.rb
/usr/local/bin/brew install -f --overwrite ./molten-vk.rb
export CXX=clang++
export CC=clang
export BREW_PATH;
BREW_PATH="$(brew --prefix)"
export BREW_X64_PATH;
BREW_X64_PATH="$("/usr/local/bin/brew" --prefix)"
export BREW_BIN="/usr/local/bin"
export BREW_SBIN="/usr/local/sbin"
export CMAKE_EXTRA_OPTS='-DLLVM_TARGETS_TO_BUILD=arm64'
export WORKDIR;
WORKDIR="$(pwd)"
# Get Qt
if [ ! -d "/tmp/Qt/$QT_VER" ]; then
mkdir -p "/tmp/Qt"
git clone https://github.com/engnr/qt-downloader.git
cd qt-downloader
git checkout f52efee0f18668c6d6de2dec0234b8c4bc54c597
# nested Qt 6.8.3 URL workaround
# sed -i '' "s/'qt{0}_{0}{1}{2}'.format(major, minor, patch)]))/'qt{0}_{0}{1}{2}'.format(major, minor, patch), 'qt{0}_{0}{1}{2}'.format(major, minor, patch)]))/g" qt-downloader
# sed -i '' "s/'{}\/{}\/qt{}_{}\/'/'{0}\/{1}\/qt{2}_{3}\/qt{2}_{3}\/'/g" qt-downloader
cd "/tmp/Qt"
"$BREW_X64_PATH/bin/pipenv" run pip3 install py7zr requests semantic_version lxml
mkdir -p "$QT_VER/macos" ; ln -s "macos" "$QT_VER/clang_64"
# sed -i '' 's/args\.version \/ derive_toolchain_dir(args) \/ //g' "$WORKDIR/qt-downloader/qt-downloader" # Qt 6.8.3 workaround
"$BREW_X64_PATH/bin/pipenv" run "$WORKDIR/qt-downloader/qt-downloader" macos desktop "$QT_VER" clang_64 --opensource --addons qtmultimedia qtimageformats # -o "$QT_VER/clang_64"
fi
cd "$WORKDIR"
ditto "/tmp/Qt/$QT_VER" "qt-downloader/$QT_VER"
export Qt6_DIR="$WORKDIR/qt-downloader/$QT_VER/clang_64/lib/cmake/Qt$QT_VER_MAIN"
export SDL3_DIR="$BREW_ARM64_PATH/opt/sdl3/lib/cmake/SDL3"
export PATH="$BREW_X64_PATH/opt/llvm@$LLVM_COMPILER_VER/bin:$WORKDIR/qt-downloader/$QT_VER/clang_64/bin:$BREW_BIN:$BREW_SBIN:/usr/bin:/bin:/usr/sbin:/sbin:/opt/X11/bin:/Library/Apple/usr/bin:$PATH"
export LDFLAGS="-L$BREW_ARM64_PATH/lib $BREW_ARM64_PATH/opt/ffmpeg@5/lib/libavcodec.dylib $BREW_ARM64_PATH/opt/ffmpeg@5/lib/libavformat.dylib $BREW_ARM64_PATH/opt/ffmpeg@5/lib/libavutil.dylib $BREW_ARM64_PATH/opt/ffmpeg@5/lib/libswscale.dylib $BREW_ARM64_PATH/opt/ffmpeg@5/lib/libswresample.dylib $BREW_ARM64_PATH/opt/llvm@$LLVM_COMPILER_VER/lib/c++/libc++.1.dylib $BREW_ARM64_PATH/lib/libSDL3.dylib $BREW_ARM64_PATH/lib/libGLEW.dylib $BREW_ARM64_PATH/opt/llvm@$LLVM_COMPILER_VER/lib/libunwind.1.dylib -Wl,-rpath,$BREW_ARM64_PATH/lib"
export CPPFLAGS="-I$BREW_ARM64_PATH/include -I$BREW_X64_PATH/include -no-pie -D__MAC_OS_X_VERSION_MIN_REQUIRED=140000"
export CFLAGS="-D__MAC_OS_X_VERSION_MIN_REQUIRED=140000"
export LIBRARY_PATH="$BREW_ARM64_PATH/lib"
export LD_LIBRARY_PATH="$BREW_ARM64_PATH/lib"
export VULKAN_SDK
VULKAN_SDK="$BREW_ARM64_PATH/opt/molten-vk"
ln -s "$VULKAN_SDK/lib/libMoltenVK.dylib" "$VULKAN_SDK/lib/libvulkan.dylib" || true
export VK_ICD_FILENAMES="$VULKAN_SDK/share/vulkan/icd.d/MoltenVK_icd.json"
export LLVM_DIR
LLVM_DIR="$BREW_ARM64_PATH/opt/llvm@$LLVM_COMPILER_VER"
# exclude ffmpeg, LLVM, and sdl from submodule update
# shellcheck disable=SC2046
git submodule -q update --init --depth=1 --jobs=8 $(awk '/path/ && !/ffmpeg/ && !/llvm/ && !/SDL/ { print $3 }' .gitmodules)
# 3rdparty fixes
sed -i '' "s/extern const double NSAppKitVersionNumber;/const double NSAppKitVersionNumber = 1343;/g" 3rdparty/hidapi/hidapi/mac/hid.c
rm -rf build
mkdir build && cd build || exit 1
export MACOSX_DEPLOYMENT_TARGET=14.0
"$BREW_X64_PATH/bin/cmake" .. \
-DUSE_SDL=ON \
-DUSE_DISCORD_RPC=ON \
-DUSE_VULKAN=ON \
-DUSE_ALSA=OFF \
-DUSE_PULSE=OFF \
-DUSE_AUDIOUNIT=ON \
-DUSE_SYSTEM_FFMPEG=ON \
-DLLVM_CCACHE_BUILD=OFF \
-DLLVM_BUILD_RUNTIME=OFF \
-DLLVM_BUILD_TOOLS=OFF \
-DLLVM_INCLUDE_DOCS=OFF \
-DLLVM_INCLUDE_EXAMPLES=OFF \
-DLLVM_INCLUDE_TESTS=OFF \
-DLLVM_INCLUDE_TOOLS=OFF \
-DLLVM_INCLUDE_UTILS=OFF \
-DLLVM_USE_PERF=OFF \
-DLLVM_ENABLE_Z3_SOLVER=OFF \
-DUSE_NATIVE_INSTRUCTIONS=OFF \
-DUSE_SYSTEM_MVK=ON \
-DUSE_SYSTEM_FAUDIO=OFF \
-DUSE_SYSTEM_SDL=ON \
-DUSE_SYSTEM_OPENCV=ON \
$CMAKE_EXTRA_OPTS \
-DLLVM_TARGET_ARCH=arm64 \
-DCMAKE_OSX_ARCHITECTURES=arm64 \
-DCMAKE_IGNORE_PATH="$BREW_X64_PATH/lib" \
-DCMAKE_IGNORE_PREFIX_PATH=/usr/local/opt \
-DCMAKE_SYSTEM_PROCESSOR=arm64 \
-DCMAKE_TOOLCHAIN_FILE=buildfiles/cmake/TCDarwinARM64.cmake \
-DCMAKE_CXX_FLAGS="-D__MAC_OS_X_VERSION_MIN_REQUIRED=140000" \
-DCMAKE_POLICY_VERSION_MINIMUM=3.5 \
-G Ninja
"$BREW_PATH/bin/ninja"; build_status=$?;
cd ..
{ [ "$CI_HAS_ARTIFACTS" = "true" ];
} && SHOULD_DEPLOY="true" || SHOULD_DEPLOY="false"
if [ "$build_status" -eq 0 ] && [ "$SHOULD_DEPLOY" = "true" ]; then
.ci/deploy-mac-arm64.sh
fi

View file

@ -1,123 +0,0 @@
#!/bin/sh -ex
# shellcheck disable=SC2086
export HOMEBREW_NO_AUTO_UPDATE=1
export HOMEBREW_NO_INSTALLED_DEPENDENTS_CHECK=1
brew unlink certifi
brew install -f --overwrite nasm ninja p7zip ccache pipenv #create-dmg
#/usr/sbin/softwareupdate --install-rosetta --agree-to-license
arch -x86_64 /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
arch -x86_64 /usr/local/bin/brew update
arch -x86_64 /usr/local/bin/brew install -f --overwrite python || arch -x86_64 /usr/local/bin/brew link --overwrite python
arch -x86_64 /usr/local/bin/brew uninstall -f --ignore-dependencies ffmpeg
arch -x86_64 /usr/local/bin/brew install -f --build-from-source ffmpeg@5
arch -x86_64 /usr/local/bin/brew reinstall -f --build-from-source gnutls freetype
arch -x86_64 /usr/local/bin/brew install llvm@$LLVM_COMPILER_VER glew cmake sdl3 vulkan-headers coreutils
arch -x86_64 /usr/local/bin/brew link -f llvm@$LLVM_COMPILER_VER ffmpeg@5
# moltenvk based on commit for 1.2.11 release
wget https://raw.githubusercontent.com/Homebrew/homebrew-core/6bfc8950c696d1f952425e8af2a6248603dc0df9/Formula/m/molten-vk.rb
arch -x86_64 /usr/local/bin/brew install -f --overwrite ./molten-vk.rb
export CXX=clang++
export CC=clang
export BREW_PATH;
BREW_PATH="$(brew --prefix)"
export BREW_X64_PATH;
BREW_X64_PATH="$("/usr/local/bin/brew" --prefix)"
export BREW_BIN="/usr/local/bin"
export BREW_SBIN="/usr/local/sbin"
export CMAKE_EXTRA_OPTS='-DLLVM_TARGETS_TO_BUILD=X86'
export WORKDIR;
WORKDIR="$(pwd)"
# Get Qt
if [ ! -d "/tmp/Qt/$QT_VER" ]; then
mkdir -p "/tmp/Qt"
git clone https://github.com/engnr/qt-downloader.git
cd qt-downloader
git checkout f52efee0f18668c6d6de2dec0234b8c4bc54c597
# nested Qt 6.8.3 URL workaround
# sed -i '' "s/'qt{0}_{0}{1}{2}'.format(major, minor, patch)]))/'qt{0}_{0}{1}{2}'.format(major, minor, patch), 'qt{0}_{0}{1}{2}'.format(major, minor, patch)]))/g" qt-downloader
# sed -i '' "s/'{}\/{}\/qt{}_{}\/'/'{0}\/{1}\/qt{2}_{3}\/qt{2}_{3}\/'/g" qt-downloader
cd "/tmp/Qt"
"$BREW_X64_PATH/bin/pipenv" run pip3 install py7zr requests semantic_version lxml
mkdir -p "$QT_VER/macos" ; ln -s "macos" "$QT_VER/clang_64"
# sed -i '' 's/args\.version \/ derive_toolchain_dir(args) \/ //g' "$WORKDIR/qt-downloader/qt-downloader" # Qt 6.8.3 workaround
"$BREW_X64_PATH/bin/pipenv" run "$WORKDIR/qt-downloader/qt-downloader" macos desktop "$QT_VER" clang_64 --opensource --addons qtmultimedia qtimageformats # -o "$QT_VER/clang_64"
fi
cd "$WORKDIR"
ditto "/tmp/Qt/$QT_VER" "qt-downloader/$QT_VER"
export Qt6_DIR="$WORKDIR/qt-downloader/$QT_VER/clang_64/lib/cmake/Qt$QT_VER_MAIN"
export SDL3_DIR="$BREW_X64_PATH/opt/sdl3/lib/cmake/SDL3"
export PATH="$BREW_X64_PATH/opt/llvm@$LLVM_COMPILER_VER/bin:$WORKDIR/qt-downloader/$QT_VER/clang_64/bin:$BREW_BIN:$BREW_SBIN:/usr/bin:/bin:/usr/sbin:/sbin:/opt/X11/bin:/Library/Apple/usr/bin:$PATH"
export LDFLAGS="-L$BREW_X64_PATH/lib -Wl,-rpath,$BREW_X64_PATH/lib"
export CPPFLAGS="-I$BREW_X64_PATH/include -msse -msse2 -mcx16 -no-pie -D__MAC_OS_X_VERSION_MIN_REQUIRED=140000"
export CFLAGS="-D__MAC_OS_X_VERSION_MIN_REQUIRED=140000"
export LIBRARY_PATH="$BREW_X64_PATH/lib"
export LD_LIBRARY_PATH="$BREW_X64_PATH/lib"
export VULKAN_SDK
VULKAN_SDK="$BREW_X64_PATH/opt/molten-vk"
ln -s "$VULKAN_SDK/lib/libMoltenVK.dylib" "$VULKAN_SDK/lib/libvulkan.dylib"
export VK_ICD_FILENAMES="$VULKAN_SDK/share/vulkan/icd.d/MoltenVK_icd.json"
export LLVM_DIR
LLVM_DIR="BREW_X64_PATH/opt/llvm@$LLVM_COMPILER_VER"
# exclude ffmpeg, LLVM, opencv, and sdl from submodule update
# shellcheck disable=SC2046
git submodule -q update --init --depth=1 --jobs=8 $(awk '/path/ && !/ffmpeg/ && !/llvm/ && !/opencv/ && !/SDL/ { print $3 }' .gitmodules)
# 3rdparty fixes
sed -i '' "s/extern const double NSAppKitVersionNumber;/const double NSAppKitVersionNumber = 1343;/g" 3rdparty/hidapi/hidapi/mac/hid.c
mkdir build && cd build || exit 1
export MACOSX_DEPLOYMENT_TARGET=14.0
"$BREW_X64_PATH/bin/cmake" .. \
-DUSE_SDL=ON \
-DUSE_DISCORD_RPC=ON \
-DUSE_VULKAN=ON \
-DUSE_ALSA=OFF \
-DUSE_PULSE=OFF \
-DUSE_AUDIOUNIT=ON \
-DUSE_SYSTEM_FFMPEG=ON \
-DLLVM_CCACHE_BUILD=OFF \
-DLLVM_BUILD_RUNTIME=OFF \
-DLLVM_BUILD_TOOLS=OFF \
-DLLVM_INCLUDE_DOCS=OFF \
-DLLVM_INCLUDE_EXAMPLES=OFF \
-DLLVM_INCLUDE_TESTS=OFF \
-DLLVM_INCLUDE_TOOLS=OFF \
-DLLVM_INCLUDE_UTILS=OFF \
-DLLVM_USE_PERF=OFF \
-DLLVM_ENABLE_Z3_SOLVER=OFF \
-DUSE_NATIVE_INSTRUCTIONS=OFF \
-DUSE_SYSTEM_MVK=ON \
-DUSE_SYSTEM_FAUDIO=OFF \
-DUSE_SYSTEM_SDL=ON \
-DUSE_SYSTEM_OPENCV=ON \
$CMAKE_EXTRA_OPTS \
-DLLVM_TARGET_ARCH=X86_64 \
-DCMAKE_OSX_ARCHITECTURES=x86_64 \
-DCMAKE_IGNORE_PATH="$BREW_PATH/lib" \
-DCMAKE_CXX_FLAGS="-D__MAC_OS_X_VERSION_MIN_REQUIRED=140000" \
-DCMAKE_POLICY_VERSION_MINIMUM=3.5 \
-G Ninja
"$BREW_PATH/bin/ninja"; build_status=$?;
cd ..
{ [ "$CI_HAS_ARTIFACTS" = "true" ];
} && SHOULD_DEPLOY="true" || SHOULD_DEPLOY="false"
if [ "$build_status" -eq 0 ] && [ "$SHOULD_DEPLOY" = "true" ]; then
.ci/deploy-mac.sh
fi

View file

@ -1,35 +0,0 @@
#!/bin/sh -ex
cd build || exit 1
CPU_ARCH="${1:-x86_64}"
if [ "$DEPLOY_APPIMAGE" = "true" ]; then
DESTDIR=AppDir ninja install
sudo curl -fsSLo /usr/bin/linuxdeploy "https://github.com/linuxdeploy/linuxdeploy/releases/download/continuous/linuxdeploy-$CPU_ARCH.AppImage"
sudo chmod a+x /usr/bin/linuxdeploy
sudo curl -fsSLo /usr/bin/linuxdeploy-plugin-qt "https://github.com/linuxdeploy/linuxdeploy-plugin-qt/releases/download/continuous/linuxdeploy-plugin-qt-$CPU_ARCH.AppImage"
sudo chmod a+x /usr/bin/linuxdeploy-plugin-qt
curl -fsSLo linuxdeploy-plugin-checkrt.sh https://github.com/darealshinji/linuxdeploy-plugin-checkrt/releases/download/continuous/linuxdeploy-plugin-checkrt.sh
chmod +x ./linuxdeploy-plugin-checkrt.sh
export EXTRA_PLATFORM_PLUGINS="libqwayland-egl.so;libqwayland-generic.so"
export EXTRA_QT_PLUGINS="svg;wayland-decoration-client;wayland-graphics-integration-client;wayland-shell-integration;waylandcompositor"
APPIMAGE_EXTRACT_AND_RUN=1 linuxdeploy --appdir AppDir --plugin qt --plugin checkrt
# Remove libwayland-client because it has platform-dependent exports and breaks other OSes
rm -f ./AppDir/usr/lib/libwayland-client.so*
# Remove libvulkan because it causes issues with gamescope
rm -f ./AppDir/usr/lib/libvulkan.so*
# Remove git directory containing local commit history file
rm -rf ./AppDir/usr/share/rpcs3/git
linuxdeploy --appimage-extract
./squashfs-root/plugins/linuxdeploy-plugin-appimage/usr/bin/appimagetool AppDir -g
mv ./*.AppImage ../RPCS3-Qt-UI.AppImage
fi

View file

@ -1,76 +0,0 @@
#!/bin/sh -ex
# shellcheck disable=SC2086
cd build || exit 1
# Gather explicit version number and number of commits
COMM_TAG=$(awk '/version{.*}/ { printf("%d.%d.%d", $5, $6, $7) }' ../rpcs3/rpcs3_version.cpp)
COMM_COUNT=$(git rev-list --count HEAD)
COMM_HASH=$(git rev-parse --short=8 HEAD)
AVVER="${COMM_TAG}-${COMM_COUNT}"
# AVVER is used for GitHub releases, it is the version number.
echo "AVVER=$AVVER" >> ../.ci/ci-vars.env
cd bin
mkdir "rpcs3.app/Contents/lib/" || true
cp "$(realpath /opt/homebrew1/opt/llvm@$LLVM_COMPILER_VER/lib/c++/libc++abi.1.0.dylib)" "rpcs3.app/Contents/Frameworks/libc++abi.1.dylib"
cp "$(realpath /opt/homebrew1/lib/libsharpyuv.0.dylib)" "rpcs3.app/Contents/lib/libsharpyuv.0.dylib"
cp "$(realpath /opt/homebrew1/lib/libintl.8.dylib)" "rpcs3.app/Contents/lib/libintl.8.dylib"
rm -rf "rpcs3.app/Contents/Frameworks/QtPdf.framework" \
"rpcs3.app/Contents/Frameworks/QtQml.framework" \
"rpcs3.app/Contents/Frameworks/QtQmlModels.framework" \
"rpcs3.app/Contents/Frameworks/QtQuick.framework" \
"rpcs3.app/Contents/Frameworks/QtVirtualKeyboard.framework" \
"rpcs3.app/Contents/Plugins/platforminputcontexts" \
"rpcs3.app/Contents/Plugins/virtualkeyboard" \
"rpcs3.app/Contents/Resources/git"
../../.ci/optimize-mac.sh rpcs3.app
# Hack
install_name_tool \
-delete_rpath /opt/homebrew1/lib \
-delete_rpath /opt/homebrew/lib \
-delete_rpath /opt/homebrew1/opt/llvm@$LLVM_COMPILER_VER/lib \
-delete_rpath /usr/local/lib RPCS3.app/Contents/MacOS/rpcs3
#-delete_rpath /opt/homebrew1/Cellar/sdl3/3.2.8/lib
# Need to do this rename hack due to case insensitive filesystem
mv rpcs3.app RPCS3_.app
mv RPCS3_.app RPCS3.app
# NOTE: "--deep" is deprecated
codesign --deep -fs - RPCS3.app
echo "[InternetShortcut]" > Quickstart.url
echo "URL=https://rpcs3.net/quickstart" >> Quickstart.url
echo "IconIndex=0" >> Quickstart.url
#DMG_FILEPATH="$BUILD_ARTIFACTSTAGINGDIRECTORY/rpcs3-v${COMM_TAG}-${COMM_COUNT}-${COMM_HASH}_macos_arm64.dmg"
#"$BREW_X64_PATH/bin/create-dmg" --volname RPCS3 \
#--window-size 800 400 \
#--icon-size 100 \
#--icon rpcs3.app 200 190 \
#--add-file Quickstart.url Quickstart.url 400 20 \
#--hide-extension rpcs3.app \
#--hide-extension Quickstart.url \
#--app-drop-link 600 185 \
#--skip-jenkins \
#--format ULMO \
#"$DMG_FILEPATH" \
#RPCS3.app
#FILESIZE=$(stat -f %z "$DMG_FILEPATH")
#SHA256SUM=$(shasum -a 256 "$DMG_FILEPATH" | awk '{ print $1 }')
ARCHIVE_FILEPATH="$BUILD_ARTIFACTSTAGINGDIRECTORY/rpcs3-v${COMM_TAG}-${COMM_COUNT}-${COMM_HASH}_macos_arm64.7z"
"$BREW_X64_PATH/bin/7z" a -mx9 "$ARCHIVE_FILEPATH" RPCS3.app Quickstart.url
FILESIZE=$(stat -f %z "$ARCHIVE_FILEPATH")
SHA256SUM=$(shasum -a 256 "$ARCHIVE_FILEPATH" | awk '{ print $1 }')
cd ..
echo "${SHA256SUM};${FILESIZE}B" > "$RELEASE_MESSAGE"
cd bin

View file

@ -1,74 +0,0 @@
#!/bin/sh -ex
# shellcheck disable=SC2086
cd build || exit 1
# Gather explicit version number and number of commits
COMM_TAG=$(awk '/version{.*}/ { printf("%d.%d.%d", $5, $6, $7) }' ../rpcs3/rpcs3_version.cpp)
COMM_COUNT=$(git rev-list --count HEAD)
COMM_HASH=$(git rev-parse --short=8 HEAD)
AVVER="${COMM_TAG}-${COMM_COUNT}"
# AVVER is used for GitHub releases, it is the version number.
echo "AVVER=$AVVER" >> ../.ci/ci-vars.env
cd bin
mkdir "rpcs3.app/Contents/lib/"
cp "/usr/local/opt/llvm@$LLVM_COMPILER_VER/lib/c++/libc++abi.1.0.dylib" "rpcs3.app/Contents/lib/libc++abi.1.dylib"
cp "$(realpath /usr/local/lib/libsharpyuv.0.dylib)" "rpcs3.app/Contents/lib/libsharpyuv.0.dylib"
cp "$(realpath /usr/local/lib/libintl.8.dylib)" "rpcs3.app/Contents/lib/libintl.8.dylib"
rm -rf "rpcs3.app/Contents/Frameworks/QtPdf.framework" \
"rpcs3.app/Contents/Frameworks/QtQml.framework" \
"rpcs3.app/Contents/Frameworks/QtQmlModels.framework" \
"rpcs3.app/Contents/Frameworks/QtQuick.framework" \
"rpcs3.app/Contents/Frameworks/QtVirtualKeyboard.framework" \
"rpcs3.app/Contents/Plugins/platforminputcontexts" \
"rpcs3.app/Contents/Plugins/virtualkeyboard" \
"rpcs3.app/Contents/Resources/git"
../../.ci/optimize-mac.sh rpcs3.app
# Need to do this rename hack due to case insensitive filesystem
mv rpcs3.app RPCS3_.app
mv RPCS3_.app RPCS3.app
# Hack
install_name_tool \
-delete_rpath /usr/local/lib \
-delete_rpath /usr/local/opt/llvm@$LLVM_COMPILER_VER/lib RPCS3.app/Contents/MacOS/rpcs3
#-delete_rpath /usr/local/Cellar/sdl3/3.2.8/lib
# NOTE: "--deep" is deprecated
codesign --deep -fs - RPCS3.app
echo "[InternetShortcut]" > Quickstart.url
echo "URL=https://rpcs3.net/quickstart" >> Quickstart.url
echo "IconIndex=0" >> Quickstart.url
#DMG_FILEPATH="$BUILD_ARTIFACTSTAGINGDIRECTORY/rpcs3-v${COMM_TAG}-${COMM_COUNT}-${COMM_HASH}_macos.dmg"
#"$BREW_X64_PATH/bin/create-dmg" --volname RPCS3 \
#--window-size 800 400 \
#--icon-size 100 \
#--icon rpcs3.app 200 190 \
#--add-file Quickstart.url Quickstart.url 400 20 \
#--hide-extension rpcs3.app \
#--hide-extension Quickstart.url \
#--app-drop-link 600 185 \
#--skip-jenkins \
#--format ULMO \
#"$DMG_FILEPATH" \
#RPCS3.app
#FILESIZE=$(stat -f %z "$DMG_FILEPATH")
#SHA256SUM=$(shasum -a 256 "$DMG_FILEPATH" | awk '{ print $1 }')
ARCHIVE_FILEPATH="$BUILD_ARTIFACTSTAGINGDIRECTORY/rpcs3-v${COMM_TAG}-${COMM_COUNT}-${COMM_HASH}_macos.7z"
"$BREW_X64_PATH/bin/7z" a -mx9 "$ARCHIVE_FILEPATH" RPCS3.app Quickstart.url
FILESIZE=$(stat -f %z "$ARCHIVE_FILEPATH")
SHA256SUM=$(shasum -a 256 "$ARCHIVE_FILEPATH" | awk '{ print $1 }')
cd ..
echo "${SHA256SUM};${FILESIZE}B" > "$RELEASE_MESSAGE"
cd bin

View file

@ -1,19 +0,0 @@
#!/bin/sh -ex
# First let's see print some info about our caches
"$(cygpath -u "$CCACHE_BIN_DIR")"/ccache.exe --show-stats -v
# Remove unecessary files
rm -f ./rpcs3/bin/rpcs3.exp ./rpcs3/bin/rpcs3.lib ./rpcs3/bin/rpcs3.pdb ./rpcs3/bin/vc_redist.x64.exe
rm -rf ./rpcs3/bin/git
# Prepare compatibility and SDL database for packaging
mkdir -p ./rpcs3/bin/config/input_configs
curl -fsSL 'https://raw.githubusercontent.com/gabomdq/SDL_GameControllerDB/master/gamecontrollerdb.txt' 1> ./rpcs3/bin/config/input_configs/gamecontrollerdb.txt
cp -rf ./build-msvc/bin/ ./rpcs3/bin/
# Package artifacts
7z a -m0=LZMA2 -mx9 "$BUILD" ./rpcs3/bin/*
# Move files to publishing directory
cp -- "$BUILD" ./RPCS3-Qt-UI.7z

View file

@ -1,15 +0,0 @@
# Variables set by Azure Pipelines
CI_HAS_ARTIFACTS
BUILD_REASON
BUILD_SOURCEVERSION
BUILD_ARTIFACTSTAGINGDIRECTORY
BUILD_REPOSITORY_NAME
BUILD_SOURCEBRANCHNAME
APPDIR
ARTDIR
RELEASE_MESSAGE
# Variables for build matrix
COMPILER
DEPLOY_APPIMAGE
# Private variables
GITHUB_TOKEN

View file

@ -1,13 +0,0 @@
#!/bin/sh -e
# Export variables for later stages of the Azure pipeline
# Values done in this manner will appear as environment variables
# in later stages.
# From pure-sh-bible
# Setting 'IFS' tells 'read' where to split the string.
while IFS='=' read -r key val; do
# Skip over lines containing comments.
[ "${key##\#*}" ] || continue
echo "##vso[task.setvariable variable=$key]$val"
done < ".ci/ci-vars.env"

View file

@ -1,13 +0,0 @@
#!/bin/sh -e
# Export variables for later stages of the Cirrus pipeline
# Values done in this manner will appear as environment variables
# in later stages.
# From pure-sh-bible
# Setting 'IFS' tells 'read' where to split the string.
while IFS='=' read -r key val; do
# Skip over lines containing comments.
[ "${key##\#*}" ] || continue
export "$key"="$val"
done < ".ci/ci-vars.env"

View file

@ -1,13 +0,0 @@
#!/bin/sh -ex
mkdir -p ../translations
LUPDATE_PATH=$(find /usr -name lupdate -type f 2>/dev/null | head -n 1)
if [ -z "$LUPDATE_PATH" ]; then
echo "Error: lupdate not found!"
exit 1
else
echo "lupdate found at: $LUPDATE_PATH"
$LUPDATE_PATH -recursive . -ts ../translations/rpcs3_template.ts
sed -i 's|filename="\.\./|filename="./|g' ../translations/rpcs3_template.ts
fi

View file

@ -1,4 +0,0 @@
#!/bin/sh -ex
curl -fLo "./llvm.lock" "https://github.com/RPCS3/llvm-mirror/releases/download/custom-build-win-${LLVM_VER}/llvmlibs_mt.7z.sha256"
curl -fLo "./glslang.lock" "https://github.com/RPCS3/glslang/releases/download/custom-build-win/glslanglibs_mt.7z.sha256"

View file

@ -1,42 +0,0 @@
#!/bin/sh -ex
ARTIFACT_DIR="$BUILD_ARTIFACTSTAGINGDIRECTORY"
generate_post_data()
{
body=$(cat GitHubReleaseMessage.txt)
cat <<EOF
{
"tag_name": "build-${BUILD_SOURCEVERSION}",
"target_commitish": "${UPLOAD_COMMIT_HASH}",
"name": "${AVVER}",
"body": "$body",
"draft": false,
"prerelease": false
}
EOF
}
curl -fsS \
-H "Authorization: token ${RPCS3_TOKEN}" \
-H "Accept: application/vnd.github.v3+json" \
--data "$(generate_post_data)" "https://api.github.com/repos/$UPLOAD_REPO_FULL_NAME/releases" >> release.json
cat release.json
id=$(grep '"id"' release.json | cut -d ':' -f2 | head -n1 | awk '{$1=$1;print}')
id=${id%?}
echo "${id:?}"
upload_file()
{
curl -fsS \
-H "Authorization: token ${RPCS3_TOKEN}" \
-H "Accept: application/vnd.github.v3+json" \
-H "Content-Type: application/octet-stream" \
--data-binary @"$2"/"$3" \
"https://uploads.github.com/repos/$UPLOAD_REPO_FULL_NAME/releases/$1/assets?name=$3"
}
for file in "$ARTIFACT_DIR"/*; do
name=$(basename "$file")
upload_file "$id" "$ARTIFACT_DIR" "$name"
done

View file

@ -1,18 +0,0 @@
#!/usr/bin/env -S su -m root -ex
# NOTE: this script is run under root permissions
# shellcheck shell=sh disable=SC2096
# RPCS3 often needs recent Qt and Vulkan-Headers
sed -i '' 's/quarterly/latest/' /etc/pkg/FreeBSD.conf
export ASSUME_ALWAYS_YES=true
pkg info # debug
# WITH_LLVM
pkg install "llvm$LLVM_COMPILER_VER"
# Mandatory dependencies (qtX-base is pulled via qtX-multimedia)
pkg install git ccache cmake ninja "qt$QT_VER_MAIN-multimedia" "qt$QT_VER_MAIN-svg" glew openal-soft ffmpeg
# Optional dependencies (libevdev is pulled by qtX-base)
pkg install pkgconf alsa-lib pulseaudio sdl3 evdev-proto vulkan-headers vulkan-loader

View file

@ -1,21 +0,0 @@
#!/bin/sh
file_path=$(find "$1/Contents/MacOS" -type f -print0 | head -n 1)
if [ -z "$file_path" ]; then
echo "No executable file found in $1/Contents/MacOS" >&2
exit 1
fi
target_architecture="$(lipo "$file_path" -archs)"
if [ -z "$target_architecture" ]; then
exit 1
fi
# shellcheck disable=SC3045
find "$1" -type f -print0 | while IFS= read -r -d '' file; do
echo Thinning "$file" -> "$target_architecture"
lipo "$file" -thin "$target_architecture" -output "$file" || true
done

View file

@ -1,134 +0,0 @@
#!/bin/sh -ex
# These are Azure specific, so we wrap them for portability
REPO_NAME="$BUILD_REPOSITORY_NAME"
REPO_BRANCH="$SYSTEM_PULLREQUEST_SOURCEBRANCH"
PR_NUMBER="$SYSTEM_PULLREQUEST_PULLREQUESTID"
# Resource/dependency URLs
# Qt mirrors can be volatile and slow, so we list 2
#QT_HOST="http://mirrors.ocf.berkeley.edu/qt/"
QT_HOST="http://qt.mirror.constant.com/"
QT_URL_VER=$(echo "$QT_VER" | sed "s/\.//g")
QT_VER_MSVC_UP=$(echo "${QT_VER_MSVC}" | tr '[:lower:]' '[:upper:]')
QT_PREFIX="online/qtsdkrepository/windows_x86/desktop/qt${QT_VER_MAIN}_${QT_URL_VER}/qt${QT_VER_MAIN}_${QT_URL_VER}/qt.qt${QT_VER_MAIN}.${QT_URL_VER}."
QT_PREFIX_2="win64_${QT_VER_MSVC}_64/${QT_VER}-0-${QT_DATE}"
QT_SUFFIX="-Windows-Windows_11_23H2-${QT_VER_MSVC_UP}-Windows-Windows_11_23H2-X86_64.7z"
QT_BASE_URL="${QT_HOST}${QT_PREFIX}${QT_PREFIX_2}qtbase${QT_SUFFIX}"
QT_DECL_URL="${QT_HOST}${QT_PREFIX}${QT_PREFIX_2}qtdeclarative${QT_SUFFIX}"
QT_TOOL_URL="${QT_HOST}${QT_PREFIX}${QT_PREFIX_2}qttools${QT_SUFFIX}"
QT_MM_URL="${QT_HOST}${QT_PREFIX}addons.qtmultimedia.${QT_PREFIX_2}qtmultimedia${QT_SUFFIX}"
QT_SVG_URL="${QT_HOST}${QT_PREFIX}${QT_PREFIX_2}qtsvg${QT_SUFFIX}"
# LLVMLIBS_URL="https://github.com/RPCS3/llvm-mirror/releases/download/custom-build-win-${LLVM_VER}/llvmlibs_mt.7z"
# GLSLANG_URL='https://github.com/RPCS3/glslang/releases/latest/download/glslanglibs_mt.7z'
VULKAN_SDK_URL="https://www.dropbox.com/scl/fi/sjjh0fc4ld281pjbl2xzu/VulkanSDK-${VULKAN_VER}-Installer.exe?rlkey=f6wzc0lvms5vwkt2z3qabfv9d&dl=1"
CCACHE_URL="https://github.com/ccache/ccache/releases/download/v4.11.2/ccache-4.11.2-windows-x86_64.zip"
DEP_URLS=" \
$QT_BASE_URL \
$QT_DECL_URL \
$QT_TOOL_URL \
$QT_MM_URL \
$QT_SVG_URL \
$LLVMLIBS_URL \
$GLSLANG_URL \
$VULKAN_SDK_URL\
$CCACHE_URL"
# Azure pipelines doesn't make a cache dir if it doesn't exist, so we do it manually
[ -d "$DEPS_CACHE_DIR" ] || mkdir "$DEPS_CACHE_DIR"
# Pull all the submodules except llvm, since it is built separately and we just download that build
# Note: Tried to use git submodule status, but it takes over 20 seconds
# shellcheck disable=SC2046
git submodule -q update --init --depth=1 --jobs=8 $(awk '/path/ && !/FAudio/ { print $3 }' .gitmodules)
# Git bash doesn't have rev, so here it is
rev()
{
echo "$1" | awk '{ for(i = length($0); i != 0; --i) { a = a substr($0, i, 1); } } END { print a }'
}
# Usage: download_and_verify url checksum algo file
# Check to see if a file is already cached, and the checksum matches. If not, download it.
# Tries up to 3 times
download_and_verify()
{
url="$1"
correctChecksum="$2"
algo="$3"
fileName="$4"
for _ in 1 2 3; do
[ -e "$DEPS_CACHE_DIR/$fileName" ] || curl -fLo "$DEPS_CACHE_DIR/$fileName" "$url"
fileChecksum=$("${algo}sum" "$DEPS_CACHE_DIR/$fileName" | awk '{ print $1 }')
[ "$fileChecksum" = "$correctChecksum" ] && return 0
done
return 1;
}
# Some dependencies install here
[ -d "./rpcs3/build/lib_ext/Release-x64" ] || mkdir -p "./rpcs3/build/lib_ext/Release-x64"
for url in $DEP_URLS; do
# Get the filename from the URL and remove query strings (?arg=something).
fileName="$(rev "$(rev "$url" | cut -d'/' -f1)" | cut -d'?' -f1)"
[ -z "$fileName" ] && echo "Unable to parse url: $url" && exit 1
# shellcheck disable=SC1003
case "$url" in
*qt*) checksum=$(curl -fL "${url}.sha1"); algo="sha1"; outDir="$QTDIR/" ;;
*llvm*) checksum=$(curl -fL "${url}.sha256"); algo="sha256"; outDir="./rpcs3/build/lib_ext/Release-x64" ;;
*glslang*) checksum=$(curl -fL "${url}.sha256"); algo="sha256"; outDir="./rpcs3/build/lib_ext/Release-x64" ;;
*ccache*) checksum=$CCACHE_SHA; algo="sha256"; outDir="$CCACHE_BIN_DIR" ;;
*Vulkan*)
# Vulkan setup needs to be run in batch environment
# Need to subshell this or else it doesn't wait
download_and_verify "$url" "$VULKAN_SDK_SHA" "sha256" "$fileName"
cp "$DEPS_CACHE_DIR/$fileName" .
_=$(echo "$fileName --accept-licenses --default-answer --confirm-command install" | cmd)
continue
;;
*) echo "Unknown url resource: $url"; exit 1 ;;
esac
download_and_verify "$url" "$checksum" "$algo" "$fileName"
7z x -y "$DEPS_CACHE_DIR/$fileName" -aos -o"$outDir"
done
# Setup ccache tool
[ -d "$CCACHE_DIR" ] || mkdir -p "$(cygpath -u "$CCACHE_DIR")"
CCACHE_SH_DIR=$(cygpath -u "$CCACHE_BIN_DIR")
mv "$CCACHE_SH_DIR"/ccache-*/* "$CCACHE_SH_DIR"
cp "$CCACHE_SH_DIR"/ccache.exe "$CCACHE_SH_DIR"/cl.exe
# Gather explicit version number and number of commits
COMM_TAG=$(awk '/version{.*}/ { printf("%d.%d.%d", $5, $6, $7) }' ./rpcs3/rpcs3_version.cpp)
COMM_COUNT=$(git rev-list --count HEAD)
COMM_HASH=$(git rev-parse --short=8 HEAD)
# Format the above into filenames
if [ -n "$PR_NUMBER" ]; then
AVVER="${COMM_TAG}-${COMM_HASH}"
BUILD_RAW="rpcs3-v${AVVER}_win64"
BUILD="${BUILD_RAW}.7z"
else
AVVER="${COMM_TAG}-${COMM_COUNT}"
BUILD_RAW="rpcs3-v${AVVER}-${COMM_HASH}_win64"
BUILD="${BUILD_RAW}.7z"
fi
# BRANCH is used for experimental build warnings for pr builds, used in main_window.cpp.
# BUILD is the name of the release artifact
# BUILD_RAW is just filename
# AVVER is used for GitHub releases, it is the version number.
BRANCH="${REPO_NAME}/${REPO_BRANCH}"
# SC2129
{
echo "BRANCH=$BRANCH"
echo "BUILD=$BUILD"
echo "BUILD_RAW=$BUILD_RAW"
echo "AVVER=$AVVER"
} >> .ci/ci-vars.env

View file

@ -1,222 +0,0 @@
name: Build RPCS3 Qt UI (Legacy)
defaults:
run:
shell: bash
on:
push:
paths-ignore:
- "**/*.md"
pull_request:
paths-ignore:
- "**/*.md"
workflow_dispatch:
concurrency:
group: ${{ github.ref }}-${{ github.event_name }}
cancel-in-progress: false
env:
BUILD_REPOSITORY_NAME: ${{ github.repository }}
BUILD_SOURCEBRANCHNAME: ${{ github.ref_name }}
BUILD_SOURCEVERSION: ${{ github.sha }}
BUILD_ARTIFACTSTAGINGDIRECTORY: ${{ github.workspace }}/artifacts/
jobs:
Linux_Build:
strategy:
fail-fast: false
matrix:
include:
- os: ubuntu-24.04
build_sh: ".ci/build-linux.sh"
compiler: clang
- os: ubuntu-24.04
build_sh: ".ci/build-linux.sh"
compiler: gcc
- os: ubuntu-24.04-arm
build_sh: ".ci/build-linux-aarch64.sh"
compiler: clang
name: RPCS3 Qt UI (Legacy) for Linux ${{ matrix.os }} ${{ matrix.compiler }}
runs-on: ${{ matrix.os }}
env:
CCACHE_DIR: ${{ github.workspace }}/ccache
CI_HAS_ARTIFACTS: true
DEPLOY_APPIMAGE: true
APPDIR: "./appdir"
ARTDIR: "./artifacts"
COMPILER: ${{ matrix.compiler }}
RX_VERSION: "Unknown"
RX_SHA: "Unknown"
steps:
- name: Checkout repository
uses: actions/checkout@main
with:
fetch-depth: 0
- name: Setup Cache
uses: actions/cache@main
with:
path: ${{ env.CCACHE_DIR }}
key: ${{ runner.os }}-ccache-${{ matrix.compiler }}-${{ runner.arch }}-${{github.run_id}}
restore-keys: |
${{ runner.os }}-ccache-${{ matrix.compiler }}-${{ runner.arch }}-
- name: Setup dependencies
run: |
echo "Types: deb" | sudo tee -a /etc/apt/sources.list.d/ubuntu.sources
echo "URIs: ${{ matrix.os == 'ubuntu-24.04-arm' && 'http://ports.ubuntu.com/ubuntu-ports' || 'http://azure.archive.ubuntu.com/ubuntu/' }}" | sudo tee -a /etc/apt/sources.list.d/ubuntu.sources
echo "Suites: plucky plucky-updates plucky-security" | sudo tee -a /etc/apt/sources.list.d/ubuntu.sources
echo "Components: main restricted universe multiverse" | sudo tee -a /etc/apt/sources.list.d/ubuntu.sources
echo "Signed-By: /usr/share/keyrings/ubuntu-archive-keyring.gpg" | sudo tee -a /etc/apt/sources.list.d/ubuntu.sources
sudo apt update
sudo apt install -y cmake build-essential libunwind-dev \
libvulkan-dev vulkan-validationlayers \
libsox-dev ninja-build libasound2-dev libglfw3-dev nasm libudev-dev \
libpulse-dev libopenal-dev libglew-dev zlib1g-dev libedit-dev \
libevdev-dev libjack-dev libsndio-dev libglvnd-dev \
qt6-base-dev qt6-svg-dev qt6-base-private-dev qt6-multimedia-dev \
clang lld gcc-14 g++-14 \
- name: Build
run: |
${{ matrix.build_sh }}
RX_VERSION=`cat .rx.version | awk -F'-' '{print $1}'`
RX_SHA=`cat .rx.version | awk -F'-' '{print $5}'`
echo "RX_VERSION=$RX_VERSION" >> "${{ github.env }}"
echo "RX_SHA=$RX_SHA" >> "${{ github.env }}"
mv RPCS3-Qt-UI.AppImage RPCS3-Qt-UI-Linux-${{ runner.arch }}-${{ matrix.compiler }}.AppImage
- name: Upload artifacts
uses: actions/upload-artifact@main
with:
name: RPCS3 Qt UI (Legacy) for Linux (${{ runner.arch }}, ${{ matrix.compiler }})
path: RPCS3-Qt-UI-Linux-${{ runner.arch }}-${{ matrix.compiler }}.AppImage
compression-level: 0
- name: Deploy build
uses: softprops/action-gh-release@v2
if: |
github.event_name != 'pull_request' &&
github.ref == 'refs/heads/master' &&
github.repository == 'RPCSX/rpcsx'
with:
prerelease: false
make_latest: true
repository: RPCSX/rpcsx-build
token: ${{ secrets.BUILD_TOKEN }}
tag_name: v${{ env.RX_VERSION }}-${{ env.RX_SHA }}
files: RPCS3-Qt-UI-Linux-${{ runner.arch }}-${{ matrix.compiler }}.AppImage
body: ${{ github.server_url }}/${{ github.repository }}/commit/${{ github.sha }}
Windows_Build:
name: RPCS3 Qt UI (Legacy) for Windows
runs-on: windows-2025
env:
COMPILER: msvc
QT_VER_MAIN: '6'
QT_VER: '6.8.3'
QT_VER_MSVC: 'msvc2022'
QT_DATE: '202503201308'
LLVM_VER: '19.1.7'
VULKAN_VER: '1.3.268.0'
VULKAN_SDK_SHA: '8459ef49bd06b697115ddd3d97c9aec729e849cd775f5be70897718a9b3b9db5'
CCACHE_SHA: '1f39f3ad5aae3fe915e99ad1302633bc8f6718e58fa7c0de2b0ba7e080f0f08c'
CCACHE_BIN_DIR: 'C:\ccache_bin'
CCACHE_DIR: 'C:\ccache'
CCACHE_INODECACHE: 'true'
CCACHE_SLOPPINESS: 'time_macros'
DEPS_CACHE_DIR: ./dependency_cache
RX_VERSION: 'Unknown'
RX_SHA: 'Unknown'
steps:
- name: Checkout repository
uses: actions/checkout@main
with:
fetch-depth: 0
- name: Setup env
run: |
echo "QTDIR=C:\Qt\${{ env.QT_VER }}\${{ env.QT_VER_MSVC }}_64" >> ${{ github.env }}
echo "VULKAN_SDK=C:\VulkanSDK\${{ env.VULKAN_VER }}" >> ${{ github.env }}
# - name: Get Cache Keys
# run: .ci/get_keys-windows.sh
# - name: Setup Build Ccache
# uses: actions/cache@main
# with:
# path: ${{ env.CCACHE_DIR }}
# key: "${{ runner.os }}-ccache-${{ env.COMPILER }}-${{github.run_id}}"
# restore-keys: ${{ runner.os }}-ccache-${{ env.COMPILER }}-
# - name: Setup Dependencies Cache
# uses: actions/cache@main
# with:
# path: ${{ env.DEPS_CACHE_DIR }}
# key: "${{ runner.os }}-${{ env.COMPILER }}-${{ env.QT_VER }}-${{ env.VULKAN_SDK_SHA }}-${{ env.CCACHE_SHA }}-${{ hashFiles('llvm.lock') }}-${{ hashFiles('glslang.lock') }}"
# restore-keys: ${{ runner.os }}-${{ env.COMPILER }}-
- name: Download and unpack dependencies
run: .ci/setup-windows.sh
- name: Export Variables
run: |
while IFS='=' read -r key val; do
# Skip lines that are empty or start with '#'
[[ -z "$key" || "$key" =~ ^# ]] && continue
echo "$key=$val" >> "${{ github.env }}"
done < .ci/ci-vars.env
# - name: Add msbuild to PATH
# uses: microsoft/setup-msbuild@main
- name: Configure
run: |
cmake -B build-msvc -DCMAKE_POLICY_VERSION_MINIMUM=3.5 -DWITH_RPCSX=off -DWITH_RPCS3=on -DWITH_RPCS3_QT_UI=on -DCMAKE_CONFIGURATION_TYPES="Debug;Release" -DCMAKE_INSTALL_PREFIX="${sourceDir}/out/install/${presetName}" -DUSE_NATIVE_INSTRUCTIONS=on -DUSE_PRECOMPILED_HEADERS=on -DUSE_FAUDIO=off -DUSE_SYSTEM_CURL=off -DUSE_SYSTEM_ZLIB=off -DUSE_SYSTEM_OPENAL=off -DUSE_SYSTEM_OPENCV=off -DBUILD_LLVM=on -DSTATIC_LINK_LLVM=on
- name: Export Version
run: |
RX_VERSION=`cat .rx.version | awk -F'-' '{print $1}'`
RX_SHA=`cat .rx.version | awk -F'-' '{print $5}'`
echo "RX_VERSION=$RX_VERSION" >> "${{ github.env }}"
echo "RX_SHA=$RX_SHA" >> "${{ github.env }}"
- name: Build
run: |
cmake --build build-msvc --config Release
- name: Pack up build artifacts
run: |
mkdir -p "${{ env.BUILD_ARTIFACTSTAGINGDIRECTORY }}"
.ci/deploy-windows.sh
mv RPCS3-Qt-UI.7z RPCS3-Qt-UI-Windows-${{ runner.arch }}-${{ env.COMPILER }}.7z
- name: Upload artifacts (7z)
uses: actions/upload-artifact@main
with:
name: RPCS3 Qt UI (Legacy) for Windows (MSVC)
path: RPCS3-Qt-UI-Windows-${{ runner.arch }}-${{ env.COMPILER }}.7z
compression-level: 0
if-no-files-found: error
- name: Deploy build
uses: softprops/action-gh-release@v2
if: |
github.event_name != 'pull_request' &&
github.ref == 'refs/heads/master' &&
github.repository == 'RPCSX/rpcsx'
with:
prerelease: false
make_latest: true
repository: RPCSX/rpcsx-build
token: ${{ secrets.BUILD_TOKEN }}
tag_name: v${{ env.RX_VERSION }}-${{ env.RX_SHA }}
files: RPCS3-Qt-UI-Windows-${{ runner.arch }}-${{ env.COMPILER }}.7z
body: ${{ github.server_url }}/${{ github.repository }}/commit/${{ github.sha }}

View file

@ -131,9 +131,9 @@ function(target_base_address target address)
endfunction() endfunction()
option(WITH_RPCSX "Enable RPCSX" ON) option(WITH_PS3 "Enable PS3 emulation support" OFF)
option(WITH_RPCS3 "Enable RPCS3" OFF) option(WITH_PS4 "Enable PS4 emulation support" ON)
option(WITH_RPCS3_QT_UI "Enable RPCS3 UI" OFF)
option(WITHOUT_OPENGL "Disable OpenGL" OFF) option(WITHOUT_OPENGL "Disable OpenGL" OFF)
option(WITHOUT_OPENGLEW "Disable OpenGLEW" OFF) option(WITHOUT_OPENGLEW "Disable OpenGLEW" OFF)
option(WITHOUT_OPENAL "Disable OpenAL" OFF) option(WITHOUT_OPENAL "Disable OpenAL" OFF)
@ -159,8 +159,7 @@ option(USE_SYSTEM_OPENCV "Prefer system OpenCV instead of the builtin one" ON)
option(HAS_MEMORY_BREAKPOINTS "Add support for memory breakpoints to the interpreter" OFF) option(HAS_MEMORY_BREAKPOINTS "Add support for memory breakpoints to the interpreter" OFF)
option(USE_LTO "Use LTO for building" ON) option(USE_LTO "Use LTO for building" ON)
if (NOT WITH_PS3)
if (NOT WITH_RPCS3)
set(WITHOUT_OPENGL on) set(WITHOUT_OPENGL on)
set(WITHOUT_OPENGLEW on) set(WITHOUT_OPENGLEW on)
set(WITHOUT_OPENAL on) set(WITHOUT_OPENAL on)
@ -252,6 +251,8 @@ add_subdirectory(3rdparty EXCLUDE_FROM_ALL)
add_subdirectory(rx EXCLUDE_FROM_ALL) add_subdirectory(rx EXCLUDE_FROM_ALL)
include(3rdparty/llvm/CMakeLists.txt) include(3rdparty/llvm/CMakeLists.txt)
include(ConfigureCompiler)
include(CheckFunctionExists)
if (NOT RX_TAG) if (NOT RX_TAG)
set(RX_TAG 0) set(RX_TAG 0)
@ -266,7 +267,7 @@ target_compile_definitions(rx PRIVATE
RX_TAG_VERSION=${RX_TAG_VERSION} RX_TAG_VERSION=${RX_TAG_VERSION}
) )
if (WITH_RPCSX) if (WITH_PS4)
find_package(nlohmann_json CONFIG) find_package(nlohmann_json CONFIG)
add_subdirectory(tools) add_subdirectory(tools)
add_subdirectory(orbis-kernel) add_subdirectory(orbis-kernel)
@ -274,14 +275,7 @@ endif()
add_subdirectory(rpcsx) add_subdirectory(rpcsx)
if (WITH_RPCS3) if (WITH_PS3)
include(ConfigureCompiler)
include(CheckFunctionExists)
add_subdirectory(rpcs3) add_subdirectory(rpcs3)
add_subdirectory(ps3fw) add_subdirectory(ps3fw)
endif() endif()
if (NOT ANDROID AND WITH_RPCS3_QT_UI AND WITH_RPCS3)
add_subdirectory(rpcs3qt-legacy)
endif()

View file

@ -88,8 +88,8 @@ target_link_libraries(3rdparty_ffmpeg INTERFACE
add_dependencies(3rdparty_ffmpeg ffmpeg-unpack) add_dependencies(3rdparty_ffmpeg ffmpeg-unpack)
set(WITH_RPCSX off) set(WITH_PS4 off)
set(WITH_RPCS3 on) set(WITH_PS3 on)
set(USE_SYSTEM_LIBUSB off) set(USE_SYSTEM_LIBUSB off)
set(USE_SYSTEM_CURL off) set(USE_SYSTEM_CURL off)
set(USE_DISCORD_RPC off) set(USE_DISCORD_RPC off)
@ -113,8 +113,6 @@ add_library(${CMAKE_PROJECT_NAME} SHARED
src/rpcsx-android.cpp src/rpcsx-android.cpp
) )
target_include_directories(${CMAKE_PROJECT_NAME} PUBLIC rpcs3/rpcs3)
target_link_libraries(${CMAKE_PROJECT_NAME} target_link_libraries(${CMAKE_PROJECT_NAME}
rpcs3 rpcs3
rpcsx::fw::ps3 rpcsx::fw::ps3

View file

@ -1,32 +0,0 @@
Standard: c++20
UseTab: AlignWithSpaces
TabWidth: 4
IndentWidth: 4
AccessModifierOffset: -4
PointerAlignment: Left
NamespaceIndentation: All
ColumnLimit: 0
BreakBeforeBraces: Allman
BreakConstructorInitializers: BeforeColon
BreakBeforeBinaryOperators: None
BreakBeforeTernaryOperators: false
AlwaysBreakTemplateDeclarations: Yes
AllowShortIfStatementsOnASingleLine: Never
AllowShortBlocksOnASingleLine: Never
AllowShortCaseLabelsOnASingleLine: true
AllowShortFunctionsOnASingleLine: Empty
AllowShortLoopsOnASingleLine: false
AllowShortLambdasOnASingleLine: Empty
Cpp11BracedListStyle: true
IndentCaseLabels: false
SortIncludes: false
ReflowComments: true
AlignConsecutiveAssignments: false
AlignTrailingComments: true
AlignAfterOpenBracket: DontAlign
ConstructorInitializerAllOnOneLineOrOnePerLine: false
BinPackArguments: true
BinPackParameters: true
AlwaysBreakAfterReturnType: None
KeepEmptyLinesAtTheStartOfBlocks: true
IndentWrappedFunctionNames: false

View file

@ -1,281 +0,0 @@
include(qt6.cmake)
add_library(rpcs3_ui STATIC
about_dialog.cpp
auto_pause_settings_dialog.cpp
basic_mouse_settings_dialog.cpp
breakpoint_handler.cpp
breakpoint_list.cpp
call_stack_list.cpp
camera_settings_dialog.cpp
cg_disasm_window.cpp
cheat_manager.cpp
config_adapter.cpp
config_checker.cpp
curl_handle.cpp
custom_dialog.cpp
custom_table_widget_item.cpp
debugger_add_bp_window.cpp
debugger_frame.cpp
debugger_list.cpp
downloader.cpp
dimensions_dialog.cpp
_discord_utils.cpp
emu_settings.cpp
elf_memory_dumping_dialog.cpp
emulated_pad_settings_dialog.cpp
fatal_error_dialog.cpp
find_dialog.cpp
flow_layout.cpp
flow_widget.cpp
flow_widget_item.cpp
game_compatibility.cpp
game_list.cpp
game_list_base.cpp
game_list_delegate.cpp
game_list_frame.cpp
game_list_grid.cpp
game_list_grid_item.cpp
game_list_table.cpp
gui_application.cpp
gl_gs_frame.cpp
gs_frame.cpp
gui_game_info.cpp
gui_settings.cpp
infinity_dialog.cpp
input_dialog.cpp
instruction_editor_dialog.cpp
ipc_settings_dialog.cpp
kernel_explorer.cpp
localized.cpp
localized_emu.cpp
log_frame.cpp
log_viewer.cpp
main_window.cpp
memory_string_searcher.cpp
memory_viewer_panel.cpp
microphone_creator.cpp
midi_creator.cpp
movie_item.cpp
movie_item_base.cpp
msg_dialog_frame.cpp
osk_dialog_frame.cpp
pad_led_settings_dialog.cpp
pad_motion_settings_dialog.cpp
pad_settings_dialog.cpp
patch_creator_dialog.cpp
patch_manager_dialog.cpp
permissions.cpp
persistent_settings.cpp
pkg_install_dialog.cpp
progress_dialog.cpp
progress_indicator.cpp
ps_move_tracker_dialog.cpp
qt_camera_handler.cpp
qt_camera_video_sink.cpp
qt_music_handler.cpp
qt_utils.cpp
qt_video_source.cpp
raw_mouse_settings_dialog.cpp
register_editor_dialog.cpp
recvmessage_dialog_frame.cpp
render_creator.cpp
rpcn_settings_dialog.cpp
rsx_debugger.cpp
save_data_dialog.cpp
save_data_info_dialog.cpp
save_data_list_dialog.cpp
save_manager_dialog.cpp
savestate_manager_dialog.cpp
screenshot_item.cpp
screenshot_manager_dialog.cpp
screenshot_preview.cpp
sendmessage_dialog_frame.cpp
settings.cpp
settings_dialog.cpp
shortcut_utils.cpp
shortcut_dialog.cpp
shortcut_handler.cpp
shortcut_settings.cpp
skylander_dialog.cpp
syntax_highlighter.cpp
system_cmd_dialog.cpp
table_item_delegate.cpp
tooltips.cpp
trophy_manager_dialog.cpp
trophy_notification_frame.cpp
trophy_notification_helper.cpp
update_manager.cpp
user_account.cpp
user_manager_dialog.cpp
uuid.cpp
vfs_dialog.cpp
vfs_dialog_path_widget.cpp
vfs_dialog_tab.cpp
vfs_dialog_usb_input.cpp
vfs_dialog_usb_tab.cpp
vfs_tool_dialog.cpp
video_label.cpp
welcome_dialog.cpp
about_dialog.ui
camera_settings_dialog.ui
main_window.ui
pad_led_settings_dialog.ui
pad_motion_settings_dialog.ui
pad_settings_dialog.ui
patch_creator_dialog.ui
patch_manager_dialog.ui
ps_move_tracker_dialog.ui
settings_dialog.ui
shortcut_dialog.ui
welcome_dialog.ui
resources.qrc
)
if(HAS_MEMORY_BREAKPOINTS)
target_compile_definitions(rpcs3_ui PRIVATE RPCS3_HAS_MEMORY_BREAKPOINTS)
endif()
if(WIN32)
target_sources(rpcs3_ui PUBLIC windows.qrc)
target_compile_definitions(rpcs3_ui PRIVATE UNICODE _UNICODE)
endif()
set_target_properties(rpcs3_ui
PROPERTIES
AUTOMOC ON
AUTOUIC ON
AUTORCC ON)
# AUTOMOC brings Windows.h to the sources, which have some definitions conflicting with winsock2.h
# define WIN32_LEAN_AND_MEAN resolve the problem
# https://docs.microsoft.com/en-us/windows/win32/winsock/creating-a-basic-winsock-application
# https://docs.microsoft.com/en-us/windows/win32/winprog/using-the-windows-headers#faster-builds-with-smaller-header-files
target_compile_definitions(rpcs3_ui PUBLIC WIN32_LEAN_AND_MEAN NOMINMAX)
target_link_libraries(rpcs3_ui
PUBLIC
3rdparty::qt6
3rdparty::yaml-cpp
rpcs3
rpcsx::fw::ps3::api
)
if(TARGET OpenGL::EGL)
target_link_libraries(rpcs3_ui PUBLIC OpenGL::EGL)
endif()
if (NOT ANDROID)
if(WIN32)
add_executable(rpcs3qt-ui-legacy WIN32)
target_sources(rpcs3qt-ui-legacy PRIVATE rpcs3.rc)
target_compile_definitions(rpcs3qt-ui-legacy PUBLIC WIN32_LEAN_AND_MEAN NOMINMAX UNICODE _UNICODE)
elseif(APPLE)
add_executable(rpcs3qt-ui-legacy MACOSX_BUNDLE)
target_sources(rpcs3qt-ui-legacy PRIVATE rpcs3.icns update_helper.sh)
set_source_files_properties(update_helper.sh PROPERTIES MACOSX_PACKAGE_LOCATION Resources)
set_target_properties(rpcs3qt-ui-legacy
PROPERTIES
MACOSX_BUNDLE_INFO_PLIST "${CMAKE_CURRENT_SOURCE_DIR}/rpcs3.plist.in")
else()
add_executable(rpcs3qt-ui-legacy)
endif()
set_target_properties(rpcs3qt-ui-legacy PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
target_sources(rpcs3qt-ui-legacy
PRIVATE
display_sleep_control.cpp
headless_application.cpp
main.cpp
main_application.cpp
Input/basic_keyboard_handler.cpp
Input/basic_mouse_handler.cpp
Input/gui_pad_thread.cpp
Input/keyboard_pad_handler.cpp
)
set_target_properties(rpcs3qt-ui-legacy
PROPERTIES
AUTOMOC ON
AUTOUIC ON)
target_link_libraries(rpcs3qt-ui-legacy
PRIVATE
rpcs3_emu
rpcs3_ui
3rdparty::qt6
rpcsx::fw::ps3
rpcsx::fw::ps3::api)
if(UNIX)
set(CMAKE_THREAD_PREFER_PTHREAD TRUE)
find_package(Threads REQUIRED)
target_link_libraries(rpcs3qt-ui-legacy PRIVATE Threads::Threads)
endif()
if(WIN32)
target_link_libraries(rpcs3qt-ui-legacy PRIVATE bcrypt ws2_32 Iphlpapi Winmm Psapi gdi32 setupapi pdh)
else()
target_link_libraries(rpcs3qt-ui-legacy PRIVATE ${CMAKE_DL_LIBS})
endif()
# Copy icons to executable directory
if(APPLE)
if (CMAKE_BUILD_TYPE MATCHES "Debug" OR CMAKE_BUILD_TYPE MATCHES "RelWithDebInfo")
set(QT_DEPLOY_FLAGS "-no-strip")
else()
set(QT_DEPLOY_FLAGS "")
endif()
qt_finalize_target(rpcs3qt-ui-legacy)
add_custom_command(TARGET rpcs3qt-ui-legacy POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/rpcs3.icns $<TARGET_FILE_DIR:rpcs3qt-ui-legacy>/../Resources/rpcs3.icns
COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/rpcs3/bin/Icons $<TARGET_FILE_DIR:rpcs3qt-ui-legacy>/../Resources/Icons
COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/rpcs3/bin/GuiConfigs $<TARGET_FILE_DIR:rpcs3qt-ui-legacy>/../Resources/GuiConfigs
COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/rpcs3/bin/git $<TARGET_FILE_DIR:rpcs3qt-ui-legacy>/../Resources/git
COMMAND "${MACDEPLOYQT_EXECUTABLE}" "${PROJECT_BINARY_DIR}/bin/rpcs3.app" "${QT_DEPLOY_FLAGS}")
elseif(UNIX)
add_custom_command(TARGET rpcs3qt-ui-legacy POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/rpcs3/bin/Icons $<TARGET_FILE_DIR:rpcs3qt-ui-legacy>/Icons
COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/rpcs3/bin/GuiConfigs $<TARGET_FILE_DIR:rpcs3qt-ui-legacy>/GuiConfigs
COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/rpcs3/bin/git $<TARGET_FILE_DIR:rpcs3qt-ui-legacy>/git)
elseif(WIN32)
add_custom_command(TARGET rpcs3qt-ui-legacy POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_FILE:OpenAL::OpenAL> $<TARGET_FILE_DIR:rpcs3qt-ui-legacy>
COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/rpcs3/bin/Icons $<TARGET_FILE_DIR:rpcs3qt-ui-legacy>/Icons
COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/rpcs3/bin/GuiConfigs $<TARGET_FILE_DIR:rpcs3qt-ui-legacy>/GuiConfigs
COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/rpcs3/bin/git $<TARGET_FILE_DIR:rpcs3qt-ui-legacy>/git
COMMAND "${WINDEPLOYQT_EXECUTABLE}" --no-compiler-runtime --no-opengl-sw --no-patchqt
--no-translations --no-system-d3d-compiler --no-system-dxc-compiler --no-ffmpeg --no-quick-import
--plugindir "$<IF:$<CXX_COMPILER_ID:MSVC>,$<TARGET_FILE_DIR:rpcs3qt-ui-legacy>/plugins,$<TARGET_FILE_DIR:rpcs3qt-ui-legacy>/share/qt6/plugins>"
--verbose 0 "$<TARGET_FILE:rpcs3qt-ui-legacy>")
endif()
# Unix installation
if(UNIX AND NOT APPLE)
# Install the binary
install(TARGETS rpcs3qt-ui-legacy RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR})
# Install the application icon and menu item
install(FILES rpcs3.svg
DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/icons/hicolor/scalable/apps)
install(FILES rpcs3.png
DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/icons/hicolor/48x48/apps)
install(FILES rpcs3.desktop
DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/applications)
install(FILES rpcs3.metainfo.xml
DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/metainfo)
# Install other files
install(DIRECTORY ${CMAKE_SOURCE_DIR}/rpcs3/bin/Icons
DESTINATION ${CMAKE_INSTALL_DATADIR}/rpcs3)
install(DIRECTORY ${CMAKE_SOURCE_DIR}/rpcs3/bin/GuiConfigs
DESTINATION ${CMAKE_INSTALL_DATADIR}/rpcs3)
install(DIRECTORY ${CMAKE_SOURCE_DIR}/rpcs3/bin/git
DESTINATION ${CMAKE_INSTALL_DATADIR}/rpcs3)
install(DIRECTORY ${CMAKE_SOURCE_DIR}/rpcs3/bin/test
DESTINATION ${CMAKE_INSTALL_DATADIR}/rpcs3)
endif()
endif()

View file

@ -1,36 +0,0 @@
<svg id="DualShock_3_SVG" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="400" height="250" viewBox="0, 0, 400, 250"><!-- DualShock 3 SVG by HerrHulaHoop -->
<path id="MainOutline" d="M 116.5 41.6 C 116.9 40.5, 116 35.6, 115 29.9 C 112.7 14.7, 112.5 14.3, 108.9 12 C 108 11.4, 106.4 10.2, 105.4 9.3 C 100.4 4.6, 89 2.3, 77.4 3.5 C 70.7 4.2, 65.6 6.1, 62.2 9.2 C 61 10.2, 59.5 11.4, 58.7 11.9 C 56.8 13, 55 15.1, 54.6 16.8 C 54.2 18.1, 51.6 34, 50 42.4 M 25.4 74.2 C 22 81.1, 18.5 102.3, 10.4 159.5 C 8.1 175.6, 5.6 192.4, 4.8 196.7 C 3 207.4, 2.9 208.8, 3.4 212.7 C 7.2 241.6, 46.2 259.1, 69.4 242.3 C 77.3 236.6, 80.3 231.6, 103.5 186.3 L 110 174.1 M 292 173.5 C 292.5 174.5, 295 179.2, 297.9 184.9 C 308.1 205.1, 320.6 228.7, 323.2 232.6 C 335.6 250.8, 359.9 254.2, 380.5 240.4 C 394.5 231.1, 400.8 217.3, 398.1 202.1 C 396.5 193.4, 394.9 182.8, 390.4 151.1 C 383.3 101.3, 380 81.4, 376.8 75 M 351.9 42.3 C 351.8 40.5, 351 35.6, 350 29.9 C 347.7 14.7, 347.5 14.3, 343.9 11.5 C 343 10, 341.4 9.2, 342.6 9.8 C 335.4 4.6, 324 2.3, 312.4 3.5 C 305.7 4.2, 300.6 6.1, 297.1 9.2 C 296 10.2, 294.5 11.4, 293.7 11.9 C 291.8 13, 290.1 15.1, 289.6 16.8 C 289.2 18.1, 286.6 34, 285 42.4" stroke="black" fill="none" />
<path id="LeftShoulder" d="M 107 10.6 C 94.4 6.7, 74.8 6.5, 60.5 10.6" stroke="black" fill="none" />
<path id="RightShoulder" d="M 343.7 11.2 C 329.4 6.7, 309.8 6.5, 295.5 10.6" stroke="black" fill="none" />
<path id="UpperLine1" d="M 116.5 41.6 H 186 A 80 80, 0, 0 0, 216.5 41.6 H 286" stroke="black" fill="none" />
<line id="UpperLine2" x1="129" y1="52" x2="273" y2="52" stroke="black" fill="none" />
<line id="LowerLine1" x1="181.5" y1="164" x2="220" y2="164" stroke="black" fill="none" />
<line id="LowerLine2" x1="179" y1="170.5" x2="222.5" y2="170.5" stroke="black" fill="none" />
<rect id="SelectButton" x="155" y="95" width="20" height="10" stroke="black" fill="none" />
<text id="SelectText" x="150" y="90.5" font-family="sans-serif" font-size="8" font-weight="bold" fill="black">SELECT</text>
<path id="StartButton" d="M 226 95 V 105 L 244 100 Z" stroke="black" fill="none" />
<text id="StartText" x="222" y="90.5" font-family="sans-serif" font-size="8" font-weight="bold" fill="black">START</text>
<circle id="PSButton" cx="201" cy="129" r="13" stroke="black" fill="none" />
<circle id="RightJoystickOuter" cx="258" cy="154" r="39" stroke="black" fill="none" />
<circle id="RightJoystickMiddle" cx="258" cy="154" r="30" stroke="black" fill="none" />
<circle id="RightJoystickInner" cx="258" cy="154" r="27" stroke="black" fill="none" />
<circle id="LeftJoystickOuter" cx="143.4" cy="154" r="39" stroke="black" fill="none" />
<circle id="LeftJoystickMiddle" cx="143.4" cy="154" r="30" stroke="black" fill="none" />
<circle id="LeftJoystickInner" cx="143.4" cy="154" r="27" stroke="black" fill="none" />
<path id="RightFacebuttonCircle" d="M 297.3 152.5 A 61.8 61.8, 0, 1 0, 260 115" stroke="black" fill="none" />
<path id="RightButtonBorder" d="M 301 76 H 278 A 6 6, 0, 0 0, 272 82 V 105 A 6 6, 0, 0 0, 278 111 H 301 V 134 A 6 6, 0, 0 0, 307 140 H 330 A 6 6, 0, 0 0, 336 134 V 111 H 359 A 6 6, 0, 0 0, 365 105 V 82 A 6 6, 0, 0 0, 359 76 H 336 V 53 A 6 6, 0, 0 0, 330 47 H 307 A 6 6, 0, 0 0, 301 53 V 76.5" stroke="black" fill="none" />
<circle id="ButtonBorder1" cx="289.5" cy="93.5" r="13" stroke="black" fill="none" />
<rect id="ButtonSquare" x="282" y="86.5" width="15" height="15" stroke="black" fill="none" />
<circle id="ButtonBorder2" cx="347.5" cy="93.5" r="13" stroke="black" fill="none" />
<circle id="ButtonCircle" cx="347.5" cy="93.5" r="9" stroke="black" fill="none" />
<circle id="ButtonBorder3" cx="318.5" cy="64.5" r="13" stroke="black" fill="none" />
<path id="ButtonTriangle" d="M 310 70 H 327 L 318.5 56 Z" stroke="black" fill="none" />
<circle id="ButtonBorder4" cx="318.5" cy="122.5" r="13" stroke="black" fill="none" />
<path id="ButtonCross" d="M 311.5 115.5 L 325.5 129.5 M 311.5 129.5 L 325.5 115.5" stroke="black" fill="none" />
<path id="LeftDpadCircle" d="M 104.2 152.5 A 61.8 61.8, 0, 1 1, 142 115" stroke="black" fill="none" />
<path id="LeftDpadBorder" d="M 66 76 H 43 A 6 6, 0, 0 0, 37 82 V 105 A 6 6, 0, 0 0, 43 111 H 66 V 134 A 6 6, 0, 0 0, 72 140 H 95 A 6 6, 0, 0 0, 101 134 V 111 H 124 A 6 6, 0, 0 0, 130 105 V 82 A 6 6, 0, 0 0, 124 76 H 101 V 53 A 6 6, 0, 0 0, 95 47 H 72 A 6 6, 0, 0 0, 66 53 V 76.5" stroke="black" fill="none" />
<path id="DpadButtonLeft" d="M 52 85 H 69 L 75 93.5 L 69 102 H 52 Z M 48 88 V 99 L 43 93.5 Z" stroke="black" fill="none" />
<path id="DpadButtonRight" d="M 115 85 H 98 L 92 93.5 L 98 102 H 115 Z M 119 88 V 99 L 124 93.5 Z" stroke="black" fill="none" />
<path id="DpadButtonTop" d="M 75 62 V 79 L 83.5 85 L 92 79 V 62 Z M 78 58 H 89 L 83.5 53 Z" stroke="black" fill="none" />
<path id="DpadButtonBottom" d="M 75 125 V 108 L 83.5 102 L 92 108 V 125 Z M 78 129 H 89 L 83.5 134 Z" stroke="black" fill="none" />
</svg>

Before

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.3 KiB

View file

@ -1,347 +0,0 @@
#include "basic_keyboard_handler.h"
#include <QApplication>
#include "Emu/system_config.h"
#include "Emu/Io/interception.h"
#ifdef _WIN32
#include "windows.h"
#endif
LOG_CHANNEL(input_log, "Input");
void basic_keyboard_handler::Init(keyboard_consumer& consumer, const u32 max_connect)
{
KbInfo& info = consumer.GetInfo();
std::vector<Keyboard>& keyboards = consumer.GetKeyboards();
info = {};
keyboards.clear();
for (u32 i = 0; i < max_connect; i++)
{
Keyboard kb{};
kb.m_config.arrange = g_cfg.sys.keyboard_type;
if (consumer.id() == keyboard_consumer::identifier::overlays)
{
// Enable key repeat
kb.m_key_repeat = true;
}
LoadSettings(kb);
keyboards.emplace_back(kb);
}
info.max_connect = max_connect;
info.now_connect = std::min(::size32(keyboards), max_connect);
info.info = input::g_keyboards_intercepted ? CELL_KB_INFO_INTERCEPTED : 0; // Ownership of keyboard data: 0=Application, 1=System
info.status[0] = CELL_KB_STATUS_CONNECTED; // (TODO: Support for more keyboards)
}
/* Sets the target window for the event handler, and also installs an event filter on the target. */
void basic_keyboard_handler::SetTargetWindow(QWindow* target)
{
if (target != nullptr)
{
m_target = target;
target->installEventFilter(this);
}
else
{
// If this is hit, it probably means that some refactoring occurs because currently a gsframe is created in Load.
// We still want events so filter from application instead since target is null.
QApplication::instance()->installEventFilter(this);
input_log.error("Trying to set keyboard handler to a null target window.");
}
}
bool basic_keyboard_handler::eventFilter(QObject* watched, QEvent* event)
{
if (!event) [[unlikely]]
{
return false;
}
if (input::g_active_mouse_and_keyboard != input::active_mouse_and_keyboard::emulated)
{
if (!m_keys_released)
{
ReleaseAllKeys();
}
return false;
}
m_keys_released = false;
// !m_target is for future proofing when gsrender isn't automatically initialized on load.
// !m_target->isVisible() is a hack since currently a guiless application will STILL inititialize a gsrender (providing a valid target)
if (!m_target || !m_target->isVisible() || watched == m_target)
{
switch (event->type())
{
case QEvent::KeyPress:
{
keyPressEvent(static_cast<QKeyEvent*>(event));
break;
}
case QEvent::KeyRelease:
{
keyReleaseEvent(static_cast<QKeyEvent*>(event));
break;
}
case QEvent::FocusOut:
{
ReleaseAllKeys();
break;
}
default:
{
break;
}
}
}
return false;
}
void basic_keyboard_handler::keyPressEvent(QKeyEvent* keyEvent)
{
if (!keyEvent) [[unlikely]]
{
return;
}
if (m_consumers.empty())
{
keyEvent->ignore();
return;
}
const int key = getUnmodifiedKey(keyEvent);
if (key < 0 || !HandleKey(static_cast<u32>(key), keyEvent->nativeScanCode(), true, keyEvent->isAutoRepeat(), keyEvent->text().toStdU32String()))
{
keyEvent->ignore();
}
}
void basic_keyboard_handler::keyReleaseEvent(QKeyEvent* keyEvent)
{
if (!keyEvent) [[unlikely]]
{
return;
}
if (m_consumers.empty())
{
keyEvent->ignore();
return;
}
const int key = getUnmodifiedKey(keyEvent);
if (key < 0 || !HandleKey(static_cast<u32>(key), keyEvent->nativeScanCode(), false, keyEvent->isAutoRepeat(), keyEvent->text().toStdU32String()))
{
keyEvent->ignore();
}
}
// This should get the actual unmodified key without getting too crazy.
// key() only shows the modifiers and the modified key (e.g. no easy way of knowing that - was pressed in 'SHIFT+-' in order to get _)
s32 basic_keyboard_handler::getUnmodifiedKey(QKeyEvent* keyEvent)
{
if (!keyEvent) [[unlikely]]
{
return -1;
}
const int key = keyEvent->key();
if (key < 0)
{
return key;
}
u32 raw_key = static_cast<u32>(key);
#ifdef _WIN32
if (keyEvent->modifiers() != Qt::NoModifier && !keyEvent->text().isEmpty())
{
u32 mapped_key = static_cast<u32>(MapVirtualKeyA(static_cast<UINT>(keyEvent->nativeVirtualKey()), MAPVK_VK_TO_CHAR));
if (raw_key != mapped_key)
{
if (mapped_key > 0x80000000) // diacritics
{
mapped_key -= 0x80000000;
}
raw_key = mapped_key;
}
}
#endif
return static_cast<s32>(raw_key);
}
void basic_keyboard_handler::LoadSettings(Keyboard& keyboard)
{
std::vector<KbButton> buttons;
// Meta Keys
buttons.emplace_back(Qt::Key_Control, CELL_KB_MKEY_L_CTRL);
buttons.emplace_back(Qt::Key_Shift, CELL_KB_MKEY_L_SHIFT);
buttons.emplace_back(Qt::Key_Alt, CELL_KB_MKEY_L_ALT);
buttons.emplace_back(Qt::Key_Meta, CELL_KB_MKEY_L_WIN);
// buttons.emplace_back(, CELL_KB_MKEY_R_CTRL); // There is no way to know if it's left or right in Qt at the moment
// buttons.emplace_back(, CELL_KB_MKEY_R_SHIFT); // There is no way to know if it's left or right in Qt at the moment
// buttons.emplace_back(, CELL_KB_MKEY_R_ALT); // There is no way to know if it's left or right in Qt at the moment
// buttons.emplace_back(, CELL_KB_MKEY_R_WIN); // There is no way to know if it's left or right in Qt at the moment
buttons.emplace_back(Qt::Key_Super_L, CELL_KB_MKEY_L_WIN); // The super keys are supposed to be the windows keys, but they trigger the meta key instead. Let's assign the windows keys to both.
buttons.emplace_back(Qt::Key_Super_R, CELL_KB_MKEY_R_WIN); // The super keys are supposed to be the windows keys, but they trigger the meta key instead. Let's assign the windows keys to both.
// CELL_KB_RAWDAT
// buttons.emplace_back(, CELL_KEYC_NO_EVENT); // Redundant, listed for completeness
// buttons.emplace_back(, CELL_KEYC_E_ROLLOVER);
// buttons.emplace_back(, CELL_KEYC_E_POSTFAIL);
// buttons.emplace_back(, CELL_KEYC_E_UNDEF);
buttons.emplace_back(Qt::Key_Escape, CELL_KEYC_ESCAPE);
buttons.emplace_back(Qt::Key_Kanji, CELL_KEYC_106_KANJI);
buttons.emplace_back(Qt::Key_CapsLock, CELL_KEYC_CAPS_LOCK);
buttons.emplace_back(Qt::Key_F1, CELL_KEYC_F1);
buttons.emplace_back(Qt::Key_F2, CELL_KEYC_F2);
buttons.emplace_back(Qt::Key_F3, CELL_KEYC_F3);
buttons.emplace_back(Qt::Key_F4, CELL_KEYC_F4);
buttons.emplace_back(Qt::Key_F5, CELL_KEYC_F5);
buttons.emplace_back(Qt::Key_F6, CELL_KEYC_F6);
buttons.emplace_back(Qt::Key_F7, CELL_KEYC_F7);
buttons.emplace_back(Qt::Key_F8, CELL_KEYC_F8);
buttons.emplace_back(Qt::Key_F9, CELL_KEYC_F9);
buttons.emplace_back(Qt::Key_F10, CELL_KEYC_F10);
buttons.emplace_back(Qt::Key_F11, CELL_KEYC_F11);
buttons.emplace_back(Qt::Key_F12, CELL_KEYC_F12);
buttons.emplace_back(Qt::Key_Print, CELL_KEYC_PRINTSCREEN);
buttons.emplace_back(Qt::Key_ScrollLock, CELL_KEYC_SCROLL_LOCK);
buttons.emplace_back(Qt::Key_Pause, CELL_KEYC_PAUSE);
buttons.emplace_back(Qt::Key_Insert, CELL_KEYC_INSERT);
buttons.emplace_back(Qt::Key_Home, CELL_KEYC_HOME);
buttons.emplace_back(Qt::Key_PageUp, CELL_KEYC_PAGE_UP);
buttons.emplace_back(Qt::Key_Delete, CELL_KEYC_DELETE);
buttons.emplace_back(Qt::Key_End, CELL_KEYC_END);
buttons.emplace_back(Qt::Key_PageDown, CELL_KEYC_PAGE_DOWN);
buttons.emplace_back(Qt::Key_Right, CELL_KEYC_RIGHT_ARROW);
buttons.emplace_back(Qt::Key_Left, CELL_KEYC_LEFT_ARROW);
buttons.emplace_back(Qt::Key_Down, CELL_KEYC_DOWN_ARROW);
buttons.emplace_back(Qt::Key_Up, CELL_KEYC_UP_ARROW);
// buttons.emplace_back(, CELL_KEYC_NUM_LOCK);
// buttons.emplace_back(, CELL_KEYC_APPLICATION); // This is probably the PS key on the PS3 keyboard
buttons.emplace_back(Qt::Key_Kana_Shift, CELL_KEYC_KANA); // maybe Key_Kana_Lock
buttons.emplace_back(Qt::Key_Henkan, CELL_KEYC_HENKAN);
buttons.emplace_back(Qt::Key_Muhenkan, CELL_KEYC_MUHENKAN);
// CELL_KB_KEYPAD
buttons.emplace_back(Qt::Key_NumLock, CELL_KEYC_KPAD_NUMLOCK);
buttons.emplace_back(Qt::Key_division, CELL_KEYC_KPAD_SLASH); // should ideally be slash but that's occupied obviously
buttons.emplace_back(Qt::Key_multiply, CELL_KEYC_KPAD_ASTERISK); // should ideally be asterisk but that's occupied obviously
// buttons.emplace_back(Qt::Key_Minus, CELL_KEYC_KPAD_MINUS); // should ideally be minus but that's occupied obviously
buttons.emplace_back(Qt::Key_Plus, CELL_KEYC_KPAD_PLUS);
buttons.emplace_back(Qt::Key_Enter, CELL_KEYC_KPAD_ENTER);
// buttons.emplace_back(Qt::Key_1, CELL_KEYC_KPAD_1);
// buttons.emplace_back(Qt::Key_2, CELL_KEYC_KPAD_2);
// buttons.emplace_back(Qt::Key_3, CELL_KEYC_KPAD_3);
// buttons.emplace_back(Qt::Key_4, CELL_KEYC_KPAD_4);
// buttons.emplace_back(Qt::Key_5, CELL_KEYC_KPAD_5);
// buttons.emplace_back(Qt::Key_6, CELL_KEYC_KPAD_6);
// buttons.emplace_back(Qt::Key_7, CELL_KEYC_KPAD_7);
// buttons.emplace_back(Qt::Key_8, CELL_KEYC_KPAD_8);
// buttons.emplace_back(Qt::Key_9, CELL_KEYC_KPAD_9);
// buttons.emplace_back(Qt::Key_0, CELL_KEYC_KPAD_0);
// buttons.emplace_back(Qt::Key_Delete, CELL_KEYC_KPAD_PERIOD);
// ASCII Printable characters
buttons.emplace_back(Qt::Key_A, CELL_KEYC_A);
buttons.emplace_back(Qt::Key_B, CELL_KEYC_B);
buttons.emplace_back(Qt::Key_C, CELL_KEYC_C);
buttons.emplace_back(Qt::Key_D, CELL_KEYC_D);
buttons.emplace_back(Qt::Key_E, CELL_KEYC_E);
buttons.emplace_back(Qt::Key_F, CELL_KEYC_F);
buttons.emplace_back(Qt::Key_G, CELL_KEYC_G);
buttons.emplace_back(Qt::Key_H, CELL_KEYC_H);
buttons.emplace_back(Qt::Key_I, CELL_KEYC_I);
buttons.emplace_back(Qt::Key_J, CELL_KEYC_J);
buttons.emplace_back(Qt::Key_K, CELL_KEYC_K);
buttons.emplace_back(Qt::Key_L, CELL_KEYC_L);
buttons.emplace_back(Qt::Key_M, CELL_KEYC_M);
buttons.emplace_back(Qt::Key_N, CELL_KEYC_N);
buttons.emplace_back(Qt::Key_O, CELL_KEYC_O);
buttons.emplace_back(Qt::Key_P, CELL_KEYC_P);
buttons.emplace_back(Qt::Key_Q, CELL_KEYC_Q);
buttons.emplace_back(Qt::Key_R, CELL_KEYC_R);
buttons.emplace_back(Qt::Key_S, CELL_KEYC_S);
buttons.emplace_back(Qt::Key_T, CELL_KEYC_T);
buttons.emplace_back(Qt::Key_U, CELL_KEYC_U);
buttons.emplace_back(Qt::Key_V, CELL_KEYC_V);
buttons.emplace_back(Qt::Key_W, CELL_KEYC_W);
buttons.emplace_back(Qt::Key_X, CELL_KEYC_X);
buttons.emplace_back(Qt::Key_Y, CELL_KEYC_Y);
buttons.emplace_back(Qt::Key_Z, CELL_KEYC_Z);
buttons.emplace_back(Qt::Key_1, CELL_KEYC_1);
buttons.emplace_back(Qt::Key_2, CELL_KEYC_2);
buttons.emplace_back(Qt::Key_3, CELL_KEYC_3);
buttons.emplace_back(Qt::Key_4, CELL_KEYC_4);
buttons.emplace_back(Qt::Key_5, CELL_KEYC_5);
buttons.emplace_back(Qt::Key_6, CELL_KEYC_6);
buttons.emplace_back(Qt::Key_7, CELL_KEYC_7);
buttons.emplace_back(Qt::Key_8, CELL_KEYC_8);
buttons.emplace_back(Qt::Key_9, CELL_KEYC_9);
buttons.emplace_back(Qt::Key_0, CELL_KEYC_0);
buttons.emplace_back(Qt::Key_Return, CELL_KEYC_ENTER);
buttons.emplace_back(Qt::Key_Backspace, CELL_KEYC_BS);
buttons.emplace_back(Qt::Key_Tab, CELL_KEYC_TAB);
buttons.emplace_back(Qt::Key_Space, CELL_KEYC_SPACE);
buttons.emplace_back(Qt::Key_Minus, CELL_KEYC_MINUS);
buttons.emplace_back(Qt::Key_Equal, CELL_KEYC_EQUAL_101);
buttons.emplace_back(Qt::Key_AsciiCircum, CELL_KEYC_ACCENT_CIRCONFLEX_106);
buttons.emplace_back(Qt::Key_At, CELL_KEYC_ATMARK_106);
buttons.emplace_back(Qt::Key_Semicolon, CELL_KEYC_SEMICOLON);
buttons.emplace_back(Qt::Key_Apostrophe, CELL_KEYC_QUOTATION_101);
buttons.emplace_back(Qt::Key_Colon, CELL_KEYC_COLON_106);
buttons.emplace_back(Qt::Key_Comma, CELL_KEYC_COMMA);
buttons.emplace_back(Qt::Key_Period, CELL_KEYC_PERIOD);
buttons.emplace_back(Qt::Key_Slash, CELL_KEYC_SLASH);
buttons.emplace_back(Qt::Key_yen, CELL_KEYC_YEN_106);
// Some buttons share the same key code on different layouts
if (keyboard.m_config.arrange == CELL_KB_MAPPING_106)
{
buttons.emplace_back(Qt::Key_Backslash, CELL_KEYC_BACKSLASH_106);
buttons.emplace_back(Qt::Key_BracketLeft, CELL_KEYC_LEFT_BRACKET_106);
buttons.emplace_back(Qt::Key_BracketRight, CELL_KEYC_RIGHT_BRACKET_106);
}
else
{
buttons.emplace_back(Qt::Key_Backslash, CELL_KEYC_BACKSLASH_101);
buttons.emplace_back(Qt::Key_BracketLeft, CELL_KEYC_LEFT_BRACKET_101);
buttons.emplace_back(Qt::Key_BracketRight, CELL_KEYC_RIGHT_BRACKET_101);
}
// Made up helper buttons
buttons.emplace_back(Qt::Key_Less, CELL_KEYC_LESS);
buttons.emplace_back(Qt::Key_NumberSign, CELL_KEYC_HASHTAG);
buttons.emplace_back(Qt::Key_ssharp, CELL_KEYC_SSHARP);
buttons.emplace_back(Qt::Key_QuoteLeft, CELL_KEYC_BACK_QUOTE);
buttons.emplace_back(Qt::Key_acute, CELL_KEYC_BACK_QUOTE);
// Fill our map
for (const KbButton& button : buttons)
{
if (!keyboard.m_keys.try_emplace(button.m_keyCode, button).second)
{
input_log.error("basic_keyboard_handler failed to set key code %d", button.m_keyCode);
}
}
}

View file

@ -1,26 +0,0 @@
#pragma once
#include "util/types.hpp"
#include "Emu/Io/KeyboardHandler.h"
#include <QKeyEvent>
#include <QWindow>
class basic_keyboard_handler final : public KeyboardHandlerBase, public QObject
{
using KeyboardHandlerBase::KeyboardHandlerBase;
public:
void Init(keyboard_consumer& consumer, const u32 max_connect) override;
void SetTargetWindow(QWindow* target);
bool eventFilter(QObject* watched, QEvent* event) override;
void keyPressEvent(QKeyEvent* event);
void keyReleaseEvent(QKeyEvent* event);
static s32 getUnmodifiedKey(QKeyEvent* event);
private:
void LoadSettings(Keyboard& keyboard);
QWindow* m_target = nullptr;
};

View file

@ -1,280 +0,0 @@
#include <QApplication>
#include <QCursor>
#include "util/types.hpp"
#include "util/logs.hpp"
#include "basic_mouse_handler.h"
#include "keyboard_pad_handler.h"
#include "../gs_frame.h"
#include "Emu/Io/interception.h"
#include "Emu/Io/mouse_config.h"
mouse_config g_cfg_mouse;
void basic_mouse_handler::Init(const u32 max_connect)
{
if (m_info.max_connect > 0)
{
// Already initialized
return;
}
if (!g_cfg_mouse.load())
{
input_log.notice("basic_mouse_handler: Could not load basic mouse config. Using defaults.");
}
reload_config();
m_mice.clear();
m_mice.emplace_back(Mouse());
m_info = {};
m_info.max_connect = max_connect;
m_info.now_connect = std::min(::size32(m_mice), max_connect);
m_info.info = input::g_mice_intercepted ? CELL_MOUSE_INFO_INTERCEPTED : 0; // Ownership of mouse data: 0=Application, 1=System
for (u32 i = 1; i < max_connect; i++)
{
m_info.status[i] = CELL_MOUSE_STATUS_DISCONNECTED;
m_info.mode[i] = CELL_MOUSE_INFO_TABLET_MOUSE_MODE;
m_info.tablet_is_supported[i] = CELL_MOUSE_INFO_TABLET_NOT_SUPPORTED;
}
m_info.status[0] = CELL_MOUSE_STATUS_CONNECTED; // (TODO: Support for more mice)
m_info.vendor_id[0] = 0x1234;
m_info.product_id[0] = 0x1234;
type = mouse_handler::basic;
}
void basic_mouse_handler::reload_config()
{
input_log.notice("Basic mouse config=\n%s", g_cfg_mouse.to_string());
m_buttons[CELL_MOUSE_BUTTON_1] = get_mouse_button(g_cfg_mouse.mouse_button_1);
m_buttons[CELL_MOUSE_BUTTON_2] = get_mouse_button(g_cfg_mouse.mouse_button_2);
m_buttons[CELL_MOUSE_BUTTON_3] = get_mouse_button(g_cfg_mouse.mouse_button_3);
m_buttons[CELL_MOUSE_BUTTON_4] = get_mouse_button(g_cfg_mouse.mouse_button_4);
m_buttons[CELL_MOUSE_BUTTON_5] = get_mouse_button(g_cfg_mouse.mouse_button_5);
m_buttons[CELL_MOUSE_BUTTON_6] = get_mouse_button(g_cfg_mouse.mouse_button_6);
m_buttons[CELL_MOUSE_BUTTON_7] = get_mouse_button(g_cfg_mouse.mouse_button_7);
m_buttons[CELL_MOUSE_BUTTON_8] = get_mouse_button(g_cfg_mouse.mouse_button_8);
}
/* Sets the target window for the event handler, and also installs an event filter on the target. */
void basic_mouse_handler::SetTargetWindow(QWindow* target)
{
if (target)
{
m_target = target;
target->installEventFilter(this);
}
else
{
// If this is hit, it probably means that some refactoring occurs because currently a gsframe is created in Load.
// We still want events so filter from application instead since target is null.
QApplication::instance()->installEventFilter(this);
input_log.error("Trying to set mouse handler to a null target window.");
}
}
bool basic_mouse_handler::eventFilter(QObject* target, QEvent* ev)
{
if (m_info.max_connect == 0)
{
// Not initialized
return false;
}
if (!ev) [[unlikely]]
{
return false;
}
if (input::g_active_mouse_and_keyboard != input::active_mouse_and_keyboard::emulated)
{
return false;
}
// !m_target is for future proofing when gsrender isn't automatically initialized on load to ensure events still occur
// !m_target->isVisible() is a hack since currently a guiless application will STILL inititialize a gsrender (providing a valid target)
if (!m_target || !m_target->isVisible() || target == m_target)
{
if (g_cfg_mouse.reload_requested.exchange(false))
{
reload_config();
}
switch (ev->type())
{
case QEvent::MouseButtonPress:
MouseButton(static_cast<QMouseEvent*>(ev), true);
break;
case QEvent::MouseButtonRelease:
MouseButton(static_cast<QMouseEvent*>(ev), false);
break;
case QEvent::MouseMove:
MouseMove(static_cast<QMouseEvent*>(ev));
break;
case QEvent::Wheel:
MouseScroll(static_cast<QWheelEvent*>(ev));
break;
case QEvent::KeyPress:
Key(static_cast<QKeyEvent*>(ev), true);
break;
case QEvent::KeyRelease:
Key(static_cast<QKeyEvent*>(ev), false);
break;
case QEvent::Leave:
{
// Issue mouse move on leave. Otherwise we may not get any mouse event at the screen borders.
const QPoint window_pos = m_target->mapToGlobal(m_target->position()) / m_target->devicePixelRatio();
const QPoint cursor_pos = QCursor::pos() - window_pos;
if (cursor_pos.x() <= 0 || cursor_pos.x() >= m_target->width() || cursor_pos.y() <= 0 || cursor_pos.y() >= m_target->height())
{
MouseMove(cursor_pos);
}
break;
}
default:
return false;
}
}
return false;
}
void basic_mouse_handler::Key(QKeyEvent* event, bool pressed)
{
if (!event) [[unlikely]]
{
return;
}
const int key = event->key();
if (const auto it = std::find_if(m_buttons.cbegin(), m_buttons.cend(), [key](const auto& entry)
{
return entry.second.code == key && entry.second.is_key;
});
it != m_buttons.cend())
{
MouseHandlerBase::Button(0, it->first, pressed);
}
}
void basic_mouse_handler::MouseButton(QMouseEvent* event, bool pressed)
{
if (!event) [[unlikely]]
{
return;
}
const int button = event->button();
if (const auto it = std::find_if(m_buttons.cbegin(), m_buttons.cend(), [button](const auto& entry)
{
return entry.second.code == button && !entry.second.is_key;
});
it != m_buttons.cend())
{
MouseHandlerBase::Button(0, it->first, pressed);
}
}
void basic_mouse_handler::MouseScroll(QWheelEvent* event)
{
if (!event) [[unlikely]]
{
return;
}
const QPoint delta = event->angleDelta();
const s8 x = std::clamp(delta.x() / 120, -128, 127);
const s8 y = std::clamp(delta.y() / 120, -128, 127);
MouseHandlerBase::Scroll(0, x, y);
}
bool basic_mouse_handler::get_mouse_lock_state() const
{
if (auto game_frame = dynamic_cast<gs_frame*>(m_target))
return game_frame->get_mouse_lock_state();
return false;
}
basic_mouse_handler::mouse_button basic_mouse_handler::get_mouse_button(const cfg::string& button)
{
const std::string name = button.to_string();
const auto it = std::find_if(mouse_list.cbegin(), mouse_list.cend(), [&name](const auto& entry)
{
return entry.second == name;
});
if (it != mouse_list.cend())
{
return mouse_button{
.code = static_cast<int>(it->first),
.is_key = false};
}
if (const u32 key = keyboard_pad_handler::GetKeyCode(QString::fromStdString(name)))
{
return mouse_button{
.code = static_cast<int>(key),
.is_key = true};
}
return mouse_button{
.code = Qt::MouseButton::NoButton,
.is_key = false};
}
void basic_mouse_handler::MouseMove(QMouseEvent* event)
{
if (!event) [[unlikely]]
{
return;
}
if (is_time_for_update())
{
MouseMove(event->pos());
}
}
void basic_mouse_handler::MouseMove(const QPoint& e_pos)
{
if (!m_target)
return;
// get the screen dimensions
const QSize screen = m_target->size();
if (m_target->isActive() && get_mouse_lock_state())
{
// get the center of the screen in global coordinates
QPoint p_center = m_target->geometry().topLeft() + QPoint(screen.width() / 2, screen.height() / 2);
// reset the mouse to the center for consistent results since edge movement won't be registered
QCursor::setPos(m_target->screen(), p_center);
// convert the center into screen coordinates
p_center = m_target->mapFromGlobal(p_center);
// current mouse position, starting at the center
static QPoint p_real(p_center);
// get the delta of the mouse position to the screen center
const QPoint p_delta = e_pos - p_center;
// update the current position without leaving the screen borders
p_real.setX(std::clamp(p_real.x() + p_delta.x(), 0, screen.width()));
p_real.setY(std::clamp(p_real.y() + p_delta.y(), 0, screen.height()));
// pass the 'real' position and the current delta to the screen center
MouseHandlerBase::Move(0, p_real.x(), p_real.y(), screen.width(), screen.height(), true, p_delta.x(), p_delta.y());
}
else
{
// pass the absolute position
MouseHandlerBase::Move(0, e_pos.x(), e_pos.y(), screen.width(), screen.height());
}
}

View file

@ -1,44 +0,0 @@
#pragma once
#include "util/types.hpp"
#include "Emu/Io/MouseHandler.h"
#include <QWindow>
#include <QMouseEvent>
#include <QWheelEvent>
namespace cfg
{
class string;
}
class basic_mouse_handler final : public MouseHandlerBase, public QObject
{
using MouseHandlerBase::MouseHandlerBase;
public:
void Init(const u32 max_connect) override;
void SetTargetWindow(QWindow* target);
void Key(QKeyEvent* event, bool pressed);
void MouseButton(QMouseEvent* event, bool pressed);
void MouseScroll(QWheelEvent* event);
void MouseMove(QMouseEvent* event);
void MouseMove(const QPoint& e_pos);
bool eventFilter(QObject* obj, QEvent* ev) override;
private:
void reload_config();
bool get_mouse_lock_state() const;
struct mouse_button
{
int code = Qt::MouseButton::NoButton;
bool is_key = false;
};
static mouse_button get_mouse_button(const cfg::string& button);
QWindow* m_target = nullptr;
std::map<u8, mouse_button> m_buttons;
};

View file

@ -1,815 +0,0 @@
#include "stdafx.h"
#include "gui_pad_thread.h"
#include "Input/ds3_pad_handler.h"
#include "Input/ds4_pad_handler.h"
#include "Input/dualsense_pad_handler.h"
#include "Input/skateboard_pad_handler.h"
#ifdef _WIN32
#include "Input/xinput_pad_handler.h"
#include "Input/mm_joystick_handler.h"
#elif HAVE_LIBEVDEV
#include "Input/evdev_joystick_handler.h"
#endif
#ifdef HAVE_SDL3
#include "Input/sdl_pad_handler.h"
#endif
#include "Emu/Io/PadHandler.h"
#include "Emu/system_config.h"
#include "../gui_settings.h"
#ifdef __linux__
#include <linux/uinput.h>
#include <fcntl.h>
#include <unistd.h>
#define CHECK_IOCTRL_RET(res) \
if (res == -1) \
{ \
gui_log.error("gui_pad_thread: ioctl failed (errno=%d=%s)", res, strerror(errno)); \
}
#elif defined(__APPLE__)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wold-style-cast"
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
#pragma GCC diagnostic ignored "-Wmissing-declarations"
#pragma GCC diagnostic ignored "-Wnullability-completeness"
#pragma GCC diagnostic ignored "-Wdeprecated-anon-enum-enum-conversion"
#include <ApplicationServices/ApplicationServices.h>
#include <Carbon/Carbon.h>
#pragma GCC diagnostic pop
#endif
#include <QApplication>
LOG_CHANNEL(gui_log, "GUI");
atomic_t<bool> gui_pad_thread::m_reset = false;
gui_pad_thread::gui_pad_thread()
{
m_thread = std::make_unique<named_thread<std::function<void()>>>("Gui Pad Thread", [this]()
{
run();
});
}
gui_pad_thread::~gui_pad_thread()
{
if (m_thread)
{
auto& thread = *m_thread;
thread = thread_state::aborting;
thread();
m_thread.reset();
}
#ifdef __linux__
if (m_uinput_fd != 1)
{
gui_log.notice("gui_pad_thread: closing /dev/uinput");
CHECK_IOCTRL_RET(ioctl(m_uinput_fd, UI_DEV_DESTROY));
int res = close(m_uinput_fd);
if (res == -1)
{
gui_log.error("gui_pad_thread: Failed to close /dev/uinput (errno=%d=%s)", res, strerror(errno));
}
m_uinput_fd = -1;
}
#endif
}
void gui_pad_thread::update_settings(const std::shared_ptr<gui_settings>& settings)
{
ensure(!!settings);
m_allow_global_input = settings->GetValue(gui::nav_global).toBool();
}
bool gui_pad_thread::init()
{
m_handler.reset();
m_pad.reset();
// Initialize last button states as pressed to avoid unwanted button presses when starting the thread.
m_last_button_state.fill(true);
m_timestamp = steady_clock::now();
m_initial_timestamp = steady_clock::now();
m_last_auto_repeat_button = pad_button::pad_button_max_enum;
g_cfg_input_configs.load();
std::string active_config = g_cfg_input_configs.active_configs.get_value("");
if (active_config.empty())
{
active_config = g_cfg_input_configs.active_configs.get_value(g_cfg_input_configs.global_key);
}
gui_log.notice("gui_pad_thread: Using input configuration: '%s'", active_config);
// Load in order to get the pad handlers
if (!g_cfg_input.load("", active_config))
{
gui_log.notice("gui_pad_thread: Loaded empty pad config");
}
// Adjust to the different pad handlers
for (usz i = 0; i < g_cfg_input.player.size(); i++)
{
std::shared_ptr<PadHandlerBase> handler;
gui_pad_thread::InitPadConfig(g_cfg_input.player[i]->config, g_cfg_input.player[i]->handler, handler);
}
// Reload with proper defaults
if (!g_cfg_input.load("", active_config))
{
gui_log.notice("gui_pad_thread: Reloaded empty pad config");
}
gui_log.trace("gui_pad_thread: Using pad config:\n%s", g_cfg_input);
for (u32 i = 0; i < CELL_PAD_MAX_PORT_NUM; i++) // max 7 pads
{
cfg_player* cfg = g_cfg_input.player[i];
const pad_handler handler_type = cfg->handler.get();
std::shared_ptr<PadHandlerBase> cur_pad_handler = GetHandler(handler_type);
if (!cur_pad_handler)
{
continue;
}
cur_pad_handler->Init();
m_handler = cur_pad_handler;
m_pad = std::make_shared<Pad>(handler_type, i, CELL_PAD_STATUS_DISCONNECTED, CELL_PAD_CAPABILITY_PS3_CONFORMITY | CELL_PAD_CAPABILITY_PRESS_MODE | CELL_PAD_CAPABILITY_ACTUATOR, CELL_PAD_DEV_TYPE_STANDARD);
if (!cur_pad_handler->bindPadToDevice(m_pad))
{
gui_log.error("gui_pad_thread: Failed to bind device '%s' to handler %s.", cfg->device.to_string(), handler_type);
}
gui_log.notice("gui_pad_thread: Pad %d: device='%s', handler=%s, VID=0x%x, PID=0x%x, class_type=0x%x, class_profile=0x%x",
i, cfg->device.to_string(), m_pad->m_pad_handler, m_pad->m_vendor_id, m_pad->m_product_id, m_pad->m_class_type, m_pad->m_class_profile);
if (handler_type != pad_handler::null)
{
input_log.notice("gui_pad_thread %d: config=\n%s", i, cfg->to_string());
}
// We only use one pad
break;
}
if (!m_handler || !m_pad)
{
gui_log.notice("gui_pad_thread: No devices configured.");
return false;
}
#ifdef __linux__
gui_log.notice("gui_pad_thread: opening /dev/uinput");
m_uinput_fd = open("/dev/uinput", O_WRONLY | O_NONBLOCK);
if (m_uinput_fd == -1)
{
gui_log.error("gui_pad_thread: Failed to open /dev/uinput (errno=%d=%s)", m_uinput_fd, strerror(errno));
return false;
}
struct uinput_setup usetup{};
usetup.id.bustype = BUS_USB;
usetup.id.vendor = 0x1234;
usetup.id.product = 0x1234;
std::strcpy(usetup.name, "RPCS3 GUI Input Device");
// The ioctls below will enable the device that is about to be created to pass events.
CHECK_IOCTRL_RET(ioctl(m_uinput_fd, UI_SET_EVBIT, EV_KEY));
CHECK_IOCTRL_RET(ioctl(m_uinput_fd, UI_SET_KEYBIT, KEY_ESC));
CHECK_IOCTRL_RET(ioctl(m_uinput_fd, UI_SET_KEYBIT, KEY_ENTER));
CHECK_IOCTRL_RET(ioctl(m_uinput_fd, UI_SET_KEYBIT, KEY_BACKSPACE));
CHECK_IOCTRL_RET(ioctl(m_uinput_fd, UI_SET_KEYBIT, KEY_TAB));
CHECK_IOCTRL_RET(ioctl(m_uinput_fd, UI_SET_KEYBIT, KEY_LEFT));
CHECK_IOCTRL_RET(ioctl(m_uinput_fd, UI_SET_KEYBIT, KEY_RIGHT));
CHECK_IOCTRL_RET(ioctl(m_uinput_fd, UI_SET_KEYBIT, KEY_UP));
CHECK_IOCTRL_RET(ioctl(m_uinput_fd, UI_SET_KEYBIT, KEY_DOWN));
CHECK_IOCTRL_RET(ioctl(m_uinput_fd, UI_SET_KEYBIT, BTN_LEFT));
CHECK_IOCTRL_RET(ioctl(m_uinput_fd, UI_SET_KEYBIT, BTN_RIGHT));
CHECK_IOCTRL_RET(ioctl(m_uinput_fd, UI_SET_KEYBIT, BTN_MIDDLE));
CHECK_IOCTRL_RET(ioctl(m_uinput_fd, UI_SET_EVBIT, EV_REL));
CHECK_IOCTRL_RET(ioctl(m_uinput_fd, UI_SET_RELBIT, REL_X));
CHECK_IOCTRL_RET(ioctl(m_uinput_fd, UI_SET_RELBIT, REL_Y));
CHECK_IOCTRL_RET(ioctl(m_uinput_fd, UI_SET_RELBIT, REL_WHEEL));
CHECK_IOCTRL_RET(ioctl(m_uinput_fd, UI_SET_RELBIT, REL_HWHEEL));
CHECK_IOCTRL_RET(ioctl(m_uinput_fd, UI_DEV_SETUP, &usetup));
CHECK_IOCTRL_RET(ioctl(m_uinput_fd, UI_DEV_CREATE));
#endif
return true;
}
std::shared_ptr<PadHandlerBase> gui_pad_thread::GetHandler(pad_handler type)
{
switch (type)
{
case pad_handler::null:
case pad_handler::keyboard:
case pad_handler::move:
// Makes no sense to use this if we are in the GUI anyway
return nullptr;
case pad_handler::ds3:
return std::make_shared<ds3_pad_handler>();
case pad_handler::ds4:
return std::make_shared<ds4_pad_handler>();
case pad_handler::dualsense:
return std::make_shared<dualsense_pad_handler>();
case pad_handler::skateboard:
return std::make_shared<skateboard_pad_handler>();
#ifdef _WIN32
case pad_handler::xinput:
return std::make_shared<xinput_pad_handler>();
case pad_handler::mm:
return std::make_shared<mm_joystick_handler>();
#endif
#ifdef HAVE_SDL3
case pad_handler::sdl:
return std::make_shared<sdl_pad_handler>();
#endif
#ifdef HAVE_LIBEVDEV
case pad_handler::evdev:
return std::make_shared<evdev_joystick_handler>();
#endif
}
return nullptr;
}
void gui_pad_thread::InitPadConfig(cfg_pad& cfg, pad_handler type, std::shared_ptr<PadHandlerBase>& handler)
{
if (!handler)
{
handler = GetHandler(type);
if (handler)
{
handler->init_config(&cfg);
}
}
}
void gui_pad_thread::run()
{
gui_log.notice("gui_pad_thread: Pad thread started");
m_reset = true;
while (thread_ctrl::state() != thread_state::aborting)
{
if (m_reset && m_reset.exchange(false))
{
if (!init())
{
gui_log.warning("gui_pad_thread: Pad thread stopped (init failed during reset)");
return;
}
}
// Only process input if there is an active window
if (m_handler && m_pad && (m_allow_global_input || QApplication::activeWindow()))
{
m_handler->process();
if (thread_ctrl::state() == thread_state::aborting)
{
break;
}
process_input();
}
thread_ctrl::wait_for(10000);
}
gui_log.notice("gui_pad_thread: Pad thread stopped");
}
void gui_pad_thread::process_input()
{
if (!m_pad || !(m_pad->m_port_status & CELL_PAD_STATUS_CONNECTED))
{
return;
}
constexpr u64 ms_threshold = 500;
const auto on_button_pressed = [this](pad_button button_id, bool pressed, u16 value)
{
if (button_id == m_mouse_boost_button)
{
m_boost_mouse = pressed;
return;
}
u16 key = 0;
mouse_button btn = mouse_button::none;
mouse_wheel wheel = mouse_wheel::none;
float wheel_delta = 0.0f;
const float wheel_multiplier = pressed ? (m_boost_mouse ? 10.0f : 1.0f) : 0.0f;
const float move_multiplier = pressed ? (m_boost_mouse ? 40.0f : 20.0f) : 0.0f;
switch (button_id)
{
#ifdef _WIN32
case pad_button::dpad_up: key = VK_UP; break;
case pad_button::dpad_down: key = VK_DOWN; break;
case pad_button::dpad_left: key = VK_LEFT; break;
case pad_button::dpad_right: key = VK_RIGHT; break;
case pad_button::circle: key = VK_ESCAPE; break;
case pad_button::cross: key = VK_RETURN; break;
case pad_button::square: key = VK_BACK; break;
case pad_button::triangle: key = VK_TAB; break;
#elif defined(__linux__)
case pad_button::dpad_up: key = KEY_UP; break;
case pad_button::dpad_down: key = KEY_DOWN; break;
case pad_button::dpad_left: key = KEY_LEFT; break;
case pad_button::dpad_right: key = KEY_RIGHT; break;
case pad_button::circle: key = KEY_ESC; break;
case pad_button::cross: key = KEY_ENTER; break;
case pad_button::square: key = KEY_BACKSPACE; break;
case pad_button::triangle: key = KEY_TAB; break;
#elif defined(__APPLE__)
case pad_button::dpad_up: key = kVK_UpArrow; break;
case pad_button::dpad_down: key = kVK_DownArrow; break;
case pad_button::dpad_left: key = kVK_LeftArrow; break;
case pad_button::dpad_right: key = kVK_RightArrow; break;
case pad_button::circle: key = kVK_Escape; break;
case pad_button::cross: key = kVK_Return; break;
case pad_button::square: key = kVK_Delete; break;
case pad_button::triangle: key = kVK_Tab; break;
#endif
case pad_button::L1: btn = mouse_button::left; break;
case pad_button::R1: btn = mouse_button::right; break;
case pad_button::rs_up:
wheel = mouse_wheel::vertical;
wheel_delta = 10.0f * wheel_multiplier;
break;
case pad_button::rs_down:
wheel = mouse_wheel::vertical;
wheel_delta = -10.0f * wheel_multiplier;
break;
case pad_button::rs_left:
wheel = mouse_wheel::horizontal;
wheel_delta = -10.0f * wheel_multiplier;
break;
case pad_button::rs_right:
wheel = mouse_wheel::horizontal;
wheel_delta = 10.0f * wheel_multiplier;
break;
case pad_button::ls_up: m_mouse_delta_y -= (abs(value - 128) / 255.f) * move_multiplier; break;
case pad_button::ls_down: m_mouse_delta_y += (abs(value - 128) / 255.f) * move_multiplier; break;
case pad_button::ls_left: m_mouse_delta_x -= (abs(value - 128) / 255.f) * move_multiplier; break;
case pad_button::ls_right: m_mouse_delta_x += (abs(value - 128) / 255.f) * move_multiplier; break;
default: return;
}
if (key)
{
send_key_event(key, pressed);
}
else if (btn != mouse_button::none)
{
send_mouse_button_event(btn, pressed);
}
else if (wheel != mouse_wheel::none && pressed)
{
send_mouse_wheel_event(wheel, wheel_delta);
}
};
const auto handle_button_press = [&](pad_button button_id, bool pressed, u16 value)
{
if (button_id >= pad_button::pad_button_max_enum)
{
return;
}
bool& last_state = m_last_button_state[static_cast<u32>(button_id)];
if (pressed)
{
const bool is_auto_repeat_button = m_auto_repeat_buttons.contains(button_id);
const bool is_mouse_move_button = m_mouse_move_buttons.contains(button_id);
if (!last_state)
{
if (button_id != m_mouse_boost_button && !is_mouse_move_button)
{
// The button was not pressed before, so this is a new button press. Reset auto-repeat.
m_timestamp = steady_clock::now();
m_initial_timestamp = m_timestamp;
m_last_auto_repeat_button = is_auto_repeat_button ? button_id : pad_button::pad_button_max_enum;
}
on_button_pressed(static_cast<pad_button>(button_id), true, value);
}
else if (is_auto_repeat_button)
{
if (m_last_auto_repeat_button == button_id && m_input_timer.GetMsSince(m_initial_timestamp) > ms_threshold && m_input_timer.GetMsSince(m_timestamp) > m_auto_repeat_buttons.at(button_id))
{
// The auto-repeat button was pressed for at least the given threshold in ms and will trigger at an interval.
m_timestamp = steady_clock::now();
on_button_pressed(static_cast<pad_button>(button_id), true, value);
}
else if (m_last_auto_repeat_button == pad_button::pad_button_max_enum)
{
// An auto-repeat button was already pressed before and will now start triggering again after the next threshold.
m_last_auto_repeat_button = button_id;
}
}
else if (is_mouse_move_button)
{
on_button_pressed(static_cast<pad_button>(button_id), pressed, value);
}
}
else if (last_state)
{
if (m_last_auto_repeat_button == button_id)
{
// We stopped pressing an auto-repeat button, so re-enable auto-repeat for other buttons.
m_last_auto_repeat_button = pad_button::pad_button_max_enum;
}
on_button_pressed(static_cast<pad_button>(button_id), false, value);
}
last_state = pressed;
};
for (const auto& button : m_pad->m_buttons)
{
pad_button button_id = pad_button::pad_button_max_enum;
if (button.m_offset == CELL_PAD_BTN_OFFSET_DIGITAL1)
{
switch (button.m_outKeyCode)
{
case CELL_PAD_CTRL_LEFT:
button_id = pad_button::dpad_left;
break;
case CELL_PAD_CTRL_RIGHT:
button_id = pad_button::dpad_right;
break;
case CELL_PAD_CTRL_DOWN:
button_id = pad_button::dpad_down;
break;
case CELL_PAD_CTRL_UP:
button_id = pad_button::dpad_up;
break;
case CELL_PAD_CTRL_L3:
button_id = pad_button::L3;
break;
case CELL_PAD_CTRL_R3:
button_id = pad_button::R3;
break;
case CELL_PAD_CTRL_SELECT:
button_id = pad_button::select;
break;
case CELL_PAD_CTRL_START:
button_id = pad_button::start;
break;
default:
break;
}
}
else if (button.m_offset == CELL_PAD_BTN_OFFSET_DIGITAL2)
{
switch (button.m_outKeyCode)
{
case CELL_PAD_CTRL_TRIANGLE:
button_id = pad_button::triangle;
break;
case CELL_PAD_CTRL_CIRCLE:
button_id = g_cfg.sys.enter_button_assignment == enter_button_assign::circle ? pad_button::cross : pad_button::circle;
break;
case CELL_PAD_CTRL_SQUARE:
button_id = pad_button::square;
break;
case CELL_PAD_CTRL_CROSS:
button_id = g_cfg.sys.enter_button_assignment == enter_button_assign::circle ? pad_button::circle : pad_button::cross;
break;
case CELL_PAD_CTRL_L1:
button_id = pad_button::L1;
break;
case CELL_PAD_CTRL_R1:
button_id = pad_button::R1;
break;
case CELL_PAD_CTRL_L2:
button_id = pad_button::L2;
break;
case CELL_PAD_CTRL_R2:
button_id = pad_button::R2;
break;
case CELL_PAD_CTRL_PS:
button_id = pad_button::ps;
break;
default:
break;
}
}
handle_button_press(button_id, button.m_pressed, button.m_value);
}
for (const AnalogStick& stick : m_pad->m_sticks)
{
pad_button button_id = pad_button::pad_button_max_enum;
pad_button release_id = pad_button::pad_button_max_enum;
switch (stick.m_offset)
{
case CELL_PAD_BTN_OFFSET_ANALOG_LEFT_X:
button_id = (stick.m_value <= 128) ? pad_button::ls_left : pad_button::ls_right;
release_id = (stick.m_value > 128) ? pad_button::ls_left : pad_button::ls_right;
break;
case CELL_PAD_BTN_OFFSET_ANALOG_LEFT_Y:
button_id = (stick.m_value <= 128) ? pad_button::ls_up : pad_button::ls_down;
release_id = (stick.m_value > 128) ? pad_button::ls_up : pad_button::ls_down;
break;
case CELL_PAD_BTN_OFFSET_ANALOG_RIGHT_X:
button_id = (stick.m_value <= 128) ? pad_button::rs_left : pad_button::rs_right;
release_id = (stick.m_value > 128) ? pad_button::rs_left : pad_button::rs_right;
break;
case CELL_PAD_BTN_OFFSET_ANALOG_RIGHT_Y:
button_id = (stick.m_value <= 128) ? pad_button::rs_up : pad_button::rs_down;
release_id = (stick.m_value > 128) ? pad_button::rs_up : pad_button::rs_down;
break;
default:
break;
}
bool pressed;
if (m_mouse_move_buttons.contains(button_id))
{
// Mouse move sticks are always pressed if they surpass a tiny deadzone.
constexpr int deadzone = 5;
pressed = std::abs(stick.m_value - 128) > deadzone;
}
else
{
// Let's say other sticks are only pressed if they are almost completely tilted. Otherwise navigation feels really wacky.
pressed = stick.m_value < 30 || stick.m_value > 225;
}
// Release other direction on the same axis first
handle_button_press(release_id, false, stick.m_value);
// Handle currently pressed stick direction
handle_button_press(button_id, pressed, stick.m_value);
}
// Send mouse move event at the end to prevent redundant calls
// Round to lower integer
const int delta_x = m_mouse_delta_x;
const int delta_y = m_mouse_delta_y;
if (delta_x || delta_y)
{
// Remove integer part
m_mouse_delta_x -= delta_x;
m_mouse_delta_y -= delta_y;
// Send event
send_mouse_move_event(delta_x, delta_y);
}
}
#ifdef __linux__
void gui_pad_thread::emit_event(int type, int code, int val)
{
struct input_event ie{};
ie.type = type;
ie.code = code;
ie.value = val;
int res = write(m_uinput_fd, &ie, sizeof(ie));
if (res == -1)
{
gui_log.error("gui_pad_thread::emit_event: write failed (errno=%d=%s)", res, strerror(errno));
}
}
#endif
void gui_pad_thread::send_key_event(u32 key, bool pressed)
{
gui_log.trace("gui_pad_thread::send_key_event: key=%d, pressed=%d", key, pressed);
#ifdef _WIN32
INPUT input{};
input.type = INPUT_KEYBOARD;
input.ki.wVk = key;
if (!pressed)
{
input.ki.dwFlags = KEYEVENTF_KEYUP;
}
if (SendInput(1, &input, sizeof(INPUT)) != 1)
{
gui_log.error("gui_pad_thread: SendInput() failed: %s", fmt::win_error{GetLastError(), nullptr});
}
#elif defined(__linux__)
emit_event(EV_KEY, key, pressed ? 1 : 0);
emit_event(EV_SYN, SYN_REPORT, 0);
#elif defined(__APPLE__)
CGEventRef ev = CGEventCreateKeyboardEvent(NULL, static_cast<CGKeyCode>(key), pressed);
if (!ev)
{
gui_log.error("gui_pad_thread: CGEventCreateKeyboardEvent() failed");
return;
}
CGEventPost(kCGHIDEventTap, ev);
CFRelease(ev);
#endif
}
void gui_pad_thread::send_mouse_button_event(mouse_button btn, bool pressed)
{
gui_log.trace("gui_pad_thread::send_mouse_button_event: btn=%d, pressed=%d", static_cast<int>(btn), pressed);
#ifdef _WIN32
INPUT input{};
input.type = INPUT_MOUSE;
switch (btn)
{
case mouse_button::none: return;
case mouse_button::left: input.mi.dwFlags = pressed ? MOUSEEVENTF_LEFTDOWN : MOUSEEVENTF_LEFTUP; break;
case mouse_button::right: input.mi.dwFlags = pressed ? MOUSEEVENTF_RIGHTDOWN : MOUSEEVENTF_RIGHTUP; break;
case mouse_button::middle: input.mi.dwFlags = pressed ? MOUSEEVENTF_MIDDLEDOWN : MOUSEEVENTF_MIDDLEUP; break;
}
if (SendInput(1, &input, sizeof(INPUT)) != 1)
{
gui_log.error("gui_pad_thread: SendInput() failed: %s", fmt::win_error{GetLastError(), nullptr});
}
#elif defined(__linux__)
int key = 0;
switch (btn)
{
case mouse_button::none: return;
case mouse_button::left: key = BTN_LEFT; break;
case mouse_button::right: key = BTN_RIGHT; break;
case mouse_button::middle: key = BTN_MIDDLE; break;
}
emit_event(EV_KEY, key, pressed ? 1 : 0);
emit_event(EV_SYN, SYN_REPORT, 0);
#elif defined(__APPLE__)
CGEventType type{};
CGMouseButton mouse_btn{};
switch (btn)
{
case mouse_button::none: return;
case mouse_button::left:
type = pressed ? kCGEventLeftMouseDown : kCGEventLeftMouseUp;
mouse_btn = kCGMouseButtonLeft;
break;
case mouse_button::right:
type = pressed ? kCGEventRightMouseDown : kCGEventRightMouseUp;
mouse_btn = kCGMouseButtonRight;
break;
case mouse_button::middle:
type = pressed ? kCGEventOtherMouseDown : kCGEventOtherMouseUp;
mouse_btn = kCGMouseButtonCenter;
break;
}
CGEventRef ev = CGEventCreateMouseEvent(NULL, type, CGPointMake(m_mouse_abs_x, m_mouse_abs_y), mouse_btn);
if (!ev)
{
gui_log.error("gui_pad_thread: CGEventCreateMouseEvent() failed");
return;
}
CGEventPost(kCGHIDEventTap, ev);
CFRelease(ev);
#endif
}
void gui_pad_thread::send_mouse_wheel_event(mouse_wheel wheel, int delta)
{
gui_log.trace("gui_pad_thread::send_mouse_wheel_event: wheel=%d, delta=%d", static_cast<int>(wheel), delta);
if (!delta)
{
return;
}
#ifdef _WIN32
INPUT input{};
input.type = INPUT_MOUSE;
input.mi.mouseData = delta;
switch (wheel)
{
case mouse_wheel::none: return;
case mouse_wheel::vertical: input.mi.dwFlags = MOUSEEVENTF_WHEEL; break;
case mouse_wheel::horizontal: input.mi.dwFlags = MOUSEEVENTF_HWHEEL; break;
}
if (SendInput(1, &input, sizeof(INPUT)) != 1)
{
gui_log.error("gui_pad_thread: SendInput() failed: %s", fmt::win_error{GetLastError(), nullptr});
}
#elif defined(__linux__)
int axis = 0;
switch (wheel)
{
case mouse_wheel::none: return;
case mouse_wheel::vertical: axis = REL_WHEEL; break;
case mouse_wheel::horizontal: axis = REL_HWHEEL; break;
}
emit_event(EV_REL, axis, delta);
emit_event(EV_SYN, SYN_REPORT, 0);
#elif defined(__APPLE__)
int v_delta = 0;
int h_delta = 0;
switch (wheel)
{
case mouse_wheel::none: return;
case mouse_wheel::vertical: v_delta = delta; break;
case mouse_wheel::horizontal: h_delta = delta; break;
}
constexpr u32 wheel_count = 2;
CGEventRef ev = CGEventCreateScrollWheelEvent(NULL, kCGScrollEventUnitPixel, wheel_count, v_delta, h_delta);
if (!ev)
{
gui_log.error("gui_pad_thread: CGEventCreateScrollWheelEvent() failed");
return;
}
CGEventPost(kCGHIDEventTap, ev);
CFRelease(ev);
#endif
}
void gui_pad_thread::send_mouse_move_event(int delta_x, int delta_y)
{
gui_log.trace("gui_pad_thread::send_mouse_move_event: delta_x=%d, delta_y=%d", delta_x, delta_y);
if (!delta_x && !delta_y)
{
return;
}
#ifdef _WIN32
INPUT input{};
input.type = INPUT_MOUSE;
input.mi.dwFlags = MOUSEEVENTF_MOVE;
input.mi.dx = delta_x;
input.mi.dy = delta_y;
if (SendInput(1, &input, sizeof(INPUT)) != 1)
{
gui_log.error("gui_pad_thread: SendInput() failed: %s", fmt::win_error{GetLastError(), nullptr});
}
#elif defined(__linux__)
if (delta_x)
emit_event(EV_REL, REL_X, delta_x);
if (delta_y)
emit_event(EV_REL, REL_Y, delta_y);
emit_event(EV_SYN, SYN_REPORT, 0);
#elif defined(__APPLE__)
CGDirectDisplayID display = CGMainDisplayID();
const usz width = CGDisplayPixelsWide(display);
const usz height = CGDisplayPixelsHigh(display);
const float mouse_abs_x = std::clamp(m_mouse_abs_x + delta_x, 0.0f, width - 1.0f);
const float mouse_abs_y = std::clamp(m_mouse_abs_y + delta_y, 0.0f, height - 1.0f);
if (m_mouse_abs_x == mouse_abs_x && m_mouse_abs_y == mouse_abs_y)
{
return;
}
m_mouse_abs_x = mouse_abs_x;
m_mouse_abs_y = mouse_abs_y;
CGEventRef ev = CGEventCreateMouseEvent(NULL, kCGEventMouseMoved, CGPointMake(m_mouse_abs_x, m_mouse_abs_y), {});
if (!ev)
{
gui_log.error("gui_pad_thread: CGEventCreateMouseEvent() failed");
return;
}
CGEventPost(kCGHIDEventTap, ev);
CFRelease(ev);
#endif
}

View file

@ -1,101 +0,0 @@
#pragma once
#include "util/types.hpp"
#include "util/atomic.hpp"
#include "Emu/Io/pad_types.h"
#include "Emu/Io/pad_config.h"
#include "Emu/Io/pad_config_types.h"
#include "util/Timer.h"
#include "util/Thread.h"
class PadHandlerBase;
class gui_settings;
class gui_pad_thread
{
public:
gui_pad_thread();
virtual ~gui_pad_thread();
void update_settings(const std::shared_ptr<gui_settings>& settings);
static std::shared_ptr<PadHandlerBase> GetHandler(pad_handler type);
static void InitPadConfig(cfg_pad& cfg, pad_handler type, std::shared_ptr<PadHandlerBase>& handler);
static void reset()
{
m_reset = true;
}
protected:
bool init();
void run();
void process_input();
enum class mouse_button
{
none,
left,
right,
middle
};
enum class mouse_wheel
{
none,
vertical,
horizontal
};
void send_key_event(u32 key, bool pressed);
void send_mouse_button_event(mouse_button btn, bool pressed);
void send_mouse_wheel_event(mouse_wheel wheel, int delta);
void send_mouse_move_event(int delta_x, int delta_y);
#ifdef __linux__
int m_uinput_fd = -1;
void emit_event(int type, int code, int val);
#endif
std::shared_ptr<PadHandlerBase> m_handler;
std::shared_ptr<Pad> m_pad;
std::unique_ptr<named_thread<std::function<void()>>> m_thread;
atomic_t<bool> m_allow_global_input = false;
static atomic_t<bool> m_reset;
std::array<bool, static_cast<u32>(pad_button::pad_button_max_enum)> m_last_button_state{};
steady_clock::time_point m_timestamp;
steady_clock::time_point m_initial_timestamp;
Timer m_input_timer;
static constexpr u64 auto_repeat_ms_interval_default = 200;
pad_button m_last_auto_repeat_button = pad_button::pad_button_max_enum;
std::map<pad_button, u64> m_auto_repeat_buttons = {
{pad_button::dpad_up, auto_repeat_ms_interval_default},
{pad_button::dpad_down, auto_repeat_ms_interval_default},
{pad_button::dpad_left, auto_repeat_ms_interval_default},
{pad_button::dpad_right, auto_repeat_ms_interval_default},
{pad_button::rs_up, 1}, // used for wheel scrolling by default
{pad_button::rs_down, 1}, // used for wheel scrolling by default
{pad_button::rs_left, 1}, // used for wheel scrolling by default
{pad_button::rs_right, 1} // used for wheel scrolling by default
};
// Mouse movement should just work without delays
std::map<pad_button, u64> m_mouse_move_buttons = {
{pad_button::ls_up, 1},
{pad_button::ls_down, 1},
{pad_button::ls_left, 1},
{pad_button::ls_right, 1}};
pad_button m_mouse_boost_button = pad_button::L2;
bool m_boost_mouse = false;
float m_mouse_delta_x = 0.0f;
float m_mouse_delta_y = 0.0f;
#ifdef __APPLE__
float m_mouse_abs_x = 0.0f;
float m_mouse_abs_y = 0.0f;
#endif
};

File diff suppressed because it is too large Load diff

View file

@ -1,154 +0,0 @@
#pragma once
#include "util/types.hpp"
#include "Emu/Io/PadHandler.h"
#include <QWindow>
#include <QKeyEvent>
#include <string>
#include <vector>
#include <unordered_map>
enum mouse
{
move_left = 0x05555550,
move_right = 0x05555551,
move_up = 0x05555552,
move_down = 0x05555553,
wheel_up = 0x05555554,
wheel_down = 0x05555555,
wheel_left = 0x05555556,
wheel_right = 0x05555557
};
// Unique button names for the config files and our pad settings dialog
const std::unordered_map<u32, std::string> mouse_list =
{
{Qt::NoButton, ""},
{Qt::LeftButton, "Mouse Left"},
{Qt::RightButton, "Mouse Right"},
{Qt::MiddleButton, "Mouse Middle"},
{Qt::BackButton, "Mouse Back"},
{Qt::ForwardButton, "Mouse Fwd"},
{Qt::TaskButton, "Mouse Task"},
{Qt::ExtraButton4, "Mouse 4"},
{Qt::ExtraButton5, "Mouse 5"},
{Qt::ExtraButton6, "Mouse 6"},
{Qt::ExtraButton7, "Mouse 7"},
{Qt::ExtraButton8, "Mouse 8"},
{Qt::ExtraButton9, "Mouse 9"},
{Qt::ExtraButton10, "Mouse 10"},
{Qt::ExtraButton11, "Mouse 11"},
{Qt::ExtraButton12, "Mouse 12"},
{Qt::ExtraButton13, "Mouse 13"},
{Qt::ExtraButton14, "Mouse 14"},
{Qt::ExtraButton15, "Mouse 15"},
{Qt::ExtraButton16, "Mouse 16"},
{Qt::ExtraButton17, "Mouse 17"},
{Qt::ExtraButton18, "Mouse 18"},
{Qt::ExtraButton19, "Mouse 19"},
{Qt::ExtraButton20, "Mouse 20"},
{Qt::ExtraButton21, "Mouse 21"},
{Qt::ExtraButton22, "Mouse 22"},
{Qt::ExtraButton23, "Mouse 23"},
{Qt::ExtraButton24, "Mouse 24"},
{mouse::move_left, "Mouse MLeft"},
{mouse::move_right, "Mouse MRight"},
{mouse::move_up, "Mouse MUp"},
{mouse::move_down, "Mouse MDown"},
{mouse::wheel_up, "Wheel Up"},
{mouse::wheel_down, "Wheel Down"},
{mouse::wheel_left, "Wheel Left"},
{mouse::wheel_right, "Wheel Right"},
};
class keyboard_pad_handler final : public QObject, public PadHandlerBase
{
public:
bool Init() override;
keyboard_pad_handler();
void SetTargetWindow(QWindow* target);
void processKeyEvent(QKeyEvent* event, bool pressed);
void keyPressEvent(QKeyEvent* event);
void keyReleaseEvent(QKeyEvent* event);
void mousePressEvent(QMouseEvent* event);
void mouseReleaseEvent(QMouseEvent* event);
void mouseMoveEvent(QMouseEvent* event);
void mouseWheelEvent(QWheelEvent* event);
bool eventFilter(QObject* target, QEvent* ev) override;
void init_config(cfg_pad* cfg) override;
std::vector<pad_list_entry> list_devices() override;
connection get_next_button_press(const std::string& /*padId*/, const pad_callback& /*callback*/, const pad_fail_callback& /*fail_callback*/, gui_call_type /*call_type*/, const std::vector<std::string>& /*buttons*/) override
{
return connection::connected;
}
bool bindPadToDevice(std::shared_ptr<Pad> pad) override;
void process() override;
static std::string GetMouseName(const QMouseEvent* event);
static std::string GetMouseName(u32 button);
static QStringList GetKeyNames(const QKeyEvent* keyEvent);
static std::string GetKeyName(const QKeyEvent* keyEvent, bool with_modifiers);
static std::string GetKeyName(const u32& keyCode);
static std::set<u32> GetKeyCodes(const cfg::string& cfg_string);
static u32 GetKeyCode(const QString& keyName);
static int native_scan_code_from_string(const std::string& key);
static std::string native_scan_code_to_string(int native_scan_code);
protected:
void Key(const u32 code, bool pressed, u16 value = 255);
private:
QWindow* m_target = nullptr;
mouse_movement_mode m_mouse_movement_mode = mouse_movement_mode::relative;
bool m_keys_released = false;
bool m_mouse_move_used = false;
bool m_mouse_wheel_used = false;
bool get_mouse_lock_state() const;
void release_all_keys();
std::vector<Pad> m_pads_internal; // Accumulates input until the next poll. Only used for user input!
// Button Movements
steady_clock::time_point m_button_time;
f32 m_analog_lerp_factor = 1.0f;
f32 m_trigger_lerp_factor = 1.0f;
bool m_analog_limiter_toggle_mode = false;
bool m_pressure_intensity_toggle_mode = false;
u32 m_pressure_intensity_deadzone = 0;
// Stick Movements
steady_clock::time_point m_stick_time;
f32 m_l_stick_lerp_factor = 1.0f;
f32 m_r_stick_lerp_factor = 1.0f;
u32 m_l_stick_multiplier = 100;
u32 m_r_stick_multiplier = 100;
static constexpr usz max_sticks = 4;
std::array<u8, max_sticks> m_stick_min{0, 0, 0, 0};
std::array<u8, max_sticks> m_stick_max{128, 128, 128, 128};
std::array<u8, max_sticks> m_stick_val{128, 128, 128, 128};
// Mouse Movements
steady_clock::time_point m_last_mouse_move_left;
steady_clock::time_point m_last_mouse_move_right;
steady_clock::time_point m_last_mouse_move_up;
steady_clock::time_point m_last_mouse_move_down;
int m_deadzone_x = 60;
int m_deadzone_y = 60;
double m_multi_x = 2;
double m_multi_y = 2.5;
// Mousewheel
steady_clock::time_point m_last_wheel_move_up;
steady_clock::time_point m_last_wheel_move_down;
steady_clock::time_point m_last_wheel_move_left;
steady_clock::time_point m_last_wheel_move_right;
};

View file

@ -1,37 +0,0 @@
#ifdef WITH_DISCORD_RPC
#include "_discord_utils.h"
#include "discord_rpc.h"
#include <string>
#include <ctime>
namespace discord
{
void initialize(const std::string& application_id)
{
DiscordEventHandlers handlers = {};
Discord_Initialize(application_id.c_str(), &handlers, 1, nullptr);
}
void shutdown()
{
Discord_Shutdown();
}
void update_presence(const std::string& state, const std::string& details, bool reset_timer)
{
DiscordRichPresence discordPresence = {};
discordPresence.details = details.c_str();
discordPresence.state = state.c_str();
discordPresence.largeImageKey = "rpcs3_logo";
discordPresence.largeImageText = "RPCS3 is the world's first PlayStation 3 emulator.";
if (reset_timer)
{
discordPresence.startTimestamp = std::time(nullptr);
}
Discord_UpdatePresence(&discordPresence);
}
} // namespace discord
#endif

View file

@ -1,15 +0,0 @@
#pragma once
#include <string>
namespace discord
{
// Convenience function for initialization
void initialize(const std::string& application_id = "424004941485572097");
// Convenience function for shutdown
void shutdown();
// Convenience function for status updates. The default is set to idle.
void update_presence(const std::string& state = "", const std::string& details = "Idle", bool reset_timer = true);
} // namespace discord

View file

@ -1,56 +0,0 @@
#include "about_dialog.h"
#include "ui_about_dialog.h"
#include "rpcs3_version.h"
#include "qt_utils.h"
#include <QDesktopServices>
#include <QUrl>
#include <QSvgWidget>
about_dialog::about_dialog(QWidget* parent) : QDialog(parent), ui(new Ui::about_dialog)
{
ui->setupUi(this);
setAttribute(Qt::WA_DeleteOnClose);
ui->close->setDefault(true);
ui->icon->load(QStringLiteral(":/rpcs3.svg"));
ui->version->setText(tr("RPCS3 Version: %1").arg(QString::fromStdString(rpcs3::get_verbose_version())));
ui->description->setText(gui::utils::make_paragraph(tr(
"RPCS3 is an open-source Sony PlayStation 3 emulator and debugger.\n"
"It is written in C++ for Windows, Linux, FreeBSD and MacOS, funded with %0.\n"
"Our developers and contributors are always working hard to ensure this project is the best that it can be.\n"
"There are still plenty of implementations to make and optimizations to do.")
.arg(gui::utils::make_link(tr("Patreon"), "https://rpcs3.net/patreon"))));
// Events
connect(ui->gitHub, &QPushButton::clicked, []
{
QDesktopServices::openUrl(QUrl("https://www.github.com/RPCS3"));
});
connect(ui->website, &QPushButton::clicked, []
{
QDesktopServices::openUrl(QUrl("https://rpcs3.net"));
});
connect(ui->forum, &QPushButton::clicked, []
{
QDesktopServices::openUrl(QUrl("https://forums.rpcs3.net"));
});
connect(ui->patreon, &QPushButton::clicked, []
{
QDesktopServices::openUrl(QUrl("https://rpcs3.net/patreon"));
});
connect(ui->discord, &QPushButton::clicked, []
{
QDesktopServices::openUrl(QUrl("https://discord.me/RPCS3"));
});
connect(ui->wiki, &QPushButton::clicked, []
{
QDesktopServices::openUrl(QUrl("https://wiki.rpcs3.net/index.php?title=Main_Page"));
});
connect(ui->close, &QPushButton::clicked, this, &QWidget::close);
}
about_dialog::~about_dialog()
{
}

View file

@ -1,20 +0,0 @@
#pragma once
#include <QDialog>
namespace Ui
{
class about_dialog;
}
class about_dialog : public QDialog
{
Q_OBJECT
public:
explicit about_dialog(QWidget* parent = nullptr);
~about_dialog();
private:
std::unique_ptr<Ui::about_dialog> ui;
};

View file

@ -1,468 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>about_dialog</class>
<widget class="QDialog" name="about_dialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>805</width>
<height>555</height>
</rect>
</property>
<property name="windowTitle">
<string>About RPCS3</string>
</property>
<property name="windowIcon">
<iconset resource="../resources.qrc">
<normaloff>:/rpcs3.ico</normaloff>:/rpcs3.ico</iconset>
</property>
<layout class="QVBoxLayout" name="about_dialog_layout" stretch="0,1,0">
<property name="spacing">
<number>6</number>
</property>
<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>
<widget class="QWidget" name="header_section" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<layout class="QHBoxLayout" name="header_section_layout" stretch="0,1">
<item>
<widget class="QWidget" name="icon_widget" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Preferred">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<layout class="QVBoxLayout" name="icon_widget_layout">
<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>
<widget class="QSvgWidget" name="icon" native="true">
<property name="maximumSize">
<size>
<width>50</width>
<height>50</height>
</size>
</property>
</widget>
</item>
<item>
<spacer name="icon_spacer">
<property name="orientation">
<enum>Qt::Orientation::Vertical</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Policy::MinimumExpanding</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>0</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
</item>
<item>
<layout class="QVBoxLayout" name="text_layout">
<item>
<widget class="QLabel" name="title">
<property name="font">
<font>
<family>Arial</family>
<pointsize>14</pointsize>
<bold>false</bold>
</font>
</property>
<property name="text">
<string>RPCS3 PlayStation 3 Emulator</string>
</property>
<property name="alignment">
<set>Qt::AlignmentFlag::AlignLeading|Qt::AlignmentFlag::AlignLeft|Qt::AlignmentFlag::AlignTop</set>
</property>
<property name="textInteractionFlags">
<set>Qt::TextInteractionFlag::TextSelectableByMouse</set>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="description">
<property name="font">
<font>
<family>Arial</family>
<kerning>true</kerning>
</font>
</property>
<property name="textFormat">
<enum>Qt::TextFormat::RichText</enum>
</property>
<property name="alignment">
<set>Qt::AlignmentFlag::AlignLeading|Qt::AlignmentFlag::AlignLeft|Qt::AlignmentFlag::AlignTop</set>
</property>
<property name="wordWrap">
<bool>false</bool>
</property>
<property name="openExternalLinks">
<bool>true</bool>
</property>
<property name="textInteractionFlags">
<set>Qt::TextInteractionFlag::TextBrowserInteraction</set>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="version">
<property name="font">
<font>
<family>Arial</family>
<kerning>true</kerning>
</font>
</property>
<property name="text">
<string/>
</property>
<property name="textFormat">
<enum>Qt::TextFormat::RichText</enum>
</property>
<property name="alignment">
<set>Qt::AlignmentFlag::AlignLeading|Qt::AlignmentFlag::AlignLeft|Qt::AlignmentFlag::AlignTop</set>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
<property name="textInteractionFlags">
<set>Qt::TextInteractionFlag::TextBrowserInteraction</set>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QScrollArea" name="name_section">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>200</height>
</size>
</property>
<property name="frameShape">
<enum>QFrame::Shape::NoFrame</enum>
</property>
<property name="verticalScrollBarPolicy">
<enum>Qt::ScrollBarPolicy::ScrollBarAlwaysOn</enum>
</property>
<property name="sizeAdjustPolicy">
<enum>QAbstractScrollArea::SizeAdjustPolicy::AdjustToContents</enum>
</property>
<property name="widgetResizable">
<bool>true</bool>
</property>
<widget class="QWidget" name="names">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>793</width>
<height>2638</height>
</rect>
</property>
<layout class="QHBoxLayout" name="names_layout" stretch="1,1,1,1">
<property name="sizeConstraint">
<enum>QLayout::SizeConstraint::SetMinimumSize</enum>
</property>
<property name="leftMargin">
<number>24</number>
</property>
<item>
<layout class="QVBoxLayout" name="developerLayout" stretch="0,1">
<property name="spacing">
<number>10</number>
</property>
<item>
<widget class="QLabel" name="developersTitle">
<property name="font">
<font>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>Developers:</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="developers">
<property name="text">
<string notr="true">&lt;p&gt;¬DH&lt;br&gt;¬AlexAltea&lt;br&gt;¬Hykem&lt;br&gt;¬Oil&lt;br&gt;Nekotekina&lt;br&gt;¬Bigpet&lt;br&gt;¬gopalsr83&lt;br&gt;¬tambry&lt;br&gt;¬vlj&lt;br&gt;kd-11&lt;br&gt;¬jarveson&lt;br&gt;¬raven02&lt;br&gt;AniLeo&lt;br&gt;¬cornytrace&lt;br&gt;¬ssshadow&lt;br&gt;¬Numan&lt;br&gt;hcorion&lt;br&gt;Megamouse&lt;br&gt;¬flash-fire&lt;br&gt;DAGINATSUKO&lt;br&gt;GalCiv&lt;br&gt;eladash&lt;/p&gt;</string>
</property>
<property name="scaledContents">
<bool>false</bool>
</property>
<property name="alignment">
<set>Qt::AlignmentFlag::AlignLeading|Qt::AlignmentFlag::AlignLeft|Qt::AlignmentFlag::AlignTop</set>
</property>
<property name="textInteractionFlags">
<set>Qt::TextInteractionFlag::TextSelectableByMouse</set>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QVBoxLayout" name="contributorsLayout" stretch="0,1">
<property name="spacing">
<number>10</number>
</property>
<item>
<widget class="QLabel" name="contributorsTitle">
<property name="font">
<font>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>Contributors:</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="contributors">
<property name="text">
<string notr="true">&lt;p&gt;BlackDaemon&lt;br&gt;elisha464&lt;br&gt;Aishou&lt;br&gt;krofna&lt;br&gt;xsacha&lt;br&gt;danilaml&lt;br&gt;unknownbrackets&lt;br&gt;Zangetsu38&lt;br&gt;lioncash&lt;br&gt;achurch&lt;br&gt;darkf&lt;br&gt;Syphurith&lt;br&gt;Blaypeg&lt;br&gt;Survanium90&lt;br&gt;georgemoralis&lt;br&gt;ikki84&lt;br&gt;scribam&lt;br&gt;TGE&lt;br&gt;velocity&lt;br&gt;Farseer&lt;br&gt;Dangles&lt;br&gt;ruipin&lt;br&gt;jbeich&lt;br&gt;CookiePLMonster&lt;br&gt;Whatcookie&lt;br&gt;rajkosto&lt;br&gt;Admiral Thrawn&lt;br&gt;FlexBy&lt;br&gt;Dunastique&lt;br&gt;Jonathan44062&lt;br&gt;yurinator557&lt;br&gt;Satan&lt;br&gt;HoldTheMourning&lt;br&gt;illusion0001&lt;/p&gt;</string>
</property>
<property name="alignment">
<set>Qt::AlignmentFlag::AlignLeading|Qt::AlignmentFlag::AlignLeft|Qt::AlignmentFlag::AlignTop</set>
</property>
<property name="textInteractionFlags">
<set>Qt::TextInteractionFlag::TextSelectableByMouse</set>
</property>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QVBoxLayout" name="supportersLayout" stretch="0,1">
<property name="spacing">
<number>10</number>
</property>
<item>
<widget class="QLabel" name="supportersTitle">
<property name="font">
<font>
<bold>true</bold>
</font>
</property>
<property name="text">
<string>Supporters:</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="supporters">
<property name="text">
<string notr="true">&lt;p&gt;Howard Garrison&lt;br&gt;EXPotemkin&lt;br&gt;Marko V.&lt;br&gt;danhp&lt;br&gt;Jake (5315825)&lt;br&gt;Ian Reid&lt;br&gt;Tad Sherlock&lt;br&gt;Tyler Friesen&lt;br&gt;Folzar&lt;br&gt;Payton Williams&lt;br&gt;RedPill Australia&lt;br&gt;yanghong&lt;br&gt;Mohammed El-Serougi&lt;br&gt;Дима ~Ximer13~ Кулин&lt;br&gt;James Reed&lt;br&gt;BaroqueSonata&lt;br&gt;Bonzay0&lt;br&gt;Henrijs Kons&lt;br&gt;eoiz&lt;br&gt;Lena Stöffler&lt;br&gt;Michael Holder&lt;br&gt;Max Bosse&lt;br&gt;Tyler Whisinnand&lt;br&gt;Gato Harvey&lt;br&gt;cain4355&lt;br&gt;Thomas Peltier&lt;br&gt;Loli Co.&lt;br&gt;MapleLoonie&lt;br&gt;Travis McEwen&lt;br&gt;Scott Singratsomboune&lt;br&gt;T.E&lt;br&gt;Lukas Rieger&lt;br&gt;Dane Madsen&lt;br&gt;JMS&lt;br&gt;Jonatan R&lt;br&gt;Luke Johnson&lt;br&gt;Thomas Zaorski&lt;br&gt;MyOwnFan&lt;br&gt;Alexandros Mandravillis&lt;br&gt;Socker Bopper&lt;br&gt;Faris Leonhart&lt;br&gt;Fabien Net&lt;br&gt;Raves&lt;br&gt;Barrowsx&lt;br&gt;kilsuton&lt;br&gt;Max Mason&lt;br&gt;Ethan Condon&lt;br&gt;jfidone&lt;br&gt;iaDRM&lt;br&gt;Kazer2.0&lt;br&gt;Bryce Quintin&lt;br&gt;Yuri Kunde Schlesner&lt;br&gt;Abdulla Altayer&lt;br&gt;Nicolas Jallamion&lt;br&gt;Vorvek&lt;br&gt;Ian Faddis&lt;br&gt;Leon&lt;br&gt;Mohammad Taleb&lt;br&gt;Jokez&lt;br&gt;crashX&lt;br&gt;Raveskirza&lt;br&gt;Grant Deacon&lt;br&gt;michael&lt;br&gt;David Zech&lt;br&gt;Ben Manoochehri&lt;br&gt;Adnan Kovacevic&lt;br&gt;Mighty J&lt;br&gt;Sam Shan Jiang&lt;br&gt;TheAnig&lt;br&gt;Rodney Coleman&lt;br&gt;FiniteAce&lt;br&gt;Kian Soon Alex Chiam&lt;br&gt;yukkuri&lt;br&gt;Justin Chadwick&lt;br&gt;toxic Itzi&lt;br&gt;Templerror&lt;br&gt;Myles Wesley Carlson&lt;br&gt;Max Bosse&lt;br&gt;Ethan Clark&lt;br&gt;LupineDream&lt;br&gt;CheatCodesOfLife&lt;br&gt;Jan Zykmund&lt;br&gt;Francesco Cinquemani&lt;br&gt;Andylg&lt;br&gt;Julia H de Camargos&lt;br&gt;Suvodip Mitra&lt;br&gt;Goh&lt;br&gt;Dmitry&lt;br&gt;Steel Brain&lt;br&gt;VarieZ&lt;br&gt;William Swango&lt;br&gt;Matthew Messersmith&lt;br&gt;Duane Locsin&lt;br&gt;Shuddertrix&lt;br&gt;Loweys Litsman&lt;br&gt;Shuddertrix&lt;br&gt;Mason Ferrie&lt;br&gt;Richard Kaplan&lt;br&gt;Hugues Valois&lt;br&gt;richard(lath..ch@)&lt;br&gt;Johnathan (Virtuous John)&lt;br&gt;eoiz&lt;br&gt;Dany Huguenin&lt;br&gt;doobieashtray&lt;br&gt;dean(mag..94@)&lt;br&gt;Pommier Jean-Philippe&lt;br&gt;Douglas Alan Albino&lt;br&gt;Ryan Mull&lt;br&gt;Thor-Erling Engen&lt;br&gt;Nick Carpenter&lt;br&gt;curryking3&lt;br&gt;Jared Tracton&lt;br&gt;alex(koo..oh@)&lt;br&gt;Jason O'Brien&lt;br&gt;Skeletal Charizard&lt;br&gt;Ace00&lt;br&gt;Brandon Corujo&lt;br&gt;HyperBitHero&lt;br&gt;佳文 李&lt;br&gt;sorryboi
&lt;br&gt;Johnson Bui
&lt;br&gt;itachi1986
&lt;br&gt;Mortano
&lt;br&gt;Xythera
&lt;br&gt;Albert Quinteros
&lt;br&gt;Uzair Sheikh
&lt;br&gt;Ethan Hoppins
&lt;br&gt;optic
&lt;br&gt;Quill Slyver
&lt;br&gt;Averie
&lt;br&gt;StevenCarson
&lt;br&gt;YuriNator557
&lt;br&gt;Deanmaxx
&lt;br&gt;linkQatar G
&lt;br&gt;Jack Collie
&lt;br&gt;TAL BERKOVITZ
&lt;br&gt;cjtk
&lt;br&gt;Comexzone
&lt;br&gt;mapleglass
&lt;br&gt;Liquidbings
&lt;br&gt;Dormant_Hero@0230
&lt;br&gt;Theodore Raney
&lt;br&gt;Morito
&lt;br&gt;Chaining Ten
&lt;br&gt;Xeropel
&lt;br&gt;Marko Gatzouris
&lt;br&gt;Steven (...weller@gmail.com)
&lt;br&gt;Real Gamer
&lt;br&gt;Spencer Robinson
&lt;br&gt;naps
&lt;br&gt;Matthew Stevens
&lt;br&gt;Orion Clark
&lt;br&gt;William K. Leung
&lt;br&gt;Trent M
&lt;br&gt;Viktor Ni
&lt;br&gt;Marc Tönsing
&lt;br&gt;Amogus
&lt;br&gt;Scott Davis
&lt;br&gt;秉軒 侯
&lt;br&gt;Wiktor Tkaczyński
&lt;br&gt;Vekkar
&lt;br&gt;Jackson Abney
&lt;/p&gt;</string>
</property>
<property name="alignment">
<set>Qt::AlignmentFlag::AlignLeading|Qt::AlignmentFlag::AlignLeft|Qt::AlignmentFlag::AlignTop</set>
</property>
<property name="textInteractionFlags">
<set>Qt::TextInteractionFlag::TextSelectableByMouse</set>
</property>
</widget>
</item>
</layout>
</item>
<item>
<spacer name="names_spacer">
<property name="orientation">
<enum>Qt::Orientation::Horizontal</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Policy::MinimumExpanding</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>0</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</widget>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="button_section">
<property name="leftMargin">
<number>9</number>
</property>
<property name="topMargin">
<number>9</number>
</property>
<property name="rightMargin">
<number>9</number>
</property>
<property name="bottomMargin">
<number>9</number>
</property>
<item>
<widget class="QPushButton" name="gitHub">
<property name="text">
<string>GitHub</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="website">
<property name="text">
<string>Website</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="forum">
<property name="text">
<string>Forum</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="discord">
<property name="text">
<string>Discord</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="wiki">
<property name="text">
<string>Wiki</string>
</property>
</widget>
</item>
<item>
<widget class="QPushButton" name="patreon">
<property name="text">
<string>Patreon</string>
</property>
</widget>
</item>
<item>
<spacer name="button_spacer">
<property name="orientation">
<enum>Qt::Orientation::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="close">
<property name="text">
<string>Close</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>QSvgWidget</class>
<extends>QWidget</extends>
<header>qsvgwidget.h</header>
<container>1</container>
</customwidget>
</customwidgets>
<resources>
<include location="../resources.qrc"/>
</resources>
<connections/>
</ui>

View file

@ -1,299 +0,0 @@
#include "auto_pause_settings_dialog.h"
#include "table_item_delegate.h"
#include "Emu/System.h"
#include <QFontDatabase>
#include <QMenu>
#include <QMouseEvent>
#include <QVBoxLayout>
#include <QPushButton>
#include "util/logs.hpp"
#include "util/File.h"
LOG_CHANNEL(autopause_log, "AutoPause");
auto_pause_settings_dialog::auto_pause_settings_dialog(QWidget* parent) : QDialog(parent)
{
QLabel* description = new QLabel(tr("To use auto pause: enter the ID(s) of a function or a system call.\nRestart of the game is required to apply. You can enable/disable this in the settings."), this);
m_pause_list = new QTableWidget(this);
m_pause_list->setColumnCount(2);
m_pause_list->setHorizontalHeaderLabels(QStringList() << tr("Call ID") << tr("Type"));
// m_pause_list->horizontalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents);
m_pause_list->setSelectionBehavior(QAbstractItemView::SelectRows);
m_pause_list->setContextMenuPolicy(Qt::CustomContextMenu);
m_pause_list->setItemDelegate(new table_item_delegate(this));
m_pause_list->setShowGrid(false);
QPushButton* clearButton = new QPushButton(tr("Clear"), this);
QPushButton* reloadButton = new QPushButton(tr("Reload"), this);
QPushButton* saveButton = new QPushButton(tr("Save"), this);
QPushButton* cancelButton = new QPushButton(tr("Cancel"), this);
cancelButton->setDefault(true);
QHBoxLayout* buttonsLayout = new QHBoxLayout();
buttonsLayout->addWidget(clearButton);
buttonsLayout->addWidget(reloadButton);
buttonsLayout->addStretch();
buttonsLayout->addWidget(saveButton);
buttonsLayout->addWidget(cancelButton);
QVBoxLayout* mainLayout = new QVBoxLayout(this);
mainLayout->addWidget(description);
mainLayout->addWidget(m_pause_list);
mainLayout->addLayout(buttonsLayout);
setLayout(mainLayout);
setMinimumSize(QSize(400, 360));
setWindowTitle(tr("Auto Pause Manager"));
setObjectName("auto_pause_manager");
// Events
connect(m_pause_list, &QTableWidget::customContextMenuRequested, this, &auto_pause_settings_dialog::ShowContextMenu);
connect(clearButton, &QAbstractButton::clicked, [this]()
{
m_entries.clear();
UpdateList();
});
connect(reloadButton, &QAbstractButton::clicked, [this]()
{
LoadEntries();
UpdateList();
});
connect(saveButton, &QAbstractButton::clicked, [this]()
{
SaveEntries();
autopause_log.success("File pause.bin was updated.");
});
connect(cancelButton, &QAbstractButton::clicked, this, &QWidget::close);
Emu.GracefulShutdown(false);
LoadEntries();
UpdateList();
setFixedSize(sizeHint());
}
// Copied some from AutoPause.
void auto_pause_settings_dialog::LoadEntries()
{
m_entries.clear();
m_entries.reserve(16);
const fs::file list(fs::get_config_dir() + "pause.bin");
if (list)
{
// System calls ID and Function calls ID are all u32 iirc.
u32 num;
const usz fmax = list.size();
usz fcur = 0;
list.seek(0);
while (fcur <= fmax - sizeof(u32))
{
list.read(&num, sizeof(u32));
fcur += sizeof(u32);
if (num == 0xFFFFFFFF)
break;
m_entries.emplace_back(num);
}
}
}
// Copied some from AutoPause.
// Tip: This one doesn't check for the file is being read or not.
// This would always use a 0xFFFFFFFF as end of the pause.bin
void auto_pause_settings_dialog::SaveEntries()
{
fs::file list(fs::get_config_dir() + "pause.bin", fs::rewrite);
// System calls ID and Function calls ID are all u32 iirc.
u32 num = 0;
list.seek(0);
for (usz i = 0; i < m_entries.size(); ++i)
{
if (num == 0xFFFFFFFF)
continue;
num = m_entries[i];
list.write(&num, sizeof(u32));
}
num = 0xFFFFFFFF;
list.write(&num, sizeof(u32));
}
void auto_pause_settings_dialog::UpdateList()
{
const int entries_size = static_cast<int>(m_entries.size());
m_pause_list->clearContents();
m_pause_list->setRowCount(entries_size);
for (int i = 0; i < entries_size; ++i)
{
QTableWidgetItem* callItem = new QTableWidgetItem;
QTableWidgetItem* typeItem = new QTableWidgetItem;
callItem->setFlags(callItem->flags() & ~Qt::ItemIsEditable);
typeItem->setFlags(typeItem->flags() & ~Qt::ItemIsEditable);
if (m_entries[i] != 0xFFFFFFFF)
{
callItem->setData(Qt::DisplayRole, QString::fromStdString(fmt::format("%08x", m_entries[i])));
}
else
{
callItem->setData(Qt::DisplayRole, tr("Unset"));
}
if (m_entries[i] < 1024)
{
typeItem->setData(Qt::DisplayRole, tr("System Call"));
}
else
{
typeItem->setData(Qt::DisplayRole, tr("Function Call"));
}
m_pause_list->setItem(i, 0, callItem);
m_pause_list->setItem(i, 1, typeItem);
}
}
void auto_pause_settings_dialog::ShowContextMenu(const QPoint& pos)
{
const int row = m_pause_list->indexAt(pos).row();
QMenu myMenu;
// Make Actions
QAction* add = myMenu.addAction(tr("&Add"));
QAction* remove = myMenu.addAction(tr("&Remove"));
myMenu.addSeparator();
QAction* config = myMenu.addAction(tr("&Config"));
if (row == -1)
{
remove->setEnabled(false);
config->setEnabled(false);
}
auto OnEntryConfig = [this](int row, bool newEntry)
{
AutoPauseConfigDialog* config = new AutoPauseConfigDialog(this, this, newEntry, &m_entries[row]);
config->setModal(true);
config->exec();
UpdateList();
};
connect(add, &QAction::triggered, this, [=, this]()
{
m_entries.emplace_back(0xFFFFFFFF);
UpdateList();
const int idx = static_cast<int>(m_entries.size()) - 1;
m_pause_list->selectRow(idx);
OnEntryConfig(idx, true);
});
connect(remove, &QAction::triggered, this, &auto_pause_settings_dialog::OnRemove);
connect(config, &QAction::triggered, this, [=, this]()
{
OnEntryConfig(row, false);
});
myMenu.exec(m_pause_list->viewport()->mapToGlobal(pos));
}
void auto_pause_settings_dialog::OnRemove()
{
QModelIndexList selection = m_pause_list->selectionModel()->selectedRows();
std::sort(selection.begin(), selection.end());
for (int i = selection.count() - 1; i >= 0; i--)
{
m_entries.erase(m_entries.begin() + ::at32(selection, i).row());
}
UpdateList();
}
void auto_pause_settings_dialog::keyPressEvent(QKeyEvent* event)
{
if (event->isAutoRepeat())
{
return;
}
if (event->key() == Qt::Key_Delete)
{
OnRemove();
}
}
AutoPauseConfigDialog::AutoPauseConfigDialog(QWidget* parent, auto_pause_settings_dialog* apsd, bool newEntry, u32* entry)
: QDialog(parent), m_presult(entry), m_newEntry(newEntry), m_apsd(apsd)
{
m_entry = *m_presult;
setMinimumSize(QSize(300, -1));
QPushButton* button_ok = new QPushButton(tr("&Ok"), this);
QPushButton* button_cancel = new QPushButton(tr("&Cancel"), this);
button_ok->setFixedWidth(50);
button_cancel->setFixedWidth(50);
QLabel* description = new QLabel(tr("Specify ID of System Call or Function Call below. You need to use a Hexadecimal ID."), this);
description->setWordWrap(true);
m_current_converted = new QLabel(tr("Currently it gets an id of \"Unset\"."), this);
m_current_converted->setWordWrap(true);
m_id = new QLineEdit(this);
m_id->setText(QString::fromStdString(fmt::format("%08x", m_entry)));
m_id->setPlaceholderText("ffffffff");
m_id->setFont(QFontDatabase::systemFont(QFontDatabase::FixedFont));
m_id->setMaxLength(8);
m_id->setFixedWidth(65);
setWindowTitle("Auto Pause Setting: " + m_id->text());
connect(button_cancel, &QAbstractButton::clicked, this, &AutoPauseConfigDialog::OnCancel);
connect(button_ok, &QAbstractButton::clicked, this, &AutoPauseConfigDialog::OnOk);
connect(m_id, &QLineEdit::textChanged, this, &AutoPauseConfigDialog::OnUpdateValue);
QHBoxLayout* configHBox = new QHBoxLayout();
configHBox->addWidget(m_id);
configHBox->addWidget(button_ok);
configHBox->addWidget(button_cancel);
configHBox->setAlignment(Qt::AlignCenter);
QVBoxLayout* mainLayout = new QVBoxLayout(this);
mainLayout->addWidget(description);
mainLayout->addLayout(configHBox);
mainLayout->addWidget(m_current_converted);
setLayout(mainLayout);
setFixedSize(QSize(300, sizeHint().height()));
OnUpdateValue();
}
void AutoPauseConfigDialog::OnOk()
{
bool ok;
const ullong value = m_id->text().toULongLong(&ok, 16);
m_entry = value;
*m_presult = m_entry;
accept();
}
void AutoPauseConfigDialog::OnCancel()
{
if (m_newEntry)
{
m_apsd->OnRemove();
}
close();
}
void AutoPauseConfigDialog::OnUpdateValue() const
{
bool ok;
const ullong value = m_id->text().toULongLong(&ok, 16);
const bool is_ok = ok && value <= u32{umax};
m_current_converted->setText(tr("Current value: %1 (%2)").arg(value, 8, 16).arg(is_ok ? tr("OK") : tr("Conversion failed")));
}

View file

@ -1,56 +0,0 @@
#pragma once
#include "util/types.hpp"
#include <QDialog>
#include <QLabel>
#include <QTableWidget>
#include <QLineEdit>
#include <vector>
class auto_pause_settings_dialog : public QDialog
{
Q_OBJECT
enum
{
id_add,
id_remove,
id_config,
};
std::vector<u32> m_entries;
QTableWidget* m_pause_list;
public:
explicit auto_pause_settings_dialog(QWidget* parent);
void UpdateList();
void LoadEntries();
void SaveEntries();
public Q_SLOTS:
void OnRemove();
private Q_SLOTS:
void ShowContextMenu(const QPoint& pos);
void keyPressEvent(QKeyEvent* event) override;
};
class AutoPauseConfigDialog : public QDialog
{
Q_OBJECT
u32 m_entry;
u32* m_presult;
bool m_newEntry;
QLineEdit* m_id;
QLabel* m_current_converted;
auto_pause_settings_dialog* m_apsd;
public:
explicit AutoPauseConfigDialog(QWidget* parent, auto_pause_settings_dialog* apsd, bool newEntry, u32* entry);
private Q_SLOTS:
void OnOk();
void OnCancel();
void OnUpdateValue() const;
};

View file

@ -1,298 +0,0 @@
#include "stdafx.h"
#include "basic_mouse_settings_dialog.h"
#include "localized_emu.h"
#include "Input/basic_mouse_handler.h"
#include "Input/keyboard_pad_handler.h"
#include "Emu/Io/mouse_config.h"
#include "util/asm.hpp"
#include <QGroupBox>
#include <QMessageBox>
#include <QVBoxLayout>
LOG_CHANNEL(cfg_log, "CFG");
enum button_role
{
button_name = Qt::UserRole,
button_code
};
basic_mouse_settings_dialog::basic_mouse_settings_dialog(QWidget* parent)
: QDialog(parent)
{
setObjectName("basic_mouse_settings_dialog");
setWindowTitle(tr("Configure Basic Mouse Handler"));
setAttribute(Qt::WA_DeleteOnClose);
setAttribute(Qt::WA_StyledBackground);
setModal(true);
QVBoxLayout* v_layout = new QVBoxLayout(this);
m_button_box = new QDialogButtonBox(this);
m_button_box->setStandardButtons(QDialogButtonBox::Apply | QDialogButtonBox::Cancel | QDialogButtonBox::Save | QDialogButtonBox::RestoreDefaults);
connect(m_button_box, &QDialogButtonBox::clicked, this, [this](QAbstractButton* button)
{
if (button == m_button_box->button(QDialogButtonBox::Apply))
{
g_cfg_mouse.save();
}
else if (button == m_button_box->button(QDialogButtonBox::Save))
{
g_cfg_mouse.save();
accept();
}
else if (button == m_button_box->button(QDialogButtonBox::RestoreDefaults))
{
if (QMessageBox::question(this, tr("Confirm Reset"), tr("Reset all settings?")) != QMessageBox::Yes)
return;
reset_config();
}
else if (button == m_button_box->button(QDialogButtonBox::Cancel))
{
// Restore config
if (!g_cfg_mouse.load())
{
cfg_log.notice("Could not restore mouse config. Using defaults.");
}
reject();
}
});
if (!g_cfg_mouse.load())
{
cfg_log.notice("Could not load basic mouse config. Using defaults.");
}
m_buttons = new QButtonGroup(this);
connect(m_buttons, &QButtonGroup::idClicked, this, &basic_mouse_settings_dialog::on_button_click);
connect(&m_remap_timer, &QTimer::timeout, this, [this]()
{
auto button = m_buttons->button(m_button_id);
if (--m_seconds <= 0)
{
if (button)
{
if (const int button_id = m_buttons->id(button))
{
const std::string name = g_cfg_mouse.get_button(button_id).to_string();
button->setText(name.empty() ? QStringLiteral("-") : QString::fromStdString(name));
}
}
reactivate_buttons();
return;
}
if (button)
{
button->setText(tr("[ Waiting %1 ]").arg(m_seconds));
}
});
const auto insert_button = [this](int id, QPushButton* button)
{
m_buttons->addButton(button, id);
button->installEventFilter(this);
};
constexpr u32 button_count = 8;
constexpr u32 max_items_per_column = 4;
int rows = button_count;
for (u32 cols = 1; utils::aligned_div(button_count, cols) > max_items_per_column;)
{
rows = utils::aligned_div(button_count, ++cols);
}
QWidget* widget = new QWidget(this);
QGridLayout* grid_layout = new QGridLayout(this);
for (int i = 0, row = 0, col = 0; i < static_cast<int>(button_count); i++, row++)
{
const int cell_code = get_mouse_button_code(i);
const QString translated_cell_button = localized_emu::translated_mouse_button(cell_code);
QHBoxLayout* h_layout = new QHBoxLayout(this);
QGroupBox* gb = new QGroupBox(translated_cell_button, this);
QPushButton* pb = new QPushButton(this);
insert_button(cell_code, pb);
const std::string saved_btn = g_cfg_mouse.get_button(cell_code);
pb->setText(saved_btn.empty() ? QStringLiteral("-") : QString::fromStdString(saved_btn));
if (row >= rows)
{
row = 0;
col++;
}
m_push_buttons[cell_code] = pb;
h_layout->addWidget(pb);
gb->setLayout(h_layout);
grid_layout->addWidget(gb, row, col);
}
widget->setLayout(grid_layout);
v_layout->addWidget(widget);
v_layout->addWidget(m_button_box);
setLayout(v_layout);
m_palette = m_push_buttons[CELL_MOUSE_BUTTON_1]->palette(); // save normal palette
}
void basic_mouse_settings_dialog::reset_config()
{
g_cfg_mouse.from_default();
for (auto& [cell_code, pb] : m_push_buttons)
{
if (!pb)
continue;
const QString text = QString::fromStdString(g_cfg_mouse.get_button(cell_code).def);
pb->setText(text.isEmpty() ? QStringLiteral("-") : text);
}
}
void basic_mouse_settings_dialog::on_button_click(int id)
{
if (id < 0)
{
return;
}
for (auto but : m_buttons->buttons())
{
but->setEnabled(false);
but->setFocusPolicy(Qt::ClickFocus);
}
m_button_box->setEnabled(false);
for (auto but : m_button_box->buttons())
{
but->setFocusPolicy(Qt::ClickFocus);
}
m_button_id = id;
if (auto button = m_buttons->button(m_button_id))
{
button->setText(tr("[ Waiting %1 ]").arg(MAX_SECONDS));
button->setPalette(QPalette(Qt::blue));
button->grabMouse();
}
m_remap_timer.start(1000);
}
void basic_mouse_settings_dialog::keyPressEvent(QKeyEvent* event)
{
if (m_button_id < 0)
{
// We are not remapping a button, so pass the event to the base class.
QDialog::keyPressEvent(event);
return;
}
const std::string name = keyboard_pad_handler::GetKeyName(event, false);
g_cfg_mouse.get_button(m_button_id).from_string(name);
if (auto button = m_buttons->button(m_button_id))
{
button->setText(QString::fromStdString(name));
}
reactivate_buttons();
}
void basic_mouse_settings_dialog::mouseReleaseEvent(QMouseEvent* event)
{
if (m_button_id < 0)
{
// We are not remapping a button, so pass the event to the base class.
QDialog::mouseReleaseEvent(event);
return;
}
const std::string name = keyboard_pad_handler::GetMouseName(event);
g_cfg_mouse.get_button(m_button_id).from_string(name);
if (auto button = m_buttons->button(m_button_id))
{
button->setText(QString::fromStdString(name));
}
reactivate_buttons();
}
bool basic_mouse_settings_dialog::eventFilter(QObject* object, QEvent* event)
{
switch (event->type())
{
case QEvent::MouseButtonRelease:
{
// On right click clear binding if we are not remapping pad button
if (m_button_id < 0)
{
QMouseEvent* mouse_event = static_cast<QMouseEvent*>(event);
if (const auto button = qobject_cast<QPushButton*>(object); button && button->isEnabled() && mouse_event->button() == Qt::RightButton)
{
if (const int button_id = m_buttons->id(button))
{
button->setText(QStringLiteral("-"));
g_cfg_mouse.get_button(button_id).from_string("");
return true;
}
}
}
// Disabled buttons should not absorb mouseclicks
event->ignore();
break;
}
default:
{
break;
}
}
return QDialog::eventFilter(object, event);
}
void basic_mouse_settings_dialog::reactivate_buttons()
{
m_remap_timer.stop();
m_seconds = MAX_SECONDS;
if (m_button_id < 0)
{
return;
}
if (auto button = m_buttons->button(m_button_id))
{
button->setPalette(m_palette);
button->releaseMouse();
}
m_button_id = -1;
// Enable all buttons
m_button_box->setEnabled(true);
for (auto but : m_button_box->buttons())
{
but->setFocusPolicy(Qt::StrongFocus);
}
for (auto but : m_buttons->buttons())
{
but->setEnabled(true);
but->setFocusPolicy(Qt::StrongFocus);
}
}

View file

@ -1,43 +0,0 @@
#pragma once
#include <QButtonGroup>
#include <QPushButton>
#include <QDialog>
#include <QDialogButtonBox>
#include <QMouseEvent>
#include <QTimer>
#include <unordered_map>
class basic_mouse_settings_dialog : public QDialog
{
Q_OBJECT
public:
basic_mouse_settings_dialog(QWidget* parent = nullptr);
private:
void reset_config();
void on_button_click(int id);
void reactivate_buttons();
// Buttons
QDialogButtonBox* m_button_box = nullptr;
QButtonGroup* m_buttons = nullptr;
std::unordered_map<int, QPushButton*> m_push_buttons;
int m_button_id = -1;
// Backup for standard button palette
QPalette m_palette;
// Remap Timer
static constexpr int MAX_SECONDS = 5;
int m_seconds = MAX_SECONDS;
QTimer m_remap_timer;
protected:
void keyPressEvent(QKeyEvent* event) override;
void mouseReleaseEvent(QMouseEvent* event) override;
bool eventFilter(QObject* object, QEvent* event) override;
};

View file

@ -1,54 +0,0 @@
#include "breakpoint_handler.h"
extern bool ppu_breakpoint(u32 loc, bool is_adding);
bool breakpoint_handler::IsBreakOnBPM() const
{
return m_break_on_bpm;
}
void breakpoint_handler::SetBreakOnBPM(bool break_on_bpm)
{
m_break_on_bpm = break_on_bpm;
}
bool breakpoint_handler::HasBreakpoint(u32 loc, bs_t<breakpoint_types> type)
{
std::lock_guard lock(mutex_breakpoints);
return m_breakpoints.contains(loc) && ((m_breakpoints.at(loc) & type) == type);
}
bool breakpoint_handler::AddBreakpoint(u32 loc, bs_t<breakpoint_types> type)
{
std::lock_guard lock(mutex_breakpoints);
if ((type & breakpoint_types::bp_exec) && !ppu_breakpoint(loc, true))
{
return false;
}
return m_breakpoints.insert({loc, type}).second;
}
bool breakpoint_handler::RemoveBreakpoint(u32 loc)
{
std::lock_guard lock(mutex_breakpoints);
bs_t<breakpoint_types> bp_type{};
if (m_breakpoints.contains(loc))
{
bp_type = m_breakpoints.at(loc);
}
if (m_breakpoints.erase(loc) == 0)
{
return false;
}
if (bp_type & breakpoint_types::bp_exec)
{
ensure(ppu_breakpoint(loc, false));
}
return true;
}

View file

@ -1,53 +0,0 @@
#pragma once
#include "util/types.hpp"
#include "util/bit_set.h"
#include <map>
#include "util/mutex.h"
enum class breakpoint_types
{
bp_read = 0x1,
bp_write = 0x2,
bp_exec = 0x4,
__bitset_enum_max
};
/*
* This class acts as a layer between the UI and Emu for breakpoints.
*/
class breakpoint_handler
{
public:
breakpoint_handler() = default;
~breakpoint_handler() = default;
bool IsBreakOnBPM() const;
void SetBreakOnBPM(bool break_on_bpm);
/**
* Returns true iff breakpoint exists at loc.
* TODO: Add arg for flags, gameid, and maybe even thread if it should be thread local breakpoint.... breakpoint struct is probably what'll happen
*/
bool HasBreakpoint(u32 loc, bs_t<breakpoint_types> type);
/**
* Returns true if added successfully. TODO: flags
*/
bool AddBreakpoint(u32 loc, bs_t<breakpoint_types> type);
/**
* Returns true if removed breakpoint at loc successfully.
*/
bool RemoveBreakpoint(u32 loc);
private:
// TODO : generalize to hold multiple games and handle flags.Probably do : std::map<std::string (gameid), std::set<breakpoint>>.
// Although, externally, they'll only be accessed by loc (I think) so a map of maps may also do?
shared_mutex mutex_breakpoints;
std::map<u32, bs_t<breakpoint_types>> m_breakpoints; //! Holds all breakpoints.
bool m_break_on_bpm = false;
};
extern breakpoint_handler g_breakpoint_handler;

View file

@ -1,287 +0,0 @@
#include "breakpoint_list.h"
#include "breakpoint_handler.h"
#include "Emu/CPU/CPUDisAsm.h"
#include "Emu/Cell/PPUThread.h"
#include "Emu/Cell/SPUThread.h"
#include "debugger_add_bp_window.h"
#include <QMenu>
#include <QMessageBox>
#include <QMouseEvent>
extern bool is_using_interpreter(thread_class t_class);
breakpoint_list::breakpoint_list(QWidget* parent, breakpoint_handler* handler) : QListWidget(parent), m_ppu_breakpoint_handler(handler)
{
setEditTriggers(QAbstractItemView::NoEditTriggers);
setContextMenuPolicy(Qt::CustomContextMenu);
setSelectionMode(QAbstractItemView::ExtendedSelection);
connect(this, &QListWidget::itemDoubleClicked, this, &breakpoint_list::OnBreakpointListDoubleClicked);
connect(this, &QListWidget::customContextMenuRequested, this, &breakpoint_list::OnBreakpointListRightClicked);
m_delete_action = new QAction(tr("&Delete"), this);
m_delete_action->setShortcut(Qt::Key_Delete);
m_delete_action->setShortcutContext(Qt::WidgetShortcut);
connect(m_delete_action, &QAction::triggered, this, &breakpoint_list::OnBreakpointListDelete);
addAction(m_delete_action);
// Hide until used in order to allow as much space for registers panel as possible
hide();
}
/**
* It's unfortunate I need a method like this to sync these. Should ponder a cleaner way to do this.
*/
void breakpoint_list::UpdateCPUData(std::shared_ptr<CPUDisAsm> disasm)
{
m_disasm = std::move(disasm);
}
void breakpoint_list::ClearBreakpoints()
{
while (count())
{
auto* currentItem = takeItem(0);
const u32 loc = currentItem->data(Qt::UserRole).value<u32>();
m_ppu_breakpoint_handler->RemoveBreakpoint(loc);
delete currentItem;
}
hide();
}
void breakpoint_list::RemoveBreakpoint(u32 addr)
{
m_ppu_breakpoint_handler->RemoveBreakpoint(addr);
for (int i = 0; i < count(); i++)
{
QListWidgetItem* currentItem = item(i);
if (currentItem->data(Qt::UserRole).value<u32>() == addr)
{
delete takeItem(i);
break;
}
}
if (!count())
{
hide();
}
}
bool breakpoint_list::AddBreakpoint(u32 pc, bs_t<breakpoint_types> type)
{
if (!m_ppu_breakpoint_handler->AddBreakpoint(pc, type))
{
return false;
}
QString breakpoint_item_text;
if (type == breakpoint_types::bp_exec)
{
m_disasm->disasm(m_disasm->dump_pc = pc);
breakpoint_item_text = QString::fromStdString(m_disasm->last_opcode);
breakpoint_item_text.remove(10, 13);
}
else if (type == breakpoint_types::bp_read)
{
breakpoint_item_text = QString("BPMR: 0x%1").arg(pc, 8, 16, QChar('0'));
}
else if (type == breakpoint_types::bp_write)
{
breakpoint_item_text = QString("BPMW: 0x%1").arg(pc, 8, 16, QChar('0'));
}
else if (type == (breakpoint_types::bp_read + breakpoint_types::bp_write))
{
breakpoint_item_text = QString("BPMRW: 0x%1").arg(pc, 8, 16, QChar('0'));
}
QListWidgetItem* breakpoint_item = new QListWidgetItem(breakpoint_item_text);
breakpoint_item->setForeground(m_text_color_bp);
breakpoint_item->setBackground(m_color_bp);
breakpoint_item->setData(Qt::UserRole, pc);
addItem(breakpoint_item);
show();
return true;
}
/**
* If breakpoint exists, we remove it, else add new one. Yeah, it'd be nicer from a code logic to have it be set/reset. But, that logic has to happen somewhere anyhow.
*/
void breakpoint_list::HandleBreakpointRequest(u32 loc, bool only_add)
{
const auto cpu = m_disasm ? m_disasm->get_cpu() : nullptr;
if (!cpu || cpu->state & cpu_flag::exit)
{
return;
}
if (!is_using_interpreter(cpu->get_class()))
{
QMessageBox::warning(this, tr("Interpreters-Only Feature!"), tr("Cannot set breakpoints on non-interpreter decoders."));
return;
}
switch (cpu->get_class())
{
case thread_class::spu:
{
if (loc >= SPU_LS_SIZE || loc % 4)
{
QMessageBox::warning(this, tr("Invalid Memory For Breakpoints!"), tr("Cannot set breakpoints on non-SPU executable memory!"));
return;
}
const auto spu = static_cast<spu_thread*>(cpu);
auto& list = spu->local_breakpoints;
const u32 pos_at = loc / 4;
const u32 pos_bit = 1u << (pos_at % 8);
if (list[pos_at / 8].fetch_xor(pos_bit) & pos_bit)
{
if (std::none_of(list.begin(), list.end(), [](auto& val)
{
return val.load();
}))
{
spu->has_active_local_bps = false;
}
}
else
{
if (!spu->has_active_local_bps.exchange(true))
{
spu->state.atomic_op([](bs_t<cpu_flag>& flags)
{
if (flags & cpu_flag::pending)
{
flags += cpu_flag::pending_recheck;
}
else
{
flags += cpu_flag::pending;
}
});
}
}
return;
}
case thread_class::ppu:
break;
default:
QMessageBox::warning(this, tr("Unimplemented Breakpoints For Thread Type!"), tr("Cannot set breakpoints on a thread not an PPU/SPU currently, sorry."));
return;
}
if (!vm::check_addr(loc, vm::page_executable))
{
QMessageBox::warning(this, tr("Invalid Memory For Breakpoints!"), tr("Cannot set breakpoints on non-executable memory!"));
return;
}
if (m_ppu_breakpoint_handler->HasBreakpoint(loc, breakpoint_types::bp_exec))
{
if (!only_add)
{
RemoveBreakpoint(loc);
}
}
else
{
if (!AddBreakpoint(loc, breakpoint_types::bp_exec))
{
QMessageBox::warning(this, tr("Unknown error while setting breakpoint!"), tr("Failed to set breakpoints."));
return;
}
}
}
void breakpoint_list::OnBreakpointListDoubleClicked()
{
if (QListWidgetItem* item = currentItem())
{
const u32 address = item->data(Qt::UserRole).value<u32>();
Q_EMIT RequestShowAddress(address);
}
}
void breakpoint_list::OnBreakpointListRightClicked(const QPoint& pos)
{
m_context_menu = new QMenu();
if (selectedItems().count() == 1)
{
QAction* rename_action = m_context_menu->addAction(tr("&Rename"));
connect(rename_action, &QAction::triggered, this, [this]()
{
QListWidgetItem* current_item = selectedItems().first();
current_item->setFlags(current_item->flags() | Qt::ItemIsEditable);
editItem(current_item);
});
m_context_menu->addSeparator();
}
if (selectedItems().count() >= 1)
{
m_context_menu->addAction(m_delete_action);
}
QAction* m_addbp = new QAction(tr("Add Breakpoint"), this);
connect(m_addbp, &QAction::triggered, this, [this]
{
debugger_add_bp_window dlg(this, this);
dlg.exec();
});
m_context_menu->addAction(m_addbp);
#ifdef RPCS3_HAS_MEMORY_BREAKPOINTS
QAction* m_tglbpmbreak = new QAction(m_ppu_breakpoint_handler->IsBreakOnBPM() ? tr("Disable BPM") : tr("Enable BPM"), this);
connect(m_tglbpmbreak, &QAction::triggered, [this]
{
m_ppu_breakpoint_handler->SetBreakOnBPM(!m_ppu_breakpoint_handler->IsBreakOnBPM());
});
m_context_menu->addAction(m_tglbpmbreak);
#endif
m_context_menu->exec(viewport()->mapToGlobal(pos));
m_context_menu->deleteLater();
m_context_menu = nullptr;
}
void breakpoint_list::OnBreakpointListDelete()
{
for (int i = selectedItems().count() - 1; i >= 0; i--)
{
RemoveBreakpoint(::at32(selectedItems(), i)->data(Qt::UserRole).value<u32>());
}
if (m_context_menu)
{
m_context_menu->close();
}
}
void breakpoint_list::mouseDoubleClickEvent(QMouseEvent* ev)
{
if (!ev)
return;
// Qt's itemDoubleClicked signal doesn't distinguish between mouse buttons and there is no simple way to get the pressed button.
// So we have to ignore this event when another button is pressed.
if (ev->button() != Qt::LeftButton)
{
ev->ignore();
return;
}
QListWidget::mouseDoubleClickEvent(ev);
}

View file

@ -1,44 +0,0 @@
#pragma once
#include "util/types.hpp"
#include <QListWidget>
#include "breakpoint_handler.h"
class CPUDisAsm;
class cpu_thread;
class breakpoint_list : public QListWidget
{
Q_OBJECT
public:
breakpoint_list(QWidget* parent, breakpoint_handler* handler);
void UpdateCPUData(std::shared_ptr<CPUDisAsm> disasm);
void ClearBreakpoints();
void RemoveBreakpoint(u32 addr);
bool AddBreakpoint(u32 pc, bs_t<breakpoint_types> type);
QColor m_text_color_bp;
QColor m_color_bp;
protected:
void mouseDoubleClickEvent(QMouseEvent* ev) override;
Q_SIGNALS:
void RequestShowAddress(u32 addr, bool select_addr = true, bool force = false);
public Q_SLOTS:
void HandleBreakpointRequest(u32 loc, bool add_only);
private Q_SLOTS:
void OnBreakpointListDoubleClicked();
void OnBreakpointListRightClicked(const QPoint& pos);
void OnBreakpointListDelete();
private:
breakpoint_handler* m_ppu_breakpoint_handler = nullptr;
QMenu* m_context_menu = nullptr;
QAction* m_delete_action;
std::shared_ptr<CPUDisAsm> m_disasm = nullptr;
};

View file

@ -1,70 +0,0 @@
#include "call_stack_list.h"
#include "util/StrFmt.h"
#include <QKeyEvent>
#include <QMouseEvent>
call_stack_list::call_stack_list(QWidget* parent) : QListWidget(parent)
{
setEditTriggers(QAbstractItemView::NoEditTriggers);
setContextMenuPolicy(Qt::CustomContextMenu);
setSelectionMode(QAbstractItemView::ExtendedSelection);
// connects
connect(this, &QListWidget::itemDoubleClicked, this, &call_stack_list::ShowItemAddress);
// Hide until used in order to allow as much space for registers panel as possible
hide();
}
void call_stack_list::keyPressEvent(QKeyEvent* event)
{
QListWidget::keyPressEvent(event);
event->ignore(); // Propagate the event to debugger_frame
if (!event->modifiers() && event->key() == Qt::Key_Return)
{
ShowItemAddress();
}
}
void call_stack_list::HandleUpdate(const std::vector<std::pair<u32, u32>>& call_stack)
{
clear();
for (const auto& addr : call_stack)
{
const QString text = QString::fromStdString(fmt::format("0x%08llx (sp=0x%08llx)", addr.first, addr.second));
QListWidgetItem* call_stack_item = new QListWidgetItem(text);
call_stack_item->setData(Qt::UserRole, {addr.first});
addItem(call_stack_item);
}
setVisible(!call_stack.empty());
}
void call_stack_list::ShowItemAddress()
{
if (QListWidgetItem* call_stack_item = currentItem())
{
const u32 address = call_stack_item->data(Qt::UserRole).value<u32>();
Q_EMIT RequestShowAddress(address);
}
}
void call_stack_list::mouseDoubleClickEvent(QMouseEvent* ev)
{
if (!ev)
return;
// Qt's itemDoubleClicked signal doesn't distinguish between mouse buttons and there is no simple way to get the pressed button.
// So we have to ignore this event when another button is pressed.
if (ev->button() != Qt::LeftButton)
{
ev->ignore();
return;
}
QListWidget::mouseDoubleClickEvent(ev);
}

View file

@ -1,31 +0,0 @@
#pragma once
#include "util/types.hpp"
#include <QListWidget>
#include <vector>
class cpu_thread;
class CPUDisAsm;
class call_stack_list : public QListWidget
{
Q_OBJECT
public:
explicit call_stack_list(QWidget* parent);
protected:
void mouseDoubleClickEvent(QMouseEvent* ev) override;
Q_SIGNALS:
void RequestShowAddress(u32 addr, bool select_addr = true, bool force = false);
public Q_SLOTS:
void HandleUpdate(const std::vector<std::pair<u32, u32>>& call_stack);
private Q_SLOTS:
void ShowItemAddress();
private:
void keyPressEvent(QKeyEvent* event) override;
};

View file

@ -1,284 +0,0 @@
#include "stdafx.h"
#include "camera_settings_dialog.h"
#include "ui_camera_settings_dialog.h"
#include "permissions.h"
#include "Emu/Io/camera_config.h"
#include <QCameraDevice>
#include <QMediaDevices>
#include <QMessageBox>
#include <QPushButton>
LOG_CHANNEL(camera_log, "Camera");
template <>
void fmt_class_string<QVideoFrameFormat::PixelFormat>::format(std::string& out, u64 arg)
{
format_enum(out, arg, [](QVideoFrameFormat::PixelFormat value)
{
switch (value)
{
case QVideoFrameFormat::Format_ARGB8888: return "ARGB8888";
case QVideoFrameFormat::Format_ARGB8888_Premultiplied: return "ARGB8888_Premultiplied";
case QVideoFrameFormat::Format_XRGB8888: return "XRGB8888";
case QVideoFrameFormat::Format_BGRA8888: return "BGRA8888";
case QVideoFrameFormat::Format_BGRA8888_Premultiplied: return "BGRA8888_Premultiplied";
case QVideoFrameFormat::Format_BGRX8888: return "BGRX8888";
case QVideoFrameFormat::Format_ABGR8888: return "ABGR8888";
case QVideoFrameFormat::Format_XBGR8888: return "XBGR8888";
case QVideoFrameFormat::Format_RGBA8888: return "RGBA8888";
case QVideoFrameFormat::Format_RGBX8888: return "RGBX8888";
case QVideoFrameFormat::Format_AYUV: return "AYUV";
case QVideoFrameFormat::Format_AYUV_Premultiplied: return "AYUV_Premultiplied";
case QVideoFrameFormat::Format_YUV420P: return "YUV420P";
case QVideoFrameFormat::Format_YUV422P: return "YUV422P";
case QVideoFrameFormat::Format_YV12: return "YV12";
case QVideoFrameFormat::Format_UYVY: return "UYVY";
case QVideoFrameFormat::Format_YUYV: return "YUYV";
case QVideoFrameFormat::Format_NV12: return "NV12";
case QVideoFrameFormat::Format_NV21: return "NV21";
case QVideoFrameFormat::Format_IMC1: return "IMC1";
case QVideoFrameFormat::Format_IMC2: return "IMC2";
case QVideoFrameFormat::Format_IMC3: return "IMC3";
case QVideoFrameFormat::Format_IMC4: return "IMC4";
case QVideoFrameFormat::Format_Y8: return "Y8";
case QVideoFrameFormat::Format_Y16: return "Y16";
case QVideoFrameFormat::Format_P010: return "P010";
case QVideoFrameFormat::Format_P016: return "P016";
case QVideoFrameFormat::Format_SamplerExternalOES: return "SamplerExternalOES";
case QVideoFrameFormat::Format_Jpeg: return "Jpeg";
case QVideoFrameFormat::Format_SamplerRect: return "SamplerRect";
default: return unknown;
}
});
}
Q_DECLARE_METATYPE(QCameraDevice);
camera_settings_dialog::camera_settings_dialog(QWidget* parent)
: QDialog(parent), ui(new Ui::camera_settings_dialog)
{
ui->setupUi(this);
load_config();
for (const QCameraDevice& camera_info : QMediaDevices::videoInputs())
{
if (camera_info.isNull())
continue;
ui->combo_camera->addItem(camera_info.description(), QVariant::fromValue(camera_info));
camera_log.notice("Found camera: '%s'", camera_info.description());
}
connect(ui->combo_camera, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &camera_settings_dialog::handle_camera_change);
connect(ui->combo_settings, QOverload<int>::of(&QComboBox::currentIndexChanged), this, &camera_settings_dialog::handle_settings_change);
connect(ui->buttonBox, &QDialogButtonBox::clicked, [this](QAbstractButton* button)
{
if (button == ui->buttonBox->button(QDialogButtonBox::Save))
{
save_config();
accept();
}
else if (button == ui->buttonBox->button(QDialogButtonBox::Apply))
{
save_config();
}
});
if (ui->combo_camera->count() == 0)
{
ui->combo_camera->setEnabled(false);
ui->combo_settings->setEnabled(false);
ui->buttonBox->button(QDialogButtonBox::Save)->setEnabled(false);
ui->buttonBox->button(QDialogButtonBox::Apply)->setEnabled(false);
}
else
{
// TODO: show camera ID somewhere
ui->combo_camera->setCurrentIndex(0);
}
}
camera_settings_dialog::~camera_settings_dialog()
{
}
void camera_settings_dialog::handle_camera_change(int index)
{
if (index < 0 || !ui->combo_camera->itemData(index).canConvert<QCameraDevice>())
{
ui->combo_settings->clear();
return;
}
const QCameraDevice camera_info = ui->combo_camera->itemData(index).value<QCameraDevice>();
if (camera_info.isNull())
{
ui->combo_settings->clear();
return;
}
m_camera.reset(new QCamera(camera_info));
m_media_capture_session.reset(new QMediaCaptureSession(nullptr));
m_media_capture_session->setCamera(m_camera.get());
m_media_capture_session->setVideoSink(ui->videoWidget->videoSink());
if (!m_camera->isAvailable())
{
ui->combo_settings->clear();
QMessageBox::warning(this, tr("Camera not available"), tr("The selected camera is not available.\nIt might be blocked by another application."));
return;
}
ui->combo_settings->blockSignals(true);
ui->combo_settings->clear();
QList<QCameraFormat> settings = camera_info.videoFormats();
std::sort(settings.begin(), settings.end(), [](const QCameraFormat& l, const QCameraFormat& r) -> bool
{
if (l.resolution().width() > r.resolution().width())
return true;
if (l.resolution().width() < r.resolution().width())
return false;
if (l.resolution().height() > r.resolution().height())
return true;
if (l.resolution().height() < r.resolution().height())
return false;
if (l.minFrameRate() > r.minFrameRate())
return true;
if (l.minFrameRate() < r.minFrameRate())
return false;
if (l.maxFrameRate() > r.maxFrameRate())
return true;
if (l.maxFrameRate() < r.maxFrameRate())
return false;
if (l.pixelFormat() > r.pixelFormat())
return true;
if (l.pixelFormat() < r.pixelFormat())
return false;
return false;
});
for (const QCameraFormat& setting : settings)
{
if (setting.isNull())
continue;
const QString description = tr("%0x%1, %2-%3 FPS, Format=%4")
.arg(setting.resolution().width())
.arg(setting.resolution().height())
.arg(setting.minFrameRate())
.arg(setting.maxFrameRate())
.arg(QString::fromStdString(fmt::format("%s", setting.pixelFormat())));
ui->combo_settings->addItem(description, QVariant::fromValue(setting));
}
ui->combo_settings->blockSignals(false);
if (ui->combo_settings->count() == 0)
{
ui->combo_settings->setEnabled(false);
}
else
{
// Load selected settings from config file
int index = 0;
bool success = false;
const std::string key = camera_info.id().toStdString();
cfg_camera::camera_setting cfg_setting = g_cfg_camera.get_camera_setting(key, success);
if (success)
{
camera_log.notice("Found config entry for camera \"%s\"", key);
// Select matching drowdown entry
const double epsilon = 0.001;
for (int i = 0; i < ui->combo_settings->count(); i++)
{
const QCameraFormat tmp = ui->combo_settings->itemData(i).value<QCameraFormat>();
if (tmp.resolution().width() == cfg_setting.width &&
tmp.resolution().height() == cfg_setting.height &&
tmp.minFrameRate() >= (cfg_setting.min_fps - epsilon) &&
tmp.minFrameRate() <= (cfg_setting.min_fps + epsilon) &&
tmp.maxFrameRate() >= (cfg_setting.max_fps - epsilon) &&
tmp.maxFrameRate() <= (cfg_setting.max_fps + epsilon) &&
tmp.pixelFormat() == static_cast<QVideoFrameFormat::PixelFormat>(cfg_setting.format))
{
index = i;
break;
}
}
}
ui->combo_settings->setCurrentIndex(std::max<int>(0, index));
ui->combo_settings->setEnabled(true);
// Update config to match user interface outcome
const QCameraFormat setting = ui->combo_settings->currentData().value<QCameraFormat>();
cfg_setting.width = setting.resolution().width();
cfg_setting.height = setting.resolution().height();
cfg_setting.min_fps = setting.minFrameRate();
cfg_setting.max_fps = setting.maxFrameRate();
cfg_setting.format = static_cast<int>(setting.pixelFormat());
g_cfg_camera.set_camera_setting(key, cfg_setting);
}
}
void camera_settings_dialog::handle_settings_change(int index)
{
if (!m_camera)
{
return;
}
if (!m_camera->isAvailable())
{
QMessageBox::warning(this, tr("Camera not available"), tr("The selected camera is not available.\nIt might be blocked by another application."));
return;
}
if (!gui::utils::check_camera_permission(this, [this, index]()
{
handle_settings_change(index);
},
[this]()
{
QMessageBox::warning(this, tr("Camera permissions denied!"), tr("RPCS3 has no permissions to access cameras on this device."));
}))
{
return;
}
if (index >= 0 && ui->combo_settings->itemData(index).canConvert<QCameraFormat>() && ui->combo_camera->currentData().canConvert<QCameraDevice>())
{
const QCameraFormat setting = ui->combo_settings->itemData(index).value<QCameraFormat>();
if (!setting.isNull())
{
m_camera->setCameraFormat(setting);
}
cfg_camera::camera_setting cfg_setting;
cfg_setting.width = setting.resolution().width();
cfg_setting.height = setting.resolution().height();
cfg_setting.min_fps = setting.minFrameRate();
cfg_setting.max_fps = setting.maxFrameRate();
cfg_setting.format = static_cast<int>(setting.pixelFormat());
g_cfg_camera.set_camera_setting(ui->combo_camera->currentData().value<QCameraDevice>().id().toStdString(), cfg_setting);
}
m_camera->start();
}
void camera_settings_dialog::load_config()
{
if (!g_cfg_camera.load())
{
camera_log.notice("Could not load camera config. Using defaults.");
}
}
void camera_settings_dialog::save_config()
{
g_cfg_camera.save();
}

View file

@ -1,31 +0,0 @@
#pragma once
#include <QCamera>
#include <QDialog>
#include <QMediaCaptureSession>
namespace Ui
{
class camera_settings_dialog;
}
class camera_settings_dialog : public QDialog
{
Q_OBJECT
public:
camera_settings_dialog(QWidget* parent = nullptr);
virtual ~camera_settings_dialog();
private Q_SLOTS:
void handle_camera_change(int index);
void handle_settings_change(int index);
private:
void load_config();
void save_config();
std::unique_ptr<Ui::camera_settings_dialog> ui;
std::unique_ptr<QCamera> m_camera;
std::unique_ptr<QMediaCaptureSession> m_media_capture_session;
};

View file

@ -1,130 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>camera_settings_dialog</class>
<widget class="QDialog" name="camera_settings_dialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>356</width>
<height>380</height>
</rect>
</property>
<property name="windowTitle">
<string>Camera Settings</string>
</property>
<layout class="QVBoxLayout" name="mainLayout" stretch="0,1,0">
<item>
<layout class="QHBoxLayout" name="settingsLayout" stretch="1,2">
<item>
<widget class="QGroupBox" name="gbCamera">
<property name="title">
<string>Camera</string>
</property>
<layout class="QVBoxLayout" name="camera_layout">
<item>
<widget class="QComboBox" name="combo_camera">
<property name="placeholderText">
<string>No cameras found</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="gbSettings">
<property name="title">
<string>Settings</string>
</property>
<layout class="QVBoxLayout" name="settings_layout">
<item>
<widget class="QComboBox" name="combo_settings">
<property name="placeholderText">
<string>No settings found</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QGroupBox" name="gbPreview">
<property name="title">
<string>Preview</string>
</property>
<layout class="QVBoxLayout" name="preview_layout">
<item>
<widget class="QVideoWidget" name="videoWidget" native="true">
<property name="minimumSize">
<size>
<width>64</width>
<height>48</height>
</size>
</property>
<property name="autoFillBackground">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Apply|QDialogButtonBox::Cancel|QDialogButtonBox::Save</set>
</property>
</widget>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>QVideoWidget</class>
<extends>QWidget</extends>
<header>qvideowidget.h</header>
<container>1</container>
</customwidget>
</customwidgets>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>camera_settings_dialog</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>248</x>
<y>254</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>camera_settings_dialog</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>316</x>
<y>260</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>

View file

@ -1,56 +0,0 @@
#pragma once
#include <QString>
#include <QStringList>
enum Category
{
Disc_Game,
HDD_Game,
PS1_Game,
PS2_Game,
PSP_Game,
Home,
Media,
Data,
OS,
Unknown_Cat,
Others,
};
namespace cat
{
const QString cat_app_music = "AM";
const QString cat_app_photo = "AP";
const QString cat_app_store = "AS";
const QString cat_app_tv = "AT";
const QString cat_app_video = "AV";
const QString cat_bc_video = "BV";
const QString cat_web_tv = "WT";
const QString cat_home = "HM";
const QString cat_network = "CB";
const QString cat_store_fe = "SF";
const QString cat_disc_game = "DG";
const QString cat_hdd_game = "HG";
const QString cat_ps2_game = "2P";
const QString cat_ps2_inst = "2G";
const QString cat_ps1_game = "1P";
const QString cat_psp_game = "PP";
const QString cat_psp_mini = "MN";
const QString cat_psp_rema = "PE";
const QString cat_ps3_data = "GD";
const QString cat_ps2_data = "2D";
const QString cat_ps3_save = "SD";
const QString cat_psp_save = "MS";
const QString cat_ps3_os = "/OS";
const QString cat_unknown = "Unknown";
const QStringList ps2_games = {cat_ps2_game, cat_ps2_inst};
const QStringList psp_games = {cat_psp_game, cat_psp_mini, cat_psp_rema};
const QStringList media = {cat_app_photo, cat_app_video, cat_bc_video, cat_app_music, cat_app_store, cat_app_tv, cat_web_tv};
const QStringList data = {cat_ps3_data, cat_ps2_data, cat_ps3_save, cat_psp_save};
const QStringList os = {cat_ps3_os};
const QStringList others = {cat_network, cat_store_fe};
} // namespace cat

View file

@ -1,172 +0,0 @@
#include "cg_disasm_window.h"
#include "gui_settings.h"
#include "syntax_highlighter.h"
#include <QSplitter>
#include <QMenu>
#include <QFileDialog>
#include <QHBoxLayout>
#include <QFontDatabase>
#include <QMimeData>
#include "Emu/RSX/Program/CgBinaryProgram.h"
LOG_CHANNEL(gui_log, "GUI");
cg_disasm_window::cg_disasm_window(std::shared_ptr<gui_settings> gui_settings)
: m_gui_settings(std::move(gui_settings))
{
setWindowTitle(tr("Cg Disasm"));
setObjectName("cg_disasm");
setAttribute(Qt::WA_DeleteOnClose);
setAttribute(Qt::WA_StyledBackground);
setAcceptDrops(true);
setMinimumSize(QSize(200, 150)); // seems fine on win 10
resize(QSize(620, 395));
m_path_last = m_gui_settings->GetValue(gui::fd_cg_disasm).toString();
m_disasm_text = new QTextEdit(this);
m_disasm_text->setReadOnly(true);
m_disasm_text->setWordWrapMode(QTextOption::NoWrap);
m_disasm_text->setFont(QFontDatabase::systemFont(QFontDatabase::FixedFont));
m_glsl_text = new QTextEdit(this);
m_glsl_text->setReadOnly(true);
m_glsl_text->setWordWrapMode(QTextOption::NoWrap);
m_glsl_text->setFont(QFontDatabase::systemFont(QFontDatabase::FixedFont));
// m_disasm_text syntax highlighter
sh_asm = new AsmHighlighter(m_disasm_text->document());
// m_glsl_text syntax highlighter
sh_glsl = new GlslHighlighter(m_glsl_text->document());
QSplitter* splitter = new QSplitter();
splitter->addWidget(m_disasm_text);
splitter->addWidget(m_glsl_text);
QHBoxLayout* layout = new QHBoxLayout();
layout->addWidget(splitter);
setLayout(layout);
m_disasm_text->setContextMenuPolicy(Qt::CustomContextMenu);
m_glsl_text->setContextMenuPolicy(Qt::CustomContextMenu);
connect(m_disasm_text, &QWidget::customContextMenuRequested, this, &cg_disasm_window::ShowContextMenu);
connect(m_glsl_text, &QWidget::customContextMenuRequested, this, &cg_disasm_window::ShowContextMenu);
ShowDisasm();
}
void cg_disasm_window::ShowContextMenu(const QPoint& pos)
{
QMenu menu;
QAction* clear = new QAction(tr("&Clear"));
QAction* open = new QAction(tr("Open &Cg binary program"));
menu.addAction(open);
menu.addSeparator();
menu.addAction(clear);
connect(clear, &QAction::triggered, [this]()
{
m_disasm_text->clear();
m_glsl_text->clear();
});
connect(open, &QAction::triggered, [this]()
{
const QString file_path = QFileDialog::getOpenFileName(this, tr("Select Cg program object"), m_path_last, tr("Cg program objects (*.fpo;*.vpo);;"));
if (file_path.isEmpty())
return;
m_path_last = file_path;
ShowDisasm();
});
const auto obj = qobject_cast<QTextEdit*>(sender());
QPoint origin;
if (obj == m_disasm_text)
{
origin = m_disasm_text->viewport()->mapToGlobal(pos);
}
else if (obj == m_glsl_text)
{
origin = m_glsl_text->viewport()->mapToGlobal(pos);
}
else
{
origin = mapToGlobal(pos);
}
menu.exec(origin);
}
void cg_disasm_window::ShowDisasm() const
{
if (QFileInfo(m_path_last).isFile())
{
CgBinaryDisasm disasm(m_path_last.toStdString());
disasm.BuildShaderBody();
m_disasm_text->setText(QString::fromStdString(disasm.GetArbShader()));
m_glsl_text->setText(QString::fromStdString(disasm.GetGlslShader()));
m_gui_settings->SetValue(gui::fd_cg_disasm, m_path_last);
}
else if (!m_path_last.isEmpty())
{
gui_log.error("CgDisasm: Failed to open %s", m_path_last);
}
}
bool cg_disasm_window::IsValidFile(const QMimeData& md, bool save)
{
const QList<QUrl> urls = md.urls();
if (urls.count() > 1)
{
return false;
}
const QString suff = QFileInfo(urls[0].fileName()).suffix().toLower();
if (suff == "fpo" || suff == "vpo")
{
if (save)
{
m_path_last = urls[0].toLocalFile();
}
return true;
}
return false;
}
void cg_disasm_window::dropEvent(QDropEvent* ev)
{
if (IsValidFile(*ev->mimeData(), true))
{
ShowDisasm();
}
}
void cg_disasm_window::dragEnterEvent(QDragEnterEvent* ev)
{
if (IsValidFile(*ev->mimeData()))
{
ev->accept();
}
}
void cg_disasm_window::dragMoveEvent(QDragMoveEvent* ev)
{
if (IsValidFile(*ev->mimeData()))
{
ev->accept();
}
}
void cg_disasm_window::dragLeaveEvent(QDragLeaveEvent* ev)
{
ev->accept();
}

View file

@ -1,40 +0,0 @@
#pragma once
#include <QTextEdit>
#include <QDropEvent>
#include <memory>
class AsmHighlighter;
class GlslHighlighter;
class gui_settings;
class cg_disasm_window : public QWidget
{
Q_OBJECT
private Q_SLOTS:
void ShowContextMenu(const QPoint& pos);
private:
void ShowDisasm() const;
bool IsValidFile(const QMimeData& md, bool save = false);
QString m_path_last;
QTextEdit* m_disasm_text;
QTextEdit* m_glsl_text;
std::shared_ptr<gui_settings> m_gui_settings;
AsmHighlighter* sh_asm;
GlslHighlighter* sh_glsl;
public:
explicit cg_disasm_window(std::shared_ptr<gui_settings> xSettings);
protected:
void dropEvent(QDropEvent* ev) override;
void dragEnterEvent(QDragEnterEvent* ev) override;
void dragMoveEvent(QDragMoveEvent* ev) override;
void dragLeaveEvent(QDragLeaveEvent* ev) override;
};

File diff suppressed because it is too large Load diff

View file

@ -1,96 +0,0 @@
#pragma once
#include "util/types.hpp"
#include <QDialog>
#include <QTableWidget>
#include <QListWidget>
#include <QLineEdit>
#include <QComboBox>
#include <QPushButton>
#include <string>
#include <vector>
#include <map>
#include "util/cheat_info.h"
class cheat_engine
{
public:
cheat_engine();
bool exist(const std::string& game, const u32 offset) const;
void add(const std::string& game, const std::string& description, const cheat_type type, const u32 offset, const std::string& red_script);
cheat_info* get(const std::string& game, const u32 offset);
bool erase(const std::string& game, const u32 offset);
void import_cheats_from_str(const std::string& str_cheats);
std::string export_cheats_to_str() const;
void save() const;
// Static functions to find/get/set values in ps3 memory
static bool resolve_script(u32& final_offset, const u32 offset, const std::string& red_script);
template <typename T>
static std::vector<u32> search(const T value, const std::vector<u32>& to_filter);
template <typename T>
static T get_value(const u32 offset, bool& success);
template <typename T>
static bool set_value(const u32 offset, const T value);
static bool is_addr_safe(const u32 offset);
static u32 reverse_lookup(const u32 addr, const u32 max_offset, const u32 max_depth, const u32 cur_depth = 0);
std::map<std::string, std::map<u32, cheat_info>> cheats;
private:
const std::string m_cheats_filename = "cheats.yml";
};
class cheat_manager_dialog : public QDialog
{
Q_OBJECT
public:
cheat_manager_dialog(QWidget* parent = nullptr);
~cheat_manager_dialog();
static cheat_manager_dialog* get_dlg(QWidget* parent = nullptr);
cheat_manager_dialog(cheat_manager_dialog const&) = delete;
void operator=(cheat_manager_dialog const&) = delete;
protected:
void update_cheat_list();
void do_the_search();
template <typename T>
T convert_from_QString(const QString& str, bool& success);
template <typename T>
bool convert_and_search();
template <typename T>
std::pair<bool, bool> convert_and_set(u32 offset);
protected:
QTableWidget* tbl_cheats = nullptr;
QListWidget* lst_search = nullptr;
QLineEdit* edt_value_final = nullptr;
QPushButton* btn_apply = nullptr;
QLineEdit* edt_cheat_search_value = nullptr;
QComboBox* cbx_cheat_search_type = nullptr;
QPushButton* btn_filter_results = nullptr;
u32 current_offset{};
std::vector<u32> offsets_found;
cheat_engine g_cheat;
private:
static cheat_manager_dialog* inst;
QString get_localized_cheat_type(cheat_type type);
};

View file

@ -1,71 +0,0 @@
#include "config_adapter.h"
#include "Emu/system_config.h"
LOG_CHANNEL(cfg_log, "CFG");
// Helper methods to interact with YAML and the config settings.
namespace cfg_adapter
{
static cfg::_base& get_cfg(const cfg::_base& root, const std::string& name)
{
if (root.get_type() == cfg::type::node)
{
for (const auto& node : static_cast<const cfg::node&>(root).get_nodes())
{
if (node->get_name() == name)
{
return *node;
}
}
}
fmt::throw_exception("Node not found: %s", name);
}
static cfg::_base& get_cfg(cfg::_base& root, const cfg_location::const_iterator begin, const cfg_location::const_iterator end)
{
return begin == end ? root : get_cfg(get_cfg(root, *begin), begin + 1, end);
}
YAML::Node get_node(const YAML::Node& node, const cfg_location::const_iterator begin, const cfg_location::const_iterator end)
{
if (begin == end)
{
return node;
}
if (!node || !node.IsMap())
{
cfg_log.fatal("Node error. A cfg_location does not match its cfg::node (location: %s)", get_yaml_node_location(node));
return YAML::Node();
}
return get_node(node[*begin], begin + 1, end); // TODO
}
YAML::Node get_node(const YAML::Node& node, const cfg_location& location)
{
return get_node(node, location.cbegin(), location.cend());
}
std::vector<std::string> get_options(const cfg_location& location)
{
return cfg_adapter::get_cfg(g_cfg, location.cbegin(), location.cend()).to_list();
}
static bool get_is_dynamic(const cfg_location& location)
{
return cfg_adapter::get_cfg(g_cfg, location.cbegin(), location.cend()).get_is_dynamic();
}
bool get_is_dynamic(emu_settings_type type)
{
return get_is_dynamic(::at32(settings_location, type));
}
std::string get_setting_name(emu_settings_type type)
{
const cfg_location& loc = ::at32(settings_location, type);
return ::at32(loc, loc.size() - 1);
}
} // namespace cfg_adapter

View file

@ -1,22 +0,0 @@
#pragma once
#include "emu_settings_type.h"
#include "util/yaml.hpp"
// Helper methods to interact with YAML and the config settings.
namespace cfg_adapter
{
YAML::Node get_node(const YAML::Node& node, const cfg_location::const_iterator begin, const cfg_location::const_iterator end);
/** Syntactic sugar to get a setting at a given config location. */
YAML::Node get_node(const YAML::Node& node, const cfg_location& location);
/** Returns possible options for values for some particular setting.*/
std::vector<std::string> get_options(const cfg_location& location);
/** Returns dynamic property for some particular setting.*/
bool get_is_dynamic(emu_settings_type type);
/** Returns the string for a given setting.*/
std::string get_setting_name(emu_settings_type type);
} // namespace cfg_adapter

View file

@ -1,214 +0,0 @@
#include "stdafx.h"
#include "config_checker.h"
#include "Emu/system_config.h"
#include <QDialog>
#include <QDialogButtonBox>
#include <QMessageBox>
#include <QTextEdit>
#include <QVBoxLayout>
#include <QLabel>
LOG_CHANNEL(gui_log, "GUI");
config_checker::config_checker(QWidget* parent, const QString& content, bool is_log) : QDialog(parent)
{
setObjectName("config_checker");
setAttribute(Qt::WA_DeleteOnClose);
QVBoxLayout* layout = new QVBoxLayout();
QLabel* label = new QLabel(this);
layout->addWidget(label);
QString result;
if (check_config(content, result, is_log))
{
setWindowTitle(tr("Interesting!"));
if (result.isEmpty())
{
label->setText(tr("Found config.\nIt seems to match the default config."));
}
else
{
label->setText(tr("Found config.\nSome settings seem to deviate from the default config:"));
QTextEdit* text_box = new QTextEdit();
text_box->setReadOnly(true);
text_box->setHtml(result);
layout->addWidget(text_box);
resize(400, 600);
}
}
else
{
setWindowTitle(tr("Ooops!"));
label->setText(result);
}
QDialogButtonBox* box = new QDialogButtonBox(QDialogButtonBox::Close);
connect(box, &QDialogButtonBox::rejected, this, &QDialog::reject);
layout->addWidget(box);
setLayout(layout);
}
bool config_checker::check_config(QString content, QString& result, bool is_log)
{
cfg_root config{};
if (is_log)
{
const QString start_token = "SYS: Used configuration:\n";
const QString end_token = "\n·";
qsizetype start = content.indexOf(start_token);
qsizetype end = -1;
if (start >= 0)
{
start += start_token.size();
end = content.indexOf(end_token, start);
}
if (end < 0)
{
result = tr("Cannot find any config!");
return false;
}
content = content.mid(start, end - start);
}
if (!config.from_string(content.toStdString()))
{
gui_log.error("log_viewer: Failed to parse config:\n%s", content);
result = tr("Cannot find any config!");
return false;
}
std::function<void(const cfg::_base*, std::string&, int)> print_diff_recursive;
print_diff_recursive = [&print_diff_recursive](const cfg::_base* base, std::string& diff, int indentation) -> void
{
if (!base)
{
return;
}
const auto indent = [](std::string& str, int indentation)
{
for (int i = 0; i < indentation * 2; i++)
{
str += "&nbsp;";
}
};
switch (base->get_type())
{
case cfg::type::node:
{
if (const auto& node = static_cast<const cfg::node*>(base))
{
std::string diff_tmp;
for (const auto& n : node->get_nodes())
{
print_diff_recursive(n, diff_tmp, indentation + 1);
}
if (!diff_tmp.empty())
{
indent(diff, indentation);
if (!base->get_name().empty())
{
fmt::append(diff, "<b>%s:</b><br>", base->get_name());
}
fmt::append(diff, "%s", diff_tmp);
}
}
break;
}
case cfg::type::_bool:
case cfg::type::_enum:
case cfg::type::_int:
case cfg::type::uint:
case cfg::type::string:
{
const std::string val = base->to_string();
const std::string def = base->def_to_string();
if (val != def)
{
indent(diff, indentation);
if (def.empty())
{
fmt::append(diff, "%s: <span style=\"color:red;\">%s</span><br>", base->get_name(), val);
}
else
{
fmt::append(diff, "%s: <span style=\"color:red;\">%s</span> <span style=\"color:gray;\">default:</span> <span style=\"color:green;\">%s</span><br>", base->get_name(), val, def);
}
}
break;
}
case cfg::type::set:
{
if (const auto& node = static_cast<const cfg::set_entry*>(base))
{
const std::vector<std::string> set_entries = node->to_list();
if (!set_entries.empty())
{
indent(diff, indentation);
fmt::append(diff, "<b>%s:</b><br>", base->get_name());
for (const std::string& entry : set_entries)
{
indent(diff, indentation + 1);
fmt::append(diff, "- <span style=\"color:red;\">%s</span><br>", entry);
}
}
}
break;
}
case cfg::type::log:
{
if (const auto& node = static_cast<const cfg::log_entry*>(base))
{
const auto& log_entries = node->get_map();
if (!log_entries.empty())
{
indent(diff, indentation);
fmt::append(diff, "<b>%s:</b><br>", base->get_name());
for (const auto& entry : log_entries)
{
indent(diff, indentation + 1);
fmt::append(diff, "<span style=\"color:red;\">%s: %s</span><br>", entry.first, entry.second);
}
}
}
break;
}
case cfg::type::map:
case cfg::type::node_map:
case cfg::type::device:
{
// Ignored
break;
}
}
};
std::string diff;
print_diff_recursive(&config, diff, 0);
result = QString::fromStdString(diff);
return true;
}

View file

@ -1,13 +0,0 @@
#pragma once
#include <QDialog>
class config_checker : public QDialog
{
Q_OBJECT
public:
config_checker(QWidget* parent, const QString& path, bool is_log);
bool check_config(QString content, QString& result, bool is_log);
};

View file

@ -1,85 +0,0 @@
#include "stdafx.h"
#include "curl_handle.h"
#include "util/logs.hpp"
#ifdef _WIN32
#include "util/StrUtil.h"
#endif
LOG_CHANNEL(network_log, "NET");
namespace rpcs3::curl
{
curl_handle::curl_handle()
{
reset_error_buffer();
m_curl = curl_easy_init();
CURLcode err = curl_easy_setopt(m_curl, CURLOPT_ERRORBUFFER, m_error_buffer.data());
if (err != CURLE_OK)
network_log.error("curl_easy_setopt(CURLOPT_ERRORBUFFER): %s", curl_easy_strerror(err));
m_uses_error_buffer = err == CURLE_OK;
err = curl_easy_setopt(m_curl, CURLOPT_VERBOSE, g_curl_verbose);
if (err != CURLE_OK)
network_log.error("curl_easy_setopt(CURLOPT_VERBOSE, %d): %s", g_curl_verbose, curl_easy_strerror(err));
#ifdef _WIN32
// Tell curl to use the native CA store for certificate verification
err = curl_easy_setopt(m_curl, CURLOPT_SSL_OPTIONS, CURLSSLOPT_NATIVE_CA);
if (err != CURLE_OK)
network_log.error("curl_easy_setopt(CURLOPT_SSL_OPTIONS): %s", curl_easy_strerror(err));
#endif
}
curl_handle::~curl_handle()
{
curl_easy_cleanup(m_curl);
}
CURL* curl_handle::get_curl() const
{
return m_curl;
}
void curl_handle::reset_error_buffer()
{
ensure(m_error_buffer.size() == CURL_ERROR_SIZE);
m_error_buffer[0] = 0;
}
std::string curl_handle::get_verbose_error(CURLcode code) const
{
if (m_uses_error_buffer)
{
ensure(m_error_buffer.size() == CURL_ERROR_SIZE);
if (m_error_buffer[0])
{
return fmt::format("Curl error (%d): %s\nDetails: %s", static_cast<int>(code), curl_easy_strerror(code), m_error_buffer.data());
}
}
return fmt::format("Curl error (%d): %s", static_cast<int>(code), curl_easy_strerror(code));
}
} // namespace rpcs3::curl
#ifdef _WIN32
// Functions exported from our user_settings.h in WolfSSL, implemented in RPCS3
extern "C"
{
FILE* wolfSSL_fopen_utf8(const char* name, const char* mode)
{
return _wfopen(utf8_to_wchar(name).c_str(), utf8_to_wchar(mode).c_str());
}
int wolfSSL_stat_utf8(const char* path, struct _stat* buffer)
{
return _wstat(utf8_to_wchar(path).c_str(), buffer);
}
}
#endif

View file

@ -1,36 +0,0 @@
#pragma once
#include <array>
#ifndef CURL_STATICLIB
#define CURL_STATICLIB
#endif
#include <curl/curl.h>
namespace rpcs3::curl
{
inline bool g_curl_verbose = false;
class curl_handle
{
public:
explicit curl_handle();
~curl_handle();
CURL* get_curl() const;
operator CURL*() const
{
return get_curl();
}
void reset_error_buffer();
std::string get_verbose_error(CURLcode code) const;
private:
CURL* m_curl = nullptr;
bool m_uses_error_buffer = false;
std::array<char, CURL_ERROR_SIZE> m_error_buffer;
};
} // namespace rpcs3::curl

View file

@ -1,36 +0,0 @@
#include "custom_dialog.h"
custom_dialog::custom_dialog(bool disableCancel, QWidget* parent)
: QDialog(parent), m_disable_cancel(disableCancel)
{
if (m_disable_cancel)
{
setWindowFlags(windowFlags() & ~Qt::WindowCloseButtonHint);
}
}
void custom_dialog::keyPressEvent(QKeyEvent* event)
{
// this won't work with Alt+F4, the window still closes
if (m_disable_cancel && event->key() == Qt::Key_Escape)
{
event->ignore();
}
else
{
QDialog::keyPressEvent(event);
}
}
void custom_dialog::closeEvent(QCloseEvent* event)
{
// spontaneous: don't close on external system level events like Alt+F4
if (m_disable_cancel && event->spontaneous())
{
event->ignore();
}
else
{
QDialog::closeEvent(event);
}
}

View file

@ -1,17 +0,0 @@
#pragma once
#include <QDialog>
#include <QKeyEvent>
class custom_dialog : public QDialog
{
Q_OBJECT
public:
explicit custom_dialog(bool disableCancel, QWidget* parent = nullptr);
bool m_disable_cancel;
private:
void keyPressEvent(QKeyEvent* event) override;
void closeEvent(QCloseEvent* event) override;
};

View file

@ -1,67 +0,0 @@
#pragma once
#include <QDockWidget>
#include <QStyleOption>
#include <QPainter>
class custom_dock_widget : public QDockWidget
{
private:
std::shared_ptr<QWidget> m_title_bar_widget;
bool m_is_title_bar_visible = true;
public:
explicit custom_dock_widget(const QString& title, QWidget* parent = Q_NULLPTR, Qt::WindowFlags flags = Qt::WindowFlags())
: QDockWidget(title, parent, flags)
{
m_title_bar_widget.reset(titleBarWidget());
connect(this, &QDockWidget::topLevelChanged, [this](bool /* topLevel*/)
{
SetTitleBarVisible(m_is_title_bar_visible);
style()->unpolish(this);
style()->polish(this);
});
}
void SetTitleBarVisible(bool visible)
{
if (visible || isFloating())
{
if (m_title_bar_widget.get() != titleBarWidget())
{
setTitleBarWidget(m_title_bar_widget.get());
QMargins margins = widget()->contentsMargins();
margins.setTop(0);
widget()->setContentsMargins(margins);
}
}
else
{
setTitleBarWidget(new QWidget());
QMargins margins = widget()->contentsMargins();
margins.setTop(1);
widget()->setContentsMargins(margins);
}
m_is_title_bar_visible = visible;
}
protected:
void paintEvent(QPaintEvent* event) override
{
// We need to repaint the dock widgets as plain widgets in floating mode.
// Source: https://stackoverflow.com/questions/10272091/cannot-add-a-background-image-to-a-qdockwidget
if (isFloating())
{
QStyleOption opt;
opt.initFrom(this);
QPainter p(this);
style()->drawPrimitive(QStyle::PE_Widget, &opt, &p, this);
return;
}
// Use inherited method for docked mode because otherwise the dock would lose the title etc.
QDockWidget::paintEvent(event);
}
};

View file

@ -1,72 +0,0 @@
#include "custom_table_widget_item.h"
#include "util/StrFmt.h"
#include <QDateTime>
custom_table_widget_item::custom_table_widget_item(const std::string& text, int sort_role, const QVariant& sort_value)
: movie_item(QString::fromStdString(text).simplified()) // simplified() forces single line text
{
if (sort_role != Qt::DisplayRole)
{
setData(sort_role, sort_value, true);
}
}
custom_table_widget_item::custom_table_widget_item(const QString& text, int sort_role, const QVariant& sort_value)
: movie_item(text.simplified()) // simplified() forces single line text
{
if (sort_role != Qt::DisplayRole)
{
setData(sort_role, sort_value, true);
}
}
bool custom_table_widget_item::operator<(const QTableWidgetItem& other) const
{
if (m_sort_role == Qt::DisplayRole)
{
return QTableWidgetItem::operator<(other);
}
const QVariant data_l = data(m_sort_role);
const QVariant data_r = other.data(m_sort_role);
const int type_l = data_l.metaType().id();
const int type_r = data_r.metaType().id();
ensure(type_l == type_r);
switch (type_l)
{
case QMetaType::Type::Bool:
case QMetaType::Type::Int:
return data_l.toInt() < data_r.toInt();
case QMetaType::Type::UInt:
return data_l.toUInt() < data_r.toUInt();
case QMetaType::Type::LongLong:
return data_l.toLongLong() < data_r.toLongLong();
case QMetaType::Type::ULongLong:
return data_l.toULongLong() < data_r.toULongLong();
case QMetaType::Type::Double:
return data_l.toDouble() < data_r.toDouble();
case QMetaType::Type::QDate:
return data_l.toDate() < data_r.toDate();
case QMetaType::Type::QTime:
return data_l.toTime() < data_r.toTime();
case QMetaType::Type::QDateTime:
return data_l.toDateTime() < data_r.toDateTime();
case QMetaType::Type::Char:
case QMetaType::Type::QString:
return data_l.toString() < data_r.toString();
default:
fmt::throw_exception("Unimplemented type %s", QMetaType(type_l).name());
}
}
void custom_table_widget_item::setData(int role, const QVariant& value, bool assign_sort_role)
{
if (assign_sort_role)
{
m_sort_role = role;
}
QTableWidgetItem::setData(role, value);
}

View file

@ -1,20 +0,0 @@
#pragma once
#include "movie_item.h"
class custom_table_widget_item : public movie_item
{
private:
int m_sort_role = Qt::DisplayRole;
public:
using QTableWidgetItem::setData;
custom_table_widget_item() = default;
custom_table_widget_item(const std::string& text, int sort_role = Qt::DisplayRole, const QVariant& sort_value = 0);
custom_table_widget_item(const QString& text, int sort_role = Qt::DisplayRole, const QVariant& sort_value = 0);
bool operator<(const QTableWidgetItem& other) const override;
void setData(int role, const QVariant& value, bool assign_sort_role);
};

View file

@ -1,116 +0,0 @@
#include "debugger_add_bp_window.h"
#include "util/StrFmt.h"
#include "util/StrUtil.h"
#include "breakpoint_handler.h"
#include "util/types.hpp"
#include <QVBoxLayout>
#include <QLineEdit>
#include <QLabel>
#include <QComboBox>
#include <QPushButton>
#include <QDialogButtonBox>
#include <QMessageBox>
debugger_add_bp_window::debugger_add_bp_window(breakpoint_list* bp_list, QWidget* parent)
: QDialog(parent)
{
ensure(bp_list);
setWindowTitle(tr("Add a breakpoint"));
setModal(true);
QVBoxLayout* vbox_panel = new QVBoxLayout();
QHBoxLayout* hbox_top = new QHBoxLayout();
QLabel* l_address = new QLabel(tr("Address"));
QLineEdit* t_address = new QLineEdit();
t_address->setPlaceholderText(tr("Address here"));
t_address->setFocus();
hbox_top->addWidget(l_address);
hbox_top->addWidget(t_address);
vbox_panel->addLayout(hbox_top);
QHBoxLayout* hbox_bot = new QHBoxLayout();
QComboBox* co_bptype = new QComboBox(this);
QStringList qstr_breakpoint_types;
qstr_breakpoint_types
#ifdef RPCS3_HAS_MEMORY_BREAKPOINTS
<< tr("Memory Read")
<< tr("Memory Write")
<< tr("Memory Read&Write")
#endif
<< tr("Execution");
co_bptype->addItems(qstr_breakpoint_types);
hbox_bot->addWidget(co_bptype);
vbox_panel->addLayout(hbox_bot);
QHBoxLayout* hbox_buttons = new QHBoxLayout();
QDialogButtonBox* button_box = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
button_box->button(QDialogButtonBox::Ok)->setText(tr("Add"));
hbox_buttons->addWidget(button_box);
vbox_panel->addLayout(hbox_buttons);
setLayout(vbox_panel);
connect(button_box, &QDialogButtonBox::accepted, this, [=, this]
{
const std::string str_address = t_address->text().toStdString();
if (str_address.empty())
{
QMessageBox::warning(this, tr("Add BP error"), tr("Address is empty!"));
return;
}
// We always want hex
const std::string parsed_string = (!str_address.starts_with("0x") && !str_address.starts_with("0X")) ? fmt::format("0x%s", str_address) : str_address;
u64 parsed_address = 0;
// We don't accept 0
if (!try_to_uint64(&parsed_address, parsed_string, 1, 0xFF'FF'FF'FF))
{
QMessageBox::warning(this, tr("Add BP error"), tr("Address is invalid!"));
return;
}
const u32 address = static_cast<u32>(parsed_address);
bs_t<breakpoint_types> bp_t{};
#ifdef RPCS3_HAS_MEMORY_BREAKPOINTS
switch (co_bptype->currentIndex())
{
case 0:
bp_t = breakpoint_types::bp_read;
break;
case 1:
bp_t = breakpoint_types::bp_write;
break;
case 2:
bp_t = breakpoint_types::bp_read + breakpoint_types::bp_write;
break;
case 3:
bp_t = breakpoint_types::bp_exec;
break;
default:
break;
}
#else
bp_t = breakpoint_types::bp_exec;
#endif
if (bp_t)
bp_list->AddBreakpoint(address, bp_t);
QDialog::accept();
});
connect(button_box, &QDialogButtonBox::rejected, this, &QDialog::reject);
move(QCursor::pos());
}

View file

@ -1,13 +0,0 @@
#pragma once
#include "breakpoint_list.h"
#include <QDialog>
class debugger_add_bp_window : public QDialog
{
Q_OBJECT
public:
explicit debugger_add_bp_window(breakpoint_list* bp_list, QWidget* parent = nullptr);
};

File diff suppressed because it is too large Load diff

View file

@ -1,146 +0,0 @@
#pragma once
#include "util/types.hpp"
#include "util/shared_ptr.hpp"
#include "custom_dock_widget.h"
#include <QSplitter>
#include <QPlainTextEdit>
#include <QPushButton>
#include <QComboBox>
#include <memory>
#include <vector>
#include <any>
#include <functional>
class CPUDisAsm;
class cpu_thread;
class gui_settings;
class debugger_list;
class breakpoint_list;
class breakpoint_handler;
class call_stack_list;
namespace rsx
{
class thread;
}
namespace utils
{
class shm;
}
enum class system_state : u32;
class instruction_editor_dialog;
class register_editor_dialog;
class debugger_frame : public custom_dock_widget
{
Q_OBJECT
const QString NoThreadString = tr("No Thread");
const QString RunString = tr("Run");
const QString PauseString = tr("Pause");
debugger_list* m_debugger_list = nullptr;
QSplitter* m_right_splitter = nullptr;
QFont m_mono;
QPlainTextEdit* m_misc_state = nullptr;
QPlainTextEdit* m_regs = nullptr;
QPushButton* m_go_to_addr = nullptr;
QPushButton* m_go_to_pc = nullptr;
QPushButton* m_btn_step = nullptr;
QPushButton* m_btn_step_over = nullptr;
QPushButton* m_btn_add_bp = nullptr;
QPushButton* m_btn_run = nullptr;
QComboBox* m_choice_units = nullptr;
QTimer* m_update = nullptr;
QSplitter* m_splitter = nullptr;
u64 m_threads_created = -1;
u64 m_threads_deleted = -1;
system_state m_emu_state{};
u64 m_emulation_id{};
u32 m_last_pc = -1;
std::vector<char> m_last_query_state;
std::string m_last_reg_state;
std::any m_dump_reg_func_data;
std::vector<std::function<cpu_thread*()>> m_threads_info;
u32 m_last_step_over_breakpoint = -1;
u64 m_ui_update_ctr = 0;
u64 m_ui_fast_update_permission_deadline = 0;
bool m_thread_list_pending_update = false;
std::shared_ptr<CPUDisAsm> m_disasm; // Only shared to allow base/derived functionality
shared_ptr<cpu_thread> m_cpu;
rsx::thread* m_rsx = nullptr;
std::shared_ptr<utils::shm> m_spu_disasm_memory;
u32 m_spu_disasm_origin_eal = 0;
u32 m_spu_disasm_pc = 0;
bool m_is_spu_disasm_mode = false;
breakpoint_list* m_breakpoint_list = nullptr;
breakpoint_handler* m_ppu_breakpoint_handler = nullptr;
call_stack_list* m_call_stack_list = nullptr;
instruction_editor_dialog* m_inst_editor = nullptr;
register_editor_dialog* m_reg_editor = nullptr;
QDialog* m_goto_dialog = nullptr;
QDialog* m_spu_disasm_dialog = nullptr;
std::shared_ptr<gui_settings> m_gui_settings;
cpu_thread* get_cpu();
std::function<cpu_thread*()> make_check_cpu(cpu_thread* cpu, bool unlocked = false);
void open_breakpoints_settings();
public:
explicit debugger_frame(std::shared_ptr<gui_settings> settings, QWidget* parent = nullptr);
void SaveSettings() const;
void ChangeColors() const;
void UpdateUI();
void UpdateUnitList();
void DoUpdate();
void WritePanels();
void EnableButtons(bool enable);
void ShowGotoAddressDialog();
void PerformGoToRequest(const QString& text_argument);
void PerformGoToThreadRequest(const QString& text_argument);
void PerformAddBreakpointRequest(u32 addr);
u64 EvaluateExpression(const QString& expression);
void ClearBreakpoints() const; // Fallthrough method into breakpoint_list.
void ClearCallStack();
/** Needed so key press events work when other objects are selected in debugger_frame. */
bool eventFilter(QObject* object, QEvent* event) override;
protected:
/** Override inherited method from Qt to allow signalling when close happened.*/
void closeEvent(QCloseEvent* event) override;
void showEvent(QShowEvent* event) override;
void hideEvent(QHideEvent* event) override;
void keyPressEvent(QKeyEvent* event) override;
Q_SIGNALS:
void DebugFrameClosed();
void CallStackUpdateRequested(const std::vector<std::pair<u32, u32>>& call_stack);
public Q_SLOTS:
void DoStep(bool step_over = false);
private Q_SLOTS:
void OnSelectUnit();
void OnSelectSPUDisassembler();
void ShowPC(bool user_requested = false);
void EnableUpdateTimer(bool enable) const;
void RunBtnPress();
};
Q_DECLARE_METATYPE(u32)

View file

@ -1,497 +0,0 @@
#include "debugger_list.h"
#include "gui_settings.h"
#include "qt_utils.h"
#include "breakpoint_handler.h"
#include "Emu/Cell/SPUThread.h"
#include "Emu/CPU/CPUDisAsm.h"
#include "Emu/CPU/CPUThread.h"
#include "Emu/RSX/RSXDisAsm.h"
#include "Emu/RSX/RSXThread.h"
#include "Emu/System.h"
#include "util/asm.hpp"
#include <QMouseEvent>
#include <QWheelEvent>
#include <QVBoxLayout>
#include <QLabel>
#include <memory>
constexpr auto qstr = QString::fromStdString;
debugger_list::debugger_list(QWidget* parent, std::shared_ptr<gui_settings> gui_settings, breakpoint_handler* handler)
: QListWidget(parent), m_gui_settings(std::move(gui_settings)), m_ppu_breakpoint_handler(handler)
{
setWindowTitle(tr("ASM"));
for (uint i = 0; i < m_item_count; ++i)
{
insertItem(i, new QListWidgetItem(""));
}
setSizeAdjustPolicy(QListWidget::AdjustToContents);
setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
connect(this, &QListWidget::currentRowChanged, this, [this](int row)
{
if (row < 0)
{
m_selected_instruction = -1;
m_showing_selected_instruction = false;
return;
}
u32 pc = m_start_addr;
const auto cpu = m_disasm && !Emu.IsStopped() ? m_disasm->get_cpu() : nullptr;
for (; cpu && cpu->get_class() == thread_class::rsx && row; row--)
{
// If scrolling forwards (downwards), we can skip entire commands
pc += std::max<u32>(m_disasm->disasm(pc), 4);
}
m_selected_instruction = pc + row * 4;
});
}
void debugger_list::UpdateCPUData(std::shared_ptr<CPUDisAsm> disasm)
{
if ((!m_disasm) != (!disasm) || (m_disasm && disasm->get_cpu() != m_disasm->get_cpu()))
{
m_selected_instruction = -1;
m_showing_selected_instruction = false;
}
m_disasm = std::move(disasm);
}
u32 debugger_list::GetStartAddress(u32 address)
{
const auto cpu = m_disasm && !Emu.IsStopped() ? m_disasm->get_cpu() : nullptr;
const u32 steps = m_item_count / 3;
const u32 inst_count_jump_on_step = std::min<u32>(steps, 4);
const bool is_spu = IsSpu();
const u32 address_mask = (is_spu ? 0x3fffc : ~3);
u32 result = address & address_mask;
if (cpu && cpu->get_class() == thread_class::rsx)
{
if (auto [count, res] = static_cast<rsx::thread*>(cpu)->try_get_pc_of_x_cmds_backwards(steps, address); count == steps)
{
result = res;
}
}
else
{
result = (address - (steps * 4)) & address_mask;
}
u32 upper_bound = (m_start_addr + (steps * 4)) & address_mask;
if (cpu && cpu->get_class() == thread_class::rsx)
{
if (auto [count, res] = static_cast<rsx::thread*>(cpu)->try_get_pc_of_x_cmds_backwards(0 - steps, m_start_addr); count == steps)
{
upper_bound = res;
}
}
bool goto_addr = false;
if (upper_bound > m_start_addr)
{
goto_addr = address < m_start_addr || address >= upper_bound;
}
else
{
// Overflowing bounds case
goto_addr = address < m_start_addr && address >= upper_bound;
}
if (goto_addr)
{
m_pc = address;
if (address > upper_bound && address - upper_bound < inst_count_jump_on_step * 4)
{
m_start_addr = result + inst_count_jump_on_step * 4;
}
else
{
m_start_addr = result;
}
}
return m_start_addr;
}
bool debugger_list::IsSpu() const
{
const auto cpu = m_disasm && !Emu.IsStopped() ? m_disasm->get_cpu() : nullptr;
return (cpu && cpu->get_class() == thread_class::spu) || (m_disasm && !cpu);
}
void debugger_list::ShowAddress(u32 addr, bool select_addr, bool direct)
{
const auto cpu = m_disasm && !Emu.IsStopped() ? m_disasm->get_cpu() : nullptr;
const decltype(spu_thread::local_breakpoints)* spu_bps_list{};
if (cpu && cpu->get_class() == thread_class::spu)
{
spu_bps_list = &static_cast<spu_thread*>(cpu)->local_breakpoints;
}
auto IsBreakpoint = [&](u32 pc)
{
switch (cpu ? cpu->get_class() : thread_class::general)
{
case thread_class::ppu:
{
return m_ppu_breakpoint_handler->HasBreakpoint(pc, breakpoint_types::bp_exec);
}
case thread_class::spu:
{
const u32 pos_at = pc / 4;
const u32 pos_bit = 1u << (pos_at % 8);
return !!((*spu_bps_list)[pos_at / 8] & pos_bit);
}
default: return false;
}
};
if (select_addr || direct)
{
// The user wants to survey a specific memory location, do not interfere from this point forth
m_follow_thread = false;
}
m_dirty_flag = false;
u32 pc = m_start_addr;
if (!direct && (m_follow_thread || select_addr))
{
pc = GetStartAddress(addr);
}
const auto& default_foreground = palette().color(foregroundRole());
const auto& default_background = palette().color(backgroundRole());
m_showing_selected_instruction = false;
if (select_addr)
{
m_selected_instruction = addr;
}
for (uint i = 0; i < m_item_count; ++i)
{
if (auto list_item = item(i); list_item->isSelected())
{
list_item->setSelected(false);
}
}
if (!m_disasm || (cpu && cpu->state.all_of(cpu_flag::exit + cpu_flag::wait)))
{
for (uint i = 0; i < m_item_count; ++i)
{
QListWidgetItem* list_item = item(i);
list_item->setText(qstr(fmt::format(" [%08x] ?? ?? ?? ??:", 0)));
list_item->setForeground(default_foreground);
list_item->setBackground(default_background);
}
}
else
{
const bool is_spu = IsSpu();
const u32 address_limits = (is_spu ? 0x3fffc : ~3);
const u32 current_pc = (cpu ? cpu->get_pc() : 0);
m_start_addr &= address_limits;
pc = m_start_addr;
for (uint i = 0, count = 4; i < m_item_count; ++i, pc = (pc + count) & address_limits)
{
QListWidgetItem* list_item = item(i);
if (pc == current_pc)
{
list_item->setForeground(m_text_color_pc);
list_item->setBackground(m_color_pc);
}
else if (pc == m_selected_instruction)
{
// setSelected may invoke a resize event which causes stack overflow, terminate recursion
if (!list_item->isSelected())
{
list_item->setSelected(true);
}
m_showing_selected_instruction = true;
}
else if (IsBreakpoint(pc))
{
list_item->setForeground(m_text_color_bp);
list_item->setBackground(m_color_bp);
}
else
{
list_item->setForeground(default_foreground);
list_item->setBackground(default_background);
}
if (cpu && cpu->get_class() == thread_class::ppu && !vm::check_addr(pc, 0))
{
list_item->setText((IsBreakpoint(pc) ? ">> " : " ") + qstr(fmt::format("[%08x] ?? ?? ?? ??:", pc)));
count = 4;
continue;
}
if (cpu && cpu->get_class() == thread_class::ppu && !vm::check_addr(pc, vm::page_executable))
{
const u32 data = *vm::get_super_ptr<atomic_be_t<u32>>(pc);
list_item->setText((IsBreakpoint(pc) ? ">> " : " ") + qstr(fmt::format("[%08x] %02x %02x %02x %02x:", pc,
static_cast<u8>(data >> 24),
static_cast<u8>(data >> 16),
static_cast<u8>(data >> 8),
static_cast<u8>(data >> 0))));
count = 4;
continue;
}
count = m_disasm->disasm(pc);
if (!count)
{
list_item->setText((IsBreakpoint(pc) ? ">> " : " ") + qstr(fmt::format("[%08x] ??? ?? ??", pc)));
count = 4;
continue;
}
list_item->setText((IsBreakpoint(pc) ? ">> " : " ") + qstr(m_disasm->last_opcode));
}
}
setLineWidth(-1);
}
void debugger_list::RefreshView()
{
const bool old = std::exchange(m_follow_thread, false);
ShowAddress(0, false);
m_follow_thread = old;
}
void debugger_list::EnableThreadFollowing(bool enable)
{
m_follow_thread = enable;
}
void debugger_list::scroll(s32 steps)
{
const auto cpu = m_disasm && !Emu.IsStopped() ? m_disasm->get_cpu() : nullptr;
for (; cpu && cpu->get_class() == thread_class::rsx && steps > 0; steps--)
{
// If scrolling forwards (downwards), we can skip entire commands
m_start_addr += std::max<u32>(m_disasm->disasm(m_start_addr), 4);
}
if (cpu && cpu->get_class() == thread_class::rsx && steps < 0)
{
// If scrolling backwards (upwards), try to obtain the start of commands tail
if (auto [count, res] = static_cast<rsx::thread*>(cpu)->try_get_pc_of_x_cmds_backwards(-steps, m_start_addr); count == 0u - steps)
{
steps = 0;
m_start_addr = res;
}
}
EnableThreadFollowing(false);
m_start_addr += steps * 4;
ShowAddress(0, false, true);
}
void debugger_list::keyPressEvent(QKeyEvent* event)
{
const auto cpu = m_disasm && !Emu.IsStopped() ? m_disasm->get_cpu() : nullptr;
// Always accept event (so it would not bubble upwards, debugger_frame already sees it)
struct accept_event_t
{
QKeyEvent* event;
~accept_event_t() noexcept
{
event->accept();
}
} accept_event{event};
if (!isActiveWindow())
{
QListWidget::keyPressEvent(event);
return;
}
if (event->modifiers())
{
QListWidget::keyPressEvent(event);
return;
}
switch (event->key())
{
case Qt::Key_PageUp: scroll(0 - m_item_count); return;
case Qt::Key_PageDown: scroll(m_item_count); return;
case Qt::Key_Up: scroll(-1); return;
case Qt::Key_Down: scroll(1); return;
case Qt::Key_I:
{
if (event->isAutoRepeat())
{
QListWidget::keyPressEvent(event);
return;
}
if (cpu && cpu->get_class() == thread_class::rsx)
{
create_rsx_command_detail(m_showing_selected_instruction ? m_selected_instruction : m_pc);
return;
}
break;
}
default: break;
}
QListWidget::keyPressEvent(event);
}
void debugger_list::showEvent(QShowEvent* event)
{
if (m_cmd_detail)
m_cmd_detail->show();
QListWidget::showEvent(event);
}
void debugger_list::hideEvent(QHideEvent* event)
{
if (m_cmd_detail)
m_cmd_detail->hide();
QListWidget::hideEvent(event);
}
void debugger_list::create_rsx_command_detail(u32 pc)
{
RSXDisAsm rsx_dis = static_cast<RSXDisAsm&>(*m_disasm);
rsx_dis.change_mode(cpu_disasm_mode::list);
// Either invalid or not a method
if (rsx_dis.disasm(pc) <= 4)
return;
if (m_cmd_detail)
{
// Edit the existing dialog
m_detail_label->setText(QString::fromStdString(rsx_dis.last_opcode));
m_cmd_detail->setFixedSize(m_cmd_detail->sizeHint());
return;
}
m_cmd_detail = new QDialog(this);
m_cmd_detail->setWindowTitle(tr("RSX Command Detail"));
m_detail_label = new QLabel(QString::fromStdString(rsx_dis.last_opcode), this);
m_detail_label->setFont(font());
gui::utils::set_font_size(*m_detail_label, 10);
m_detail_label->setTextInteractionFlags(Qt::TextSelectableByMouse | Qt::TextSelectableByKeyboard);
QVBoxLayout* layout = new QVBoxLayout(this);
layout->addWidget(m_detail_label);
m_cmd_detail->setLayout(layout);
m_cmd_detail->setFixedSize(m_cmd_detail->sizeHint());
m_cmd_detail->show();
connect(m_cmd_detail, &QDialog::finished, [this](int)
{
// Cleanup
std::exchange(m_cmd_detail, nullptr)->deleteLater();
});
}
void debugger_list::mouseDoubleClickEvent(QMouseEvent* event)
{
if (event->button() == Qt::LeftButton)
{
int i = currentRow();
if (i < 0)
return;
u32 pc = m_start_addr;
const auto cpu = m_disasm && !Emu.IsStopped() ? m_disasm->get_cpu() : nullptr;
for (; cpu && cpu->get_class() == thread_class::rsx && i; i--)
{
// If scrolling forwards (downwards), we can skip entire commands
pc += std::max<u32>(m_disasm->disasm(pc), 4);
}
pc += i * 4;
m_selected_instruction = pc;
// Let debugger_frame know about breakpoint.
// Other option is to add to breakpoint manager directly and have a signal there instead.
// Either the flow goes from debugger_list->breakpoint_manager->debugger_frame, or it goes debugger_list->debugger_frame, and I felt this was easier to read for now.
Q_EMIT BreakpointRequested(pc);
}
}
void debugger_list::wheelEvent(QWheelEvent* event)
{
const QPoint numSteps = event->angleDelta() / 8 / 15; // http://doc.qt.io/qt-5/qwheelevent.html#pixelDelta
const int value = numSteps.y();
const auto direction = (event->modifiers() == Qt::ControlModifier);
scroll(direction ? value : -value);
}
void debugger_list::resizeEvent(QResizeEvent* event)
{
QListWidget::resizeEvent(event);
if (count() < 1 || visualItemRect(item(0)).height() < 1)
{
return;
}
const u32 old_size = m_item_count;
// It is fine if the QWidgetList is a tad bit larger than the frame
m_item_count = utils::aligned_div<u32>(rect().height() - frameWidth() * 2, visualItemRect(item(0)).height());
if (old_size <= m_item_count)
{
for (u32 i = old_size; i < m_item_count; ++i)
{
insertItem(i, new QListWidgetItem(""));
m_dirty_flag = true;
}
}
else
{
for (u32 i = old_size - 1; i >= m_item_count; --i)
{
delete takeItem(i);
}
}
}

View file

@ -1,67 +0,0 @@
#pragma once
#include "util/types.hpp"
#include <QListWidget>
#include <memory>
class breakpoint_handler;
class CPUDisAsm;
class cpu_thread;
class gui_settings;
class QLabel;
class debugger_list : public QListWidget
{
Q_OBJECT
public:
u32 m_pc = 0;
u32 m_start_addr = 0;
u32 m_item_count = 30;
u32 m_selected_instruction = -1;
bool m_follow_thread = true; // If true, follow the selected thread to wherever it goes in code
bool m_showing_selected_instruction = false;
bool m_dirty_flag = false;
QColor m_color_bp;
QColor m_color_pc;
QColor m_text_color_bp;
QColor m_text_color_pc;
Q_SIGNALS:
void BreakpointRequested(u32 loc, bool only_add = false);
public:
debugger_list(QWidget* parent, std::shared_ptr<gui_settings> settings, breakpoint_handler* handler);
void UpdateCPUData(std::shared_ptr<CPUDisAsm> disasm);
void EnableThreadFollowing(bool enable = true);
public Q_SLOTS:
void ShowAddress(u32 addr, bool select_addr = true, bool direct = false);
void RefreshView();
protected:
void keyPressEvent(QKeyEvent* event) override;
void mouseDoubleClickEvent(QMouseEvent* event) override;
void wheelEvent(QWheelEvent* event) override;
void resizeEvent(QResizeEvent* event) override;
void showEvent(QShowEvent* event) override;
void hideEvent(QHideEvent* event) override;
void scroll(s32 steps);
void create_rsx_command_detail(u32 pc);
private:
/**
* It really upsetted me I had to copy this code to make debugger_list/frame not circularly dependent.
*/
u32 GetStartAddress(u32 address);
bool IsSpu() const;
std::shared_ptr<gui_settings> m_gui_settings;
breakpoint_handler* m_ppu_breakpoint_handler = nullptr;
cpu_thread* m_cpu = nullptr;
std::shared_ptr<CPUDisAsm> m_disasm;
QDialog* m_cmd_detail = nullptr;
QLabel* m_detail_label = nullptr;
};

View file

@ -1,779 +0,0 @@
#include "stdafx.h"
#include "util/File.h"
#include "dimensions_dialog.h"
#include "Emu/Io/Dimensions.h"
#include <QLabel>
#include <QGroupBox>
#include <QFileDialog>
#include <QVBoxLayout>
#include <QMessageBox>
#include <QComboBox>
#include <QPushButton>
#include <QStringList>
#include <QCompleter>
#include <QGridLayout>
dimensions_dialog* dimensions_dialog::inst = nullptr;
std::array<std::optional<u32>, 7> figure_slots = {};
static QString s_last_figure_path;
LOG_CHANNEL(dimensions_log, "dimensions");
const std::map<const u32, const std::string> list_minifigs = {
{0, "Blank Tag"},
{1, "Batman"},
{2, "Gandalf"},
{3, "Wyldstyle"},
{4, "Aquaman"},
{5, "Bad Cop"},
{6, "Bane"},
{7, "Bart Simpson"},
{8, "Benny"},
{9, "Chell"},
{10, "Cole"},
{11, "Cragger"},
{12, "Cyborg"},
{13, "Cyberman"},
{14, "Doc Brown"},
{15, "The Doctor"},
{16, "Emmet"},
{17, "Eris"},
{18, "Gimli"},
{19, "Gollum"},
{20, "Harley Quinn"},
{21, "Homer Simpson"},
{22, "Jay"},
{23, "Joker"},
{24, "Kai"},
{25, "ACU Trooper"},
{26, "Gamer Kid"},
{27, "Krusty the Clown"},
{28, "Laval"},
{29, "Legolas"},
{30, "Lloyd"},
{31, "Marty McFly"},
{32, "Nya"},
{33, "Owen Grady"},
{34, "Peter Venkman"},
{35, "Slimer"},
{36, "Scooby-Doo"},
{37, "Sensei Wu"},
{38, "Shaggy"},
{39, "Stay Puft"},
{40, "Superman"},
{41, "Unikitty"},
{42, "Wicked Witch of the West"},
{43, "Wonder Woman"},
{44, "Zane"},
{45, "Green Arrow"},
{46, "Supergirl"},
{47, "Abby Yates"},
{48, "Finn the Human"},
{49, "Ethan Hunt"},
{50, "Lumpy Space Princess"},
{51, "Jake the Dog"},
{52, "Harry Potter"},
{53, "Lord Voldemort"},
{54, "Michael Knight"},
{55, "B.A. Baracus"},
{56, "Newt Scamander"},
{57, "Sonic the Hedgehog"},
{58, "Future Update (unreleased)"},
{59, "Gizmo"},
{60, "Stripe"},
{61, "E.T."},
{62, "Tina Goldstein"},
{63, "Marceline the Vampire Queen"},
{64, "Batgirl"},
{65, "Robin"},
{66, "Sloth"},
{67, "Hermione Granger"},
{68, "Chase McCain"},
{69, "Excalibur Batman"},
{70, "Raven"},
{71, "Beast Boy"},
{72, "Betelgeuse"},
{73, "Lord Vortech (unreleased)"},
{74, "Blossom"},
{75, "Bubbles"},
{76, "Buttercup"},
{77, "Starfire"},
{78, "World 15 (unreleased)"},
{79, "World 16 (unreleased)"},
{80, "World 17 (unreleased)"},
{81, "World 18 (unreleased)"},
{82, "World 19 (unreleased)"},
{83, "World 20 (unreleased)"},
{768, "Unknown 768"},
{769, "Supergirl Red Lantern"},
{770, "Unknown 770"}};
const std::map<const u32, const std::string> list_tokens = {
{1000, "Police Car"},
{1001, "Aerial Squad Car"},
{1002, "Missile Striker"},
{1003, "Gravity Sprinter"},
{1004, "Street Shredder"},
{1005, "Sky Clobberer"},
{1006, "Batmobile"},
{1007, "Batblaster"},
{1008, "Sonic Batray"},
{1009, "Benny's Spaceship"},
{1010, "Lasercraft"},
{1011, "The Annihilator"},
{1012, "DeLorean Time Machine"},
{1013, "Electric Time Machine"},
{1014, "Ultra Time Machine"},
{1015, "Hoverboard"},
{1016, "Cyclone Board"},
{1017, "Ultimate Hoverjet"},
{1018, "Eagle Interceptor"},
{1019, "Eagle Sky Blazer"},
{1020, "Eagle Swoop Diver"},
{1021, "Swamp Skimmer"},
{1022, "Cragger's Fireship"},
{1023, "Croc Command Sub"},
{1024, "Cyber-Guard"},
{1025, "Cyber-Wrecker"},
{1026, "Laser Robot Walker"},
{1027, "K-9"},
{1028, "K-9 Ruff Rover"},
{1029, "K-9 Laser Cutter"},
{1030, "TARDIS"},
{1031, "Laser-Pulse TARDIS"},
{1032, "Energy-Burst TARDIS"},
{1033, "Emmet's Excavator"},
{1034, "Destroy Dozer"},
{1035, "Destruct-o-Mech"},
{1036, "Winged Monkey"},
{1037, "Battle Monkey"},
{1038, "Commander Monkey"},
{1039, "Axe Chariot"},
{1040, "Axe Hurler"},
{1041, "Soaring Chariot"},
{1042, "Shelob the Great"},
{1043, "8-Legged Stalker"},
{1044, "Poison Slinger"},
{1045, "Homer's Car"},
{1047, "The SubmaHomer"},
{1046, "The Homercraft"},
{1048, "Taunt-o-Vision"},
{1050, "The MechaHomer"},
{1049, "Blast Cam"},
{1051, "Velociraptor"},
{1053, "Venom Raptor"},
{1052, "Spike Attack Raptor"},
{1054, "Gyrosphere"},
{1055, "Sonic Beam Gyrosphere"},
{1056, " Gyrosphere"},
{1057, "Clown Bike"},
{1058, "Cannon Bike"},
{1059, "Anti-Gravity Rocket Bike"},
{1060, "Mighty Lion Rider"},
{1061, "Lion Blazer"},
{1062, "Fire Lion"},
{1063, "Arrow Launcher"},
{1064, "Seeking Shooter"},
{1065, "Triple Ballista"},
{1066, "Mystery Machine"},
{1067, "Mystery Tow & Go"},
{1068, "Mystery Monster"},
{1069, "Boulder Bomber"},
{1070, "Boulder Blaster"},
{1071, "Cyclone Jet"},
{1072, "Storm Fighter"},
{1073, "Lightning Jet"},
{1074, "Electro-Shooter"},
{1075, "Blade Bike"},
{1076, "Flight Fire Bike"},
{1077, "Blades of Fire"},
{1078, "Samurai Mech"},
{1079, "Samurai Shooter"},
{1080, "Soaring Samurai Mech"},
{1081, "Companion Cube"},
{1082, "Laser Deflector"},
{1083, "Gold Heart Emitter"},
{1084, "Sentry Turret"},
{1085, "Turret Striker"},
{1086, "Flight Turret Carrier"},
{1087, "Scooby Snack"},
{1088, "Scooby Fire Snack"},
{1089, "Scooby Ghost Snack"},
{1090, "Cloud Cuckoo Car"},
{1091, "X-Stream Soaker"},
{1092, "Rainbow Cannon"},
{1093, "Invisible Jet"},
{1094, "Laser Shooter"},
{1095, "Torpedo Bomber"},
{1096, "NinjaCopter"},
{1097, "Glaciator"},
{1098, "Freeze Fighter"},
{1099, "Travelling Time Train"},
{1100, "Flight Time Train"},
{1101, "Missile Blast Time Train"},
{1102, "Aqua Watercraft"},
{1103, "Seven Seas Speeder"},
{1104, "Trident of Fire"},
{1105, "Drill Driver"},
{1106, "Bane Dig 'n' Drill"},
{1107, "Bane Drill 'n' Blast"},
{1108, "Quinn Mobile"},
{1109, "Quinn Ultra Racer"},
{1110, "Missile Launcher"},
{1111, "The Joker's Chopper"},
{1112, "Mischievous Missile Blaster"},
{1113, "Lock 'n' Laser Jet"},
{1114, "Hover Pod"},
{1115, "Krypton Striker"},
{1116, "Super Stealth Pod"},
{1117, "Dalek"},
{1118, "Fire 'n' Ride Dalek"},
{1119, "Silver Shooter Dalek"},
{1120, "Ecto-1"},
{1121, "Ecto-1 Blaster"},
{1122, "Ecto-1 Water Diver"},
{1123, "Ghost Trap"},
{1124, "Ghost Stun 'n' Trap"},
{1125, "Proton Zapper"},
{1126, "Unknown"},
{1127, "Unknown"},
{1128, "Unknown"},
{1129, "Unknown"},
{1130, "Unknown"},
{1131, "Unknown"},
{1132, "Lloyd's Golden Dragon"},
{1133, "Sword Projector Dragon"},
{1134, "Unknown"},
{1135, "Unknown"},
{1136, "Unknown"},
{1137, "Unknown"},
{1138, "Unknown"},
{1139, "Unknown"},
{1140, "Unknown"},
{1141, "Unknown"},
{1142, "Unknown"},
{1143, "Unknown"},
{1144, "Mega Flight Dragon"},
{1145, "Unknown"},
{1146, "Unknown"},
{1147, "Unknown"},
{1148, "Unknown"},
{1149, "Unknown"},
{1150, "Unknown"},
{1151, "Unknown"},
{1152, "Unknown"},
{1153, "Unknown"},
{1154, "Unknown"},
{1155, "Flying White Dragon"},
{1156, "Golden Fire Dragon"},
{1157, "Ultra Destruction Dragon"},
{1158, "Arcade Machine"},
{1159, "8-Bit Shooter"},
{1160, "The Pixelator"},
{1161, "G-6155 Spy Hunter"},
{1162, "Interdiver"},
{1163, "Aerial Spyhunter"},
{1164, "Slime Shooter"},
{1165, "Slime Exploder"},
{1166, "Slime Streamer"},
{1167, "Terror Dog"},
{1168, "Terror Dog Destroyer"},
{1169, "Soaring Terror Dog"},
{1170, "Ancient Psychic Tandem War Elephant"},
{1171, "Cosmic Squid"},
{1172, "Psychic Submarine"},
{1173, "BMO"},
{1174, "DOGMO"},
{1175, "SNAKEMO"},
{1176, "Jakemobile"},
{1177, "Snail Dude Jake"},
{1178, "Hover Jake"},
{1179, "Lumpy Car"},
{1181, "Lumpy Land Whale"},
{1180, "Lumpy Truck"},
{1182, "Lunatic Amp"},
{1183, "Shadow Scorpion"},
{1184, "Heavy Metal Monster"},
{1185, "B.A.'s Van"},
{1186, "Fool Smasher"},
{1187, "Pain Plane"},
{1188, "Phone Home"},
{1189, "Mobile Uplink"},
{1190, "Super-Charged Satellite"},
{1191, "Niffler"},
{1192, "Sinister Scorpion"},
{1193, "Vicious Vulture"},
{1194, "Swooping Evil"},
{1195, "Brutal Bloom"},
{1196, "Crawling Creeper"},
{1197, "Ecto-1 (2016)"},
{1198, "Ectozer"},
{1199, "PerfEcto"},
{1200, "Flash 'n' Finish"},
{1201, "Rampage Record Player"},
{1202, "Stripe's Throne"},
{1203, "R.C. Racer"},
{1204, "Gadget-O-Matic"},
{1205, "Scarlet Scorpion"},
{1206, "Hogwarts Express"},
{1208, "Steam Warrior"},
{1207, "Soaring Steam Plane"},
{1209, "Enchanted Car"},
{1210, "Shark Sub"},
{1211, "Monstrous Mouth"},
{1212, "IMF Scrambler"},
{1213, "Shock Cycle"},
{1214, "IMF Covert Jet"},
{1215, "IMF Sports Car"},
{1216, "IMF Tank"},
{1217, "IMF Splorer"},
{1218, "Sonic Speedster"},
{1219, "Blue Typhoon"},
{1220, "Moto Bug"},
{1221, "The Tornado"},
{1222, "Crabmeat"},
{1223, "Eggcatcher"},
{1224, "K.I.T.T."},
{1225, "Goliath Armored Semi"},
{1226, "K.I.T.T. Jet"},
{1227, "Police Helicopter"},
{1228, "Police Hovercraft"},
{1229, "Police Plane"},
{1230, "Bionic Steed"},
{1231, "Bat-Raptor"},
{1232, "Ultrabat"},
{1233, "Batwing"},
{1234, "The Black Thunder"},
{1235, "Bat-Tank"},
{1236, "Skeleton Organ"},
{1237, "Skeleton Jukebox"},
{1238, "Skele-Turkey"},
{1239, "One-Eyed Willy's Pirate Ship"},
{1240, "Fanged Fortune"},
{1241, "Inferno Cannon"},
{1242, "Buckbeak"},
{1243, "Giant Owl"},
{1244, "Fierce Falcon"},
{1245, "Saturn's Sandworm"},
{1247, "Haunted Vacuum"},
{1246, "Spooky Spider"},
{1248, "PPG Smartphone"},
{1249, "PPG Hotline"},
{1250, "Powerpuff Mag-Net"},
{1253, "Mega Blast Bot"},
{1251, "Ka-Pow Cannon"},
{1252, "Slammin' Guitar"},
{1254, "Octi"},
{1255, "Super Skunk"},
{1256, "Sonic Squid"},
{1257, "T-Car"},
{1258, "T-Forklift"},
{1259, "T-Plane"},
{1260, "Spellbook of Azarath"},
{1261, "Raven Wings"},
{1262, "Giant Hand"},
{1263, "Titan Robot"},
{1264, "T-Rocket"},
{1265, "Robot Retriever"}};
minifig_creator_dialog::minifig_creator_dialog(QWidget* parent)
: QDialog(parent)
{
setWindowTitle(tr("Figure Creator"));
setObjectName("figure_creator");
setMinimumSize(QSize(500, 150));
QVBoxLayout* vbox_panel = new QVBoxLayout();
QComboBox* combo_figlist = new QComboBox();
QStringList filterlist;
for (const auto& [figure, figure_name] : list_minifigs)
{
QString name = QString::fromStdString(figure_name);
combo_figlist->addItem(name, QVariant(figure));
filterlist << std::move(name);
}
combo_figlist->addItem(tr("--Unknown--"), QVariant(0xFFFF));
combo_figlist->setEditable(true);
combo_figlist->setInsertPolicy(QComboBox::NoInsert);
combo_figlist->model()->sort(0, Qt::AscendingOrder);
QCompleter* co_compl = new QCompleter(filterlist, this);
co_compl->setCaseSensitivity(Qt::CaseInsensitive);
co_compl->setCompletionMode(QCompleter::PopupCompletion);
co_compl->setFilterMode(Qt::MatchContains);
combo_figlist->setCompleter(co_compl);
vbox_panel->addWidget(combo_figlist);
QFrame* line = new QFrame();
line->setFrameShape(QFrame::HLine);
line->setFrameShadow(QFrame::Sunken);
vbox_panel->addWidget(line);
QHBoxLayout* hbox_number = new QHBoxLayout();
QLabel* label_number = new QLabel(tr("Figure Number:"));
QLineEdit* edit_number = new QLineEdit(QString::fromStdString(std::to_string(0)));
QRegularExpressionValidator* rxv = new QRegularExpressionValidator(QRegularExpression("\\d*"), this);
edit_number->setValidator(rxv);
hbox_number->addWidget(label_number);
hbox_number->addWidget(edit_number);
vbox_panel->addLayout(hbox_number);
QHBoxLayout* hbox_buttons = new QHBoxLayout();
QPushButton* btn_create = new QPushButton(tr("Create"), this);
QPushButton* btn_cancel = new QPushButton(tr("Cancel"), this);
hbox_buttons->addStretch();
hbox_buttons->addWidget(btn_create);
hbox_buttons->addWidget(btn_cancel);
vbox_panel->addLayout(hbox_buttons);
setLayout(vbox_panel);
connect(combo_figlist, QOverload<int>::of(&QComboBox::currentIndexChanged), [=](int index)
{
const u16 fig_info = combo_figlist->itemData(index).toUInt();
if (fig_info != 0xFFFF)
{
edit_number->setText(QString::number(fig_info));
}
});
connect(btn_create, &QAbstractButton::clicked, this, [=, this]()
{
bool ok_num = false;
const u16 fig_num = edit_number->text().toUInt(&ok_num) & 0xFFFF;
if (!ok_num)
{
QMessageBox::warning(this, tr("Error converting value"), tr("Figure number entered is invalid!"), QMessageBox::Ok);
return;
}
const auto found_figure = list_minifigs.find(fig_num);
if (found_figure != list_minifigs.cend())
{
s_last_figure_path += QString::fromStdString(found_figure->second + ".bin");
}
else
{
s_last_figure_path += QString("Unknown(%1).bin").arg(fig_num);
}
m_file_path = QFileDialog::getSaveFileName(this, tr("Create Figure File"), s_last_figure_path, tr("Dimensions Figure (*.bin);;"));
if (m_file_path.isEmpty())
{
return;
}
fs::file dim_file(m_file_path.toStdString(), fs::read + fs::write + fs::create);
if (!dim_file)
{
QMessageBox::warning(this, tr("Failed to create minifig file!"), tr("Failed to create minifig file:\n%1").arg(m_file_path), QMessageBox::Ok);
return;
}
std::array<u8, 0x2D * 0x04> file_data{};
g_dimensionstoypad.create_blank_character(file_data, fig_num);
dim_file.write(file_data.data(), file_data.size());
dim_file.close();
s_last_figure_path = QFileInfo(m_file_path).absolutePath() + "/";
accept();
});
connect(btn_cancel, &QAbstractButton::clicked, this, &QDialog::reject);
connect(co_compl, QOverload<const QString&>::of(&QCompleter::activated), [=](const QString& text)
{
combo_figlist->setCurrentIndex(combo_figlist->findText(text));
});
}
QString minifig_creator_dialog::get_file_path() const
{
return m_file_path;
}
minifig_move_dialog::minifig_move_dialog(QWidget* parent, u8 old_index)
: QDialog(parent)
{
setWindowTitle(tr("Figure Mover"));
setObjectName("figure_mover");
setMinimumSize(QSize(500, 150));
auto* grid_panel = new QGridLayout();
add_minifig_position(grid_panel, 0, 0, 0, old_index);
grid_panel->addWidget(new QLabel(tr("")), 0, 1);
add_minifig_position(grid_panel, 1, 0, 2, old_index);
grid_panel->addWidget(new QLabel(tr(""), this), 0, 3);
add_minifig_position(grid_panel, 2, 0, 4, old_index);
add_minifig_position(grid_panel, 3, 1, 0, old_index);
add_minifig_position(grid_panel, 4, 1, 1, old_index);
grid_panel->addWidget(new QLabel(tr("")), 1, 2);
add_minifig_position(grid_panel, 5, 1, 3, old_index);
add_minifig_position(grid_panel, 6, 1, 4, old_index);
setLayout(grid_panel);
}
void minifig_move_dialog::add_minifig_position(QGridLayout* grid_panel, u8 index, u8 row, u8 column, u8 old_index)
{
ensure(index < figure_slots.size());
auto* vbox_panel = new QVBoxLayout();
if (figure_slots[index])
{
const auto found_figure = list_minifigs.find(figure_slots[index].value());
if (found_figure != list_minifigs.cend())
{
vbox_panel->addWidget(new QLabel(tr(found_figure->second.c_str())));
}
}
else
{
vbox_panel->addWidget(new QLabel(tr("None")));
}
auto* btn_move = new QPushButton(tr("Move Here"), this);
if (old_index == index)
{
btn_move->setText(tr("Pick up and Place"));
}
vbox_panel->addWidget(btn_move);
connect(btn_move, &QAbstractButton::clicked, this, [this, index]
{
m_index = index;
m_pad = index == 1 ? 1 :
index == 0 || index == 3 || index == 4 ? 2 :
3;
accept();
});
grid_panel->addLayout(vbox_panel, row, column);
}
u8 minifig_move_dialog::get_new_pad() const
{
return m_pad;
}
u8 minifig_move_dialog::get_new_index() const
{
return m_index;
}
dimensions_dialog::dimensions_dialog(QWidget* parent)
: QDialog(parent)
{
setWindowTitle(tr("Dimensions Manager"));
setObjectName("dimensions_manager");
setAttribute(Qt::WA_DeleteOnClose);
setMinimumSize(QSize(800, 200));
QVBoxLayout* vbox_panel = new QVBoxLayout();
QVBoxLayout* vbox_group = new QVBoxLayout();
QHBoxLayout* hbox_group_1 = new QHBoxLayout();
QHBoxLayout* hbox_group_2 = new QHBoxLayout();
QGroupBox* group_figures = new QGroupBox(tr("Active Dimensions Figures:"));
add_minifig_slot(hbox_group_1, 2, 0);
hbox_group_1->addSpacerItem(new QSpacerItem(50, 0, QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding));
add_minifig_slot(hbox_group_1, 1, 1);
hbox_group_1->addSpacerItem(new QSpacerItem(50, 0, QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding));
add_minifig_slot(hbox_group_1, 3, 2);
add_minifig_slot(hbox_group_2, 2, 3);
add_minifig_slot(hbox_group_2, 2, 4);
hbox_group_2->addSpacerItem(new QSpacerItem(50, 0, QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding));
add_minifig_slot(hbox_group_2, 3, 5);
add_minifig_slot(hbox_group_2, 3, 6);
vbox_group->addLayout(hbox_group_1);
vbox_group->addSpacerItem(new QSpacerItem(0, 20, QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding));
vbox_group->addLayout(hbox_group_2);
group_figures->setLayout(vbox_group);
vbox_panel->addWidget(group_figures);
setLayout(vbox_panel);
}
dimensions_dialog::~dimensions_dialog()
{
inst = nullptr;
}
dimensions_dialog* dimensions_dialog::get_dlg(QWidget* parent)
{
if (inst == nullptr)
inst = new dimensions_dialog(parent);
return inst;
}
void dimensions_dialog::add_minifig_slot(QHBoxLayout* layout, u8 pad, u8 index)
{
ensure(index < figure_slots.size());
QVBoxLayout* vbox_layout = new QVBoxLayout();
QHBoxLayout* hbox_name_move = new QHBoxLayout();
QHBoxLayout* hbox_actions = new QHBoxLayout();
QPushButton* clear_btn = new QPushButton(tr("Clear"));
QPushButton* create_btn = new QPushButton(tr("Create"));
QPushButton* load_btn = new QPushButton(tr("Load"));
QPushButton* move_btn = new QPushButton(tr("Move"));
m_edit_figures[index] = new QLineEdit();
m_edit_figures[index]->setEnabled(false);
if (figure_slots[index])
{
const auto found_figure = list_minifigs.find(figure_slots[index].value());
if (found_figure != list_minifigs.cend())
{
m_edit_figures[index]->setText(QString::fromStdString(found_figure->second));
}
else
{
m_edit_figures[index]->setText(tr("Unknown Figure"));
}
}
else
{
m_edit_figures[index]->setText(tr("None"));
}
connect(clear_btn, &QAbstractButton::clicked, this, [this, pad, index]
{
clear_figure(pad, index);
});
connect(create_btn, &QAbstractButton::clicked, this, [this, pad, index]
{
create_figure(pad, index);
});
connect(load_btn, &QAbstractButton::clicked, this, [this, pad, index]
{
load_figure(pad, index);
});
connect(move_btn, &QAbstractButton::clicked, this, [this, pad, index]
{
if (figure_slots[index])
{
move_figure(pad, index);
}
});
hbox_name_move->addWidget(m_edit_figures[index]);
hbox_name_move->addWidget(move_btn);
hbox_actions->addWidget(clear_btn);
hbox_actions->addWidget(create_btn);
hbox_actions->addWidget(load_btn);
vbox_layout->addLayout(hbox_name_move);
vbox_layout->addLayout(hbox_actions);
layout->addLayout(vbox_layout);
}
void dimensions_dialog::clear_figure(u8 pad, u8 index)
{
ensure(index < figure_slots.size());
if (figure_slots[index])
{
g_dimensionstoypad.remove_figure(pad, index, true, true);
figure_slots[index] = std::nullopt;
m_edit_figures[index]->setText(tr("None"));
}
}
void dimensions_dialog::create_figure(u8 pad, u8 index)
{
ensure(index < figure_slots.size());
minifig_creator_dialog create_dlg(this);
if (create_dlg.exec() == Accepted)
{
load_figure_path(pad, index, create_dlg.get_file_path());
}
}
void dimensions_dialog::load_figure(u8 pad, u8 index)
{
ensure(index < figure_slots.size());
const QString file_path = QFileDialog::getOpenFileName(this, tr("Select Dimensions File"), s_last_figure_path, tr("Dimensions Figure (*.bin);;"));
if (file_path.isEmpty())
{
return;
}
s_last_figure_path = QFileInfo(file_path).absolutePath() + "/";
load_figure_path(pad, index, file_path);
}
void dimensions_dialog::move_figure(u8 pad, u8 index)
{
ensure(index < figure_slots.size());
minifig_move_dialog move_dlg(this, index);
g_dimensionstoypad.temp_remove(index);
if (move_dlg.exec() == Accepted)
{
g_dimensionstoypad.move_figure(move_dlg.get_new_pad(), move_dlg.get_new_index(), pad, index);
if (index != move_dlg.get_new_index())
{
figure_slots[move_dlg.get_new_index()] = figure_slots[index];
m_edit_figures[move_dlg.get_new_index()]->setText(m_edit_figures[index]->text());
figure_slots[index] = std::nullopt;
m_edit_figures[index]->setText(tr("None"));
}
}
else
{
g_dimensionstoypad.cancel_remove(index);
}
}
void dimensions_dialog::load_figure_path(u8 pad, u8 index, const QString& path)
{
fs::file dim_file(path.toStdString(), fs::read + fs::write + fs::lock);
if (!dim_file)
{
QMessageBox::warning(this, tr("Failed to open the figure file!"), tr("Failed to open the figure file(%1)!\nFile may already be in use on the base.").arg(path), QMessageBox::Ok);
return;
}
std::array<u8, 0x2D * 0x04> data;
if (dim_file.read(data.data(), data.size()) != data.size())
{
QMessageBox::warning(this, tr("Failed to read the figure file!"), tr("Failed to read the figure file(%1)!\nFile was too small.").arg(path), QMessageBox::Ok);
return;
}
clear_figure(pad, index);
const u32 fig_num = g_dimensionstoypad.load_figure(data, std::move(dim_file), pad, index, true);
figure_slots[index] = fig_num;
const auto name = list_minifigs.find(fig_num);
if (name != list_minifigs.cend())
{
m_edit_figures[index]->setText(QString::fromStdString(name->second));
}
else
{
const auto blank_name = list_tokens.find(fig_num);
if (blank_name != list_tokens.cend())
{
m_edit_figures[index]->setText(QString::fromStdString(blank_name->second));
}
else
{
m_edit_figures[index]->setText("Blank Tag");
}
}
}

View file

@ -1,63 +0,0 @@
#pragma once
#include "util/types.hpp"
#include <QDialog>
#include <QLineEdit>
#include <QGridLayout>
class minifig_creator_dialog : public QDialog
{
Q_OBJECT
public:
explicit minifig_creator_dialog(QWidget* parent);
QString get_file_path() const;
protected:
QString m_file_path;
};
class minifig_move_dialog : public QDialog
{
Q_OBJECT
public:
explicit minifig_move_dialog(QWidget* parent, u8 old_index);
u8 get_new_pad() const;
u8 get_new_index() const;
protected:
u8 m_pad = 0;
u8 m_index = 0;
private:
void add_minifig_position(QGridLayout* grid_panel, u8 index, u8 row, u8 column, u8 old_index);
};
class dimensions_dialog : public QDialog
{
Q_OBJECT
public:
explicit dimensions_dialog(QWidget* parent);
~dimensions_dialog();
static dimensions_dialog* get_dlg(QWidget* parent);
dimensions_dialog(dimensions_dialog const&) = delete;
void operator=(dimensions_dialog const&) = delete;
protected:
void clear_figure(u8 pad, u8 index);
void create_figure(u8 pad, u8 index);
void load_figure(u8 pad, u8 index);
void move_figure(u8 pad, u8 index);
void load_figure_path(u8 pad, u8 index, const QString& path);
protected:
std::array<QLineEdit*, 7> m_edit_figures{};
private:
void add_minifig_slot(QHBoxLayout* layout, u8 pad, u8 index);
static dimensions_dialog* inst;
};

View file

@ -1,96 +0,0 @@
#include "display_sleep_control.h"
#ifdef _WIN32
#include <windows.h>
#elif defined(__APPLE__)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wold-style-cast"
#include <IOKit/pwr_mgt/IOPMLib.h>
#pragma GCC diagnostic pop
static IOPMAssertionID s_pm_assertion = kIOPMNullAssertionID;
#elif defined(HAVE_QTDBUS)
#include <QtDBus/QDBusConnection>
#include <QtDBus/QDBusInterface>
#include <QtDBus/QDBusMessage>
#include <QDBusReply>
#include "util/types.hpp"
static u32 s_dbus_cookie = 0;
#endif
bool display_sleep_control_supported()
{
#if defined(_WIN32) || defined(__APPLE__)
return true;
#elif defined(HAVE_QTDBUS)
for (const char* service : {"org.freedesktop.ScreenSaver", "org.mate.ScreenSaver"})
{
QDBusInterface interface(service, "/ScreenSaver", service, QDBusConnection::sessionBus());
if (interface.isValid())
{
return true;
}
}
return false;
#else
return false;
#endif
}
void enable_display_sleep(bool enabled)
{
if (!display_sleep_control_supported())
{
return;
}
#ifdef _WIN32
SetThreadExecutionState(enabled ? ES_CONTINUOUS : (ES_CONTINUOUS | ES_SYSTEM_REQUIRED | ES_DISPLAY_REQUIRED));
#elif defined(__APPLE__)
if (enabled && s_pm_assertion != kIOPMNullAssertionID)
{
IOPMAssertionRelease(s_pm_assertion);
s_pm_assertion = kIOPMNullAssertionID;
}
else if (!enabled)
{
#pragma GCC diagnostic push
// Necessary as some of those values are macro using old casts
#pragma GCC diagnostic ignored "-Wold-style-cast"
IOPMAssertionCreateWithName(kIOPMAssertionTypePreventUserIdleDisplaySleep, kIOPMAssertionLevelOn, CFSTR("Game running"), &s_pm_assertion);
#pragma GCC diagnostic pop
}
#elif defined(HAVE_QTDBUS)
if (enabled && s_dbus_cookie != 0)
{
for (const char* service : {"org.freedesktop.ScreenSaver", "org.mate.ScreenSaver"})
{
QDBusInterface interface(service, "/ScreenSaver", service, QDBusConnection::sessionBus());
if (interface.isValid())
{
interface.call("UnInhibit", s_dbus_cookie);
break;
}
}
s_dbus_cookie = 0;
}
else if (!enabled)
{
for (const char* service : {"org.freedesktop.ScreenSaver", "org.mate.ScreenSaver"})
{
QDBusInterface interface(service, "/ScreenSaver", service, QDBusConnection::sessionBus());
if (interface.isValid())
{
QDBusReply<u32> reply = interface.call("Inhibit", "rpcs3", "Game running");
if (reply.isValid())
{
s_dbus_cookie = reply.value();
}
break;
}
}
}
#endif
}

View file

@ -1,4 +0,0 @@
#pragma once
bool display_sleep_control_supported();
void enable_display_sleep(bool enabled);

View file

@ -1,204 +0,0 @@
#include <QApplication>
#include <QThread>
#include "downloader.h"
#include "curl_handle.h"
#include "progress_dialog.h"
#include "util/logs.hpp"
LOG_CHANNEL(network_log, "NET");
usz curl_write_cb_compat(char* ptr, usz /*size*/, usz nmemb, void* userdata)
{
downloader* download = static_cast<downloader*>(userdata);
return download->update_buffer(ptr, nmemb);
}
downloader::downloader(QWidget* parent)
: QObject(parent), m_parent(parent), m_curl(new rpcs3::curl::curl_handle())
{
}
downloader::~downloader()
{
if (m_thread && m_thread->isRunning())
{
m_curl_abort = true;
m_thread->wait();
}
}
void downloader::start(const std::string& url, bool follow_location, bool show_progress_dialog, const QString& progress_dialog_title, bool keep_progress_dialog_open, int expected_size)
{
network_log.notice("Starting download from URL: %s", url);
if (m_thread)
{
if (m_thread->isRunning())
{
m_curl_abort = true;
m_thread->wait();
}
m_thread->deleteLater();
}
m_keep_progress_dialog_open = keep_progress_dialog_open;
m_curl_buf.clear();
m_curl_abort = false;
CURLcode err = curl_easy_setopt(m_curl->get_curl(), CURLOPT_URL, url.c_str());
if (err != CURLE_OK)
network_log.error("curl_easy_setopt(CURLOPT_URL, %s) error: %s", url, curl_easy_strerror(err));
err = curl_easy_setopt(m_curl->get_curl(), CURLOPT_WRITEFUNCTION, curl_write_cb_compat);
if (err != CURLE_OK)
network_log.error("curl_easy_setopt(CURLOPT_WRITEFUNCTION, curl_write_cb_compat) error: %s", curl_easy_strerror(err));
err = curl_easy_setopt(m_curl->get_curl(), CURLOPT_WRITEDATA, this);
if (err != CURLE_OK)
network_log.error("curl_easy_setopt(CURLOPT_WRITEDATA) error: %s", curl_easy_strerror(err));
err = curl_easy_setopt(m_curl->get_curl(), CURLOPT_FOLLOWLOCATION, follow_location ? 1 : 0);
if (err != CURLE_OK)
network_log.error("curl_easy_setopt(CURLOPT_FOLLOWLOCATION, %d) error: %s", follow_location, curl_easy_strerror(err));
m_thread = QThread::create([this]
{
// Reset error buffer before we call curl_easy_perform
m_curl->reset_error_buffer();
const CURLcode result = curl_easy_perform(m_curl->get_curl());
m_curl_success = result == CURLE_OK;
if (!m_curl_success && !m_curl_abort)
{
const std::string error = fmt::format("curl_easy_perform(): %s", m_curl->get_verbose_error(result));
network_log.error("%s", error);
Q_EMIT signal_download_error(QString::fromStdString(error));
}
});
connect(m_thread, &QThread::finished, this, [this]()
{
if (m_curl_abort)
{
network_log.notice("Download aborted");
return;
}
if (!m_keep_progress_dialog_open || !m_curl_success)
{
close_progress_dialog();
}
if (m_curl_success)
{
network_log.notice("Download finished");
Q_EMIT signal_download_finished(m_curl_buf);
}
});
// The downloader's signals are expected to be disconnected and customized before start is called.
// Therefore we need to (re)connect its signal(s) here and not in the constructor.
connect(this, &downloader::signal_buffer_update, this, &downloader::handle_buffer_update);
if (show_progress_dialog)
{
const int maximum = expected_size > 0 ? expected_size : 100;
if (m_progress_dialog)
{
m_progress_dialog->setWindowTitle(progress_dialog_title);
m_progress_dialog->setAutoClose(!m_keep_progress_dialog_open);
m_progress_dialog->SetRange(0, maximum);
}
else
{
m_progress_dialog = new progress_dialog(progress_dialog_title, tr("Please wait..."), tr("Abort"), 0, maximum, true, m_parent);
m_progress_dialog->setAutoReset(false);
m_progress_dialog->setAutoClose(!m_keep_progress_dialog_open);
m_progress_dialog->show();
// Handle abort
connect(m_progress_dialog, &QProgressDialog::canceled, this, [this]()
{
m_curl_abort = true;
m_progress_dialog = nullptr; // The progress dialog deletes itself on close
Q_EMIT signal_download_canceled();
});
connect(m_progress_dialog, &QProgressDialog::finished, this, [this]()
{
m_progress_dialog = nullptr; // The progress dialog deletes itself on close
});
}
}
m_thread->setObjectName("Download Thread");
m_thread->setParent(this);
m_thread->start();
}
void downloader::update_progress_dialog(const QString& title) const
{
if (m_progress_dialog)
{
m_progress_dialog->setWindowTitle(title);
}
}
void downloader::close_progress_dialog()
{
if (m_progress_dialog)
{
m_progress_dialog->accept();
m_progress_dialog = nullptr;
}
}
progress_dialog* downloader::get_progress_dialog() const
{
return m_progress_dialog;
}
usz downloader::update_buffer(char* data, usz size)
{
if (m_curl_abort)
{
return 0;
}
const auto old_size = m_curl_buf.size();
const auto new_size = old_size + size;
m_curl_buf.resize(static_cast<int>(new_size));
memcpy(m_curl_buf.data() + old_size, data, size);
int max = 0;
if (m_actual_download_size < 0)
{
if (curl_easy_getinfo(m_curl->get_curl(), CURLINFO_CONTENT_LENGTH_DOWNLOAD_T, &m_actual_download_size) == CURLE_OK && m_actual_download_size > 0)
{
max = static_cast<int>(m_actual_download_size);
}
}
Q_EMIT signal_buffer_update(static_cast<int>(new_size), max);
return size;
}
void downloader::handle_buffer_update(int size, int max) const
{
if (m_curl_abort)
{
return;
}
if (m_progress_dialog)
{
m_progress_dialog->SetRange(0, max > 0 ? max : m_progress_dialog->maximum());
m_progress_dialog->SetValue(size);
QApplication::processEvents();
}
}

View file

@ -1,55 +0,0 @@
#pragma once
#include <QObject>
#include "util/atomic.hpp"
namespace rpcs3
{
namespace curl
{
class curl_handle;
}
} // namespace rpcs3
class progress_dialog;
class downloader : public QObject
{
Q_OBJECT
public:
explicit downloader(QWidget* parent = nullptr);
~downloader();
void start(const std::string& url, bool follow_location, bool show_progress_dialog, const QString& progress_dialog_title = "", bool keep_progress_dialog_open = false, int expected_size = -1);
usz update_buffer(char* data, usz size);
void update_progress_dialog(const QString& title) const;
void close_progress_dialog();
progress_dialog* get_progress_dialog() const;
private Q_SLOTS:
void handle_buffer_update(int size, int max) const;
Q_SIGNALS:
void signal_download_error(const QString& error);
void signal_download_finished(const QByteArray& data);
void signal_download_canceled();
void signal_buffer_update(int size, int max);
private:
QWidget* m_parent = nullptr;
std::unique_ptr<rpcs3::curl::curl_handle> m_curl;
QByteArray m_curl_buf;
atomic_t<bool> m_curl_abort = false;
atomic_t<bool> m_curl_success = false;
double m_actual_download_size = -1.0;
progress_dialog* m_progress_dialog = nullptr;
atomic_t<bool> m_keep_progress_dialog_open = false;
QString m_progress_dialog_title;
QThread* m_thread = nullptr;
};

View file

@ -1,222 +0,0 @@
#include "elf_memory_dumping_dialog.h"
#include "Emu/Cell/SPUThread.h"
#include "qt_utils.h"
#include <QFileDialog>
#include <QCoreApplication>
#include <QFontDatabase>
#include <QHBoxLayout>
#include <QPushButton>
#include <QMessageBox>
#include <QLineEdit>
#include <QLabel>
LOG_CHANNEL(gui_log, "GUI");
Q_DECLARE_METATYPE(spu_memory_segment_dump_data);
elf_memory_dumping_dialog::elf_memory_dumping_dialog(u32 ppu_debugger_addr, std::shared_ptr<gui_settings> _gui_settings, QWidget* parent)
: QDialog(parent), m_gui_settings(std::move(_gui_settings))
{
setWindowTitle(tr("SPU ELF Dumper"));
setAttribute(Qt::WA_DeleteOnClose);
m_seg_list = new QListWidget();
// Font
const int pSize = 10;
QFont mono = QFontDatabase::systemFont(QFontDatabase::FixedFont);
mono.setPointSize(pSize);
m_seg_list->setMinimumWidth(gui::utils::get_label_width(tr("PPU Address: 0x00000000, LS Address: 0x00000, Segment Size: 0x00000, Flags: 0x0")));
// Address expression input
auto make_hex_edit = [this, mono](u32 max_digits)
{
QLineEdit* le = new QLineEdit();
le->setFont(mono);
le->setMaxLength(max_digits + 2);
le->setPlaceholderText("0x" + QStringLiteral("0").repeated(max_digits));
le->setValidator(new QRegularExpressionValidator(QRegularExpression(QStringLiteral("^(0[xX])?0*[a-fA-F0-9]{0,%1}$").arg(max_digits)), this));
return le;
};
m_segment_size_input = make_hex_edit(5);
m_ppu_address_input = make_hex_edit(8);
m_ls_address_input = make_hex_edit(5);
m_segment_flags_input = make_hex_edit(1);
m_segment_flags_input->setText("0x7"); // READ WRITE EXEC
m_ppu_address_input->setText(QStringLiteral("0x%1").arg(ppu_debugger_addr & -0x10000, 1, 16)); // SPU code segments are usually 128 bytes aligned, let's make it even 64k so the user would have to type himself the lower part to avoid human errors.
QPushButton* add_segment_button = new QPushButton(QStringLiteral("+"));
add_segment_button->setToolTip(tr("Add new segment"));
add_segment_button->setFixedWidth(add_segment_button->sizeHint().height()); // Make button square
connect(add_segment_button, &QAbstractButton::clicked, this, &elf_memory_dumping_dialog::add_new_segment);
QPushButton* remove_segment_button = new QPushButton(QStringLiteral("-"));
remove_segment_button->setToolTip(tr("Remove segment"));
remove_segment_button->setFixedWidth(remove_segment_button->sizeHint().height()); // Make button square
remove_segment_button->setEnabled(false);
connect(remove_segment_button, &QAbstractButton::clicked, this, &elf_memory_dumping_dialog::remove_segment);
QPushButton* save_to_file = new QPushButton(tr("Save To ELF"));
save_to_file->setToolTip(tr("Save To An ELF file"));
connect(save_to_file, &QAbstractButton::clicked, this, &elf_memory_dumping_dialog::save_to_file);
QHBoxLayout* hbox_input = new QHBoxLayout;
hbox_input->addWidget(new QLabel(tr("Segment Size:")));
hbox_input->addWidget(m_segment_size_input);
hbox_input->addSpacing(5);
hbox_input->addWidget(new QLabel(tr("PPU Address:")));
hbox_input->addWidget(m_ppu_address_input);
hbox_input->addSpacing(5);
hbox_input->addWidget(new QLabel(tr("LS Address:")));
hbox_input->addWidget(m_ls_address_input);
hbox_input->addSpacing(5);
hbox_input->addWidget(new QLabel(tr("Flags:")));
hbox_input->addWidget(m_segment_flags_input);
QHBoxLayout* hbox_save_and_edit = new QHBoxLayout;
hbox_save_and_edit->addStretch(2);
hbox_save_and_edit->addWidget(add_segment_button);
hbox_save_and_edit->addSpacing(4);
hbox_save_and_edit->addWidget(remove_segment_button);
hbox_save_and_edit->addSpacing(4);
hbox_save_and_edit->addWidget(save_to_file);
QVBoxLayout* vbox = new QVBoxLayout();
vbox->addLayout(hbox_input);
vbox->addSpacing(5);
vbox->addWidget(m_seg_list);
vbox->addSpacing(5);
vbox->addLayout(hbox_save_and_edit);
setLayout(vbox);
connect(m_seg_list, &QListWidget::currentRowChanged, this, [this, remove_segment_button](int row)
{
remove_segment_button->setEnabled(row >= 0 && m_seg_list->item(row));
});
show();
}
void elf_memory_dumping_dialog::add_new_segment()
{
QStringList errors;
auto interpret = [&](QString text, QString error_field) -> u32
{
bool ok = false;
// Parse expression (or at least used to, was nuked to remove the need for QtJsEngine)
const QString fixed_expression = QRegularExpression(QRegularExpression::anchoredPattern("a .*|^[A-Fa-f0-9]+$")).match(text).hasMatch() ? "0x" + text : text;
const u32 res = static_cast<u32>(fixed_expression.toULong(&ok, 16));
if (!ok)
{
errors << error_field;
return umax;
}
return res;
};
spu_memory_segment_dump_data data{};
data.segment_size = interpret(m_segment_size_input->text(), tr("Segment Size"));
data.src_addr = vm::get_super_ptr(interpret(m_ppu_address_input->text(), tr("PPU Address")));
data.ls_addr = interpret(m_ls_address_input->text(), tr("LS Address"));
data.flags = interpret(m_segment_flags_input->text(), tr("Segment Flags"));
if (!errors.isEmpty())
{
QMessageBox::warning(this, tr("Failed To Add Segment"), tr("Segment parameters are incorrect:\n%1").arg(errors.join('\n')));
return;
}
if (data.segment_size % 4)
{
QMessageBox::warning(this, tr("Failed To Add Segment"), tr("SPU segment size must be 4 bytes aligned."));
return;
}
if (data.segment_size + data.ls_addr > SPU_LS_SIZE || data.segment_size == 0 || data.segment_size % 4)
{
QMessageBox::warning(this, tr("Failed To Add Segment"), tr("SPU segment range is invalid."));
return;
}
if (!vm::check_addr(vm::try_get_addr(data.src_addr).first, vm::page_readable, data.segment_size))
{
QMessageBox::warning(this, tr("Failed To Add Segment"), tr("PPU address range is not accessible."));
return;
}
for (int i = 0; i < m_seg_list->count(); ++i)
{
ensure(m_seg_list->item(i)->data(Qt::UserRole).canConvert<spu_memory_segment_dump_data>());
const auto seg_stored = m_seg_list->item(i)->data(Qt::UserRole).value<spu_memory_segment_dump_data>();
const auto stored_max = seg_stored.src_addr + seg_stored.segment_size;
const auto data_max = data.src_addr + data.segment_size;
if (seg_stored.src_addr < data_max && data.src_addr < stored_max)
{
QMessageBox::warning(this, tr("Failed To Add Segment"), tr("SPU segment overlaps with previous SPU segment(s)\n"));
return;
}
}
auto item = new QListWidgetItem(tr("PPU Address: 0x%0, LS Address: 0x%1, Segment Size: 0x%2, Flags: 0x%3").arg(+vm::try_get_addr(data.src_addr).first, 5, 16).arg(data.ls_addr, 2, 16).arg(data.segment_size, 2, 16).arg(data.flags, 2, 16), m_seg_list);
item->setData(Qt::UserRole, QVariant::fromValue(data));
m_seg_list->setCurrentItem(item);
}
void elf_memory_dumping_dialog::remove_segment()
{
const int row = m_seg_list->currentRow();
if (row >= 0)
{
QListWidgetItem* item = m_seg_list->takeItem(row);
delete item;
}
}
void elf_memory_dumping_dialog::save_to_file()
{
std::vector<spu_memory_segment_dump_data> segs;
segs.reserve(m_seg_list->count());
for (int i = 0; i < m_seg_list->count(); ++i)
{
ensure(m_seg_list->item(i)->data(Qt::UserRole).canConvert<spu_memory_segment_dump_data>());
const auto seg_stored = m_seg_list->item(i)->data(Qt::UserRole).value<spu_memory_segment_dump_data>();
segs.emplace_back(seg_stored);
}
if (segs.empty())
{
return;
}
const QString path_last_elf = m_gui_settings->GetValue(gui::fd_save_elf).toString();
const QString qpath = QFileDialog::getSaveFileName(this, tr("Capture"), path_last_elf, "SPU ELF (*.elf)");
const std::string path = qpath.toStdString();
if (!path.empty())
{
const auto result = spu_thread::capture_memory_as_elf({segs.data(), segs.size()}).save();
if (!result.empty() && fs::write_file(path, fs::rewrite, result))
{
gui_log.success("Saved ELF at %s", path);
m_gui_settings->SetValue(gui::fd_save_elf, qpath);
}
else
{
QMessageBox::warning(this, tr("Save Failure"), tr("Failed to save SPU ELF."));
}
}
}

View file

@ -1,33 +0,0 @@
#pragma once
#include "util/types.hpp"
#include "gui_settings.h"
#include <QListWidget>
#include <QLineEdit>
#include <QDialog>
#include <memory>
class elf_memory_dumping_dialog : public QDialog
{
Q_OBJECT
public:
explicit elf_memory_dumping_dialog(u32 ppu_debugger_pc, std::shared_ptr<gui_settings> _gui_settings, QWidget* parent = nullptr);
protected:
void add_new_segment();
void remove_segment();
void save_to_file();
std::shared_ptr<gui_settings> m_gui_settings;
// UI variables needed in higher scope
QListWidget* m_seg_list = nullptr;
QLineEdit* m_ls_address_input = nullptr;
QLineEdit* m_segment_size_input = nullptr;
QLineEdit* m_ppu_address_input = nullptr;
QLineEdit* m_segment_flags_input = nullptr;
};

File diff suppressed because it is too large Load diff

View file

@ -1,130 +0,0 @@
#pragma once
#include "util/types.hpp"
#include "util/yaml.hpp"
#include "microphone_creator.h"
#include "midi_creator.h"
#include "render_creator.h"
#include "emu_settings_type.h"
#include <QButtonGroup>
#include <QCheckBox>
#include <QStringList>
#include <QComboBox>
#include <QSpinBox>
#include <QDateTimeEdit>
#include <string>
#include <vector>
namespace cfg
{
class _base;
}
constexpr auto qstr = QString::fromStdString;
class emu_settings : public QObject
{
/** A settings class for Emulator specific settings. This class is a refactored version of the wx version. It is much nicer
*
*/
Q_OBJECT
public:
std::set<emu_settings_type> m_broken_types; // list of broken settings
/** Creates a settings object which reads in the config.yml file at rpcs3/bin/%path%/config.yml
* Settings are only written when SaveSettings is called.
*/
emu_settings();
bool Init();
/** Connects a combo box with the target settings type*/
void EnhanceComboBox(QComboBox* combobox, emu_settings_type type, bool is_ranged = false, bool use_max = false, int max = 0, bool sorted = false, bool strict = true);
/** Connects a check box with the target settings type*/
void EnhanceCheckBox(QCheckBox* checkbox, emu_settings_type type);
/** Connects a date time edit box with the target settings type*/
void EnhanceDateTimeEdit(QDateTimeEdit* date_time_edit, emu_settings_type type, const QString& format, bool use_calendar, bool as_offset_from_now, int offset_update_time = 0);
/** Connects a slider with the target settings type*/
void EnhanceSlider(QSlider* slider, emu_settings_type type);
/** Connects an integer spin box with the target settings type*/
void EnhanceSpinBox(QSpinBox* spinbox, emu_settings_type type, const QString& prefix = "", const QString& suffix = "");
/** Connects a double spin box with the target settings type*/
void EnhanceDoubleSpinBox(QDoubleSpinBox* spinbox, emu_settings_type type, const QString& prefix = "", const QString& suffix = "");
/** Connects a line edit with the target settings type*/
void EnhanceLineEdit(QLineEdit* edit, emu_settings_type type);
/** Connects a button group with the target settings type*/
void EnhanceRadioButton(QButtonGroup* button_group, emu_settings_type type);
std::vector<std::string> GetLibrariesControl();
void SaveSelectedLibraries(const std::vector<std::string>& libs);
/** Returns the valid options for a given setting.*/
static std::vector<std::string> GetSettingOptions(emu_settings_type type);
/** Returns the valid options for a given setting.*/
static QStringList GetQStringSettingOptions(emu_settings_type type);
/** Returns the default value of the setting type.*/
std::string GetSettingDefault(emu_settings_type type) const;
/** Returns the value of the setting type.*/
std::string GetSetting(emu_settings_type type) const;
/** Sets the setting type to a given value.*/
void SetSetting(emu_settings_type type, const std::string& val) const;
/** Try to find the settings type for a given string.*/
emu_settings_type FindSettingsType(const cfg::_base* node) const;
/** Gets all the renderer info for gpu settings.*/
render_creator* m_render_creator = nullptr;
/** Gets a list of all the microphones available.*/
microphone_creator m_microphone_creator;
/** Gets a list of all the midi devices available.*/
midi_creator m_midi_creator;
/** Loads the settings from path.*/
void LoadSettings(const std::string& title_id = "", bool create_config_from_global = true);
/** Fixes all registered invalid settings after asking the user for permission.*/
void OpenCorrectionDialog(QWidget* parent = Q_NULLPTR);
/** Get a localized and therefore freely adjustable version of the string used in config.yml.*/
QString GetLocalizedSetting(const QString& original, emu_settings_type type, int index, bool strict) const;
/** Get a localized and therefore freely adjustable version of the string used in config.yml.*/
std::string GetLocalizedSetting(const std::string& original, emu_settings_type type, int index, bool strict) const;
/** Get a localized and therefore freely adjustable version of the string used in config.yml.*/
std::string GetLocalizedSetting(const cfg::_base* node, u32 index) const;
/** Validates the settings and logs unused entries or cleans up the yaml*/
bool ValidateSettings(bool cleanup);
/** Resets the current settings to the global default. This includes all connected widgets. */
void RestoreDefaults();
Q_SIGNALS:
void RestoreDefaultsSignal();
public Q_SLOTS:
/** Writes the unsaved settings to file. Used in settings dialog on accept.*/
void SaveSettings() const;
private:
YAML::Node m_default_settings; // The default settings as a YAML node.
YAML::Node m_current_settings; // The current settings as a YAML node.
std::string m_title_id;
};

View file

@ -1,414 +0,0 @@
#pragma once
#include <map>
#include <vector>
// Node location
using cfg_location = std::vector<const char*>;
enum class emu_settings_type
{
// Core
PPUDecoder,
SPUDecoder,
HookStaticFuncs,
ThreadSchedulerMode,
SPULoopDetection,
PreferredSPUThreads,
PPUDebug,
SPUDebug,
MFCDebug,
MaxLLVMThreads,
LLVMPrecompilation,
EnableTSX,
AccurateSpuDMA,
AccurateClineStores,
AccurateRSXAccess,
FIFOAccuracy,
XFloatAccuracy,
AccuratePPU128Loop,
MFCCommandsShuffling,
NumPPUThreads,
SetDAZandFTZ,
SPUBlockSize,
SPUCache,
DebugConsoleMode,
SilenceAllLogs,
SuspendEmulationSavestateMode,
CompatibleEmulationSavestateMode,
StartSavestatePaused,
MaxSPURSThreads,
SleepTimersAccuracy,
ClocksScale,
PerformanceReport,
FullWidthAVX512,
PPUNJFixup,
AccurateDFMA,
AccuratePPUSAT,
AccuratePPUNJ,
FixupPPUVNAN,
AccuratePPUVNAN,
AccuratePPUFPCC,
MaxPreemptCount,
SPUProfiler,
DisableSpinOptimization,
// Graphics
Renderer,
Resolution,
AspectRatio,
FrameLimit,
MSAA,
LogShaderPrograms,
WriteDepthBuffer,
WriteColorBuffers,
ReadColorBuffers,
ReadDepthBuffer,
HandleRSXTiledMemory,
VSync,
DebugOutput,
DebugOverlay,
RenderdocCompatibility,
GPUTextureScaling,
StretchToDisplayArea,
VulkanAdapter,
ForceHighpZ,
StrictRenderingMode,
DisableVertexCache,
DisableOcclusionQueries,
DisableVideoOutput,
DisableFIFOReordering,
StrictTextureFlushing,
ShaderPrecisionQuality,
StereoRenderMode,
AnisotropicFilterOverride,
TextureLodBias,
ResolutionScale,
MinimumScalableDimension,
FsrSharpeningStrength,
ExclusiveFullscreenMode,
ForceCPUBlitEmulation,
DisableOnDiskShaderCache,
DisableVulkanMemAllocator,
ShaderMode,
ShaderCompilerNumThreads,
MultithreadedRSX,
VBlankRate,
VBlankNTSCFixup,
RelaxedZCULL,
PreciseZCULL,
DriverWakeUpDelay,
VulkanAsyncTextureUploads,
VulkanAsyncSchedulerDriver,
AllowHostGPULabels,
DisableMSLFastMath,
OutputScalingMode,
ForceHwMSAAResolve,
DisableAsyncHostMM,
// Performance Overlay
PerfOverlayEnabled,
PerfOverlayFramerateGraphEnabled,
PerfOverlayFrametimeGraphEnabled,
PerfOverlayFramerateDatapoints,
PerfOverlayFrametimeDatapoints,
PerfOverlayDetailLevel,
PerfOverlayFramerateDetailLevel,
PerfOverlayFrametimeDetailLevel,
PerfOverlayPosition,
PerfOverlayUpdateInterval,
PerfOverlayFontSize,
PerfOverlayOpacity,
PerfOverlayMarginX,
PerfOverlayMarginY,
PerfOverlayCenterX,
PerfOverlayCenterY,
// Shader Loading Dialog
ShaderLoadBgEnabled,
ShaderLoadBgDarkening,
ShaderLoadBgBlur,
// Audio
AudioRenderer,
DumpToFile,
ConvertTo16Bit,
AudioFormat,
AudioFormats,
AudioProvider,
AudioAvport,
AudioDevice,
AudioChannelLayout,
MasterVolume,
EnableBuffering,
AudioBufferDuration,
EnableTimeStretching,
TimeStretchingThreshold,
MicrophoneType,
MicrophoneDevices,
MusicHandler,
// Input / Output
BackgroundInput,
ShowMoveCursor,
LockOvlIptToP1,
PadHandlerMode,
PadConnection,
KeyboardHandler,
MouseHandler,
Camera,
CameraType,
CameraFlip,
CameraID,
Move,
Buzz,
Turntable,
GHLtar,
MidiDevices,
SDLMappings,
IoDebugOverlay,
// Misc
ExitRPCS3OnFinish,
StartOnBoot,
PauseOnFocusLoss,
StartGameFullscreen,
PreventDisplaySleep,
ShowTrophyPopups,
ShowRpcnPopups,
UseNativeInterface,
ShowShaderCompilationHint,
ShowPPUCompilationHint,
ShowAutosaveAutoloadHint,
ShowPressureIntensityToggleHint,
ShowAnalogLimiterToggleHint,
ShowMouseAndKeyboardToggleHint,
WindowTitleFormat,
PauseDuringHomeMenu,
// Network
InternetStatus,
DNSAddress,
IpSwapList,
PSNStatus,
BindAddress,
EnableUpnp,
PSNCountry,
// System
LicenseArea,
Language,
KeyboardType,
EnterButtonAssignment,
EnableHostRoot,
EmptyHdd0Tmp,
LimitCacheSize,
MaximumCacheSize,
ConsoleTimeOffset,
};
/** A helper map that keeps track of where a given setting type is located*/
inline static const std::map<emu_settings_type, cfg_location> settings_location =
{
// Core Tab
{emu_settings_type::PPUDecoder, {"Core", "PPU Decoder"}},
{emu_settings_type::SPUDecoder, {"Core", "SPU Decoder"}},
{emu_settings_type::HookStaticFuncs, {"Core", "Hook static functions"}},
{emu_settings_type::ThreadSchedulerMode, {"Core", "Thread Scheduler Mode"}},
{emu_settings_type::SPULoopDetection, {"Core", "SPU loop detection"}},
{emu_settings_type::PreferredSPUThreads, {"Core", "Preferred SPU Threads"}},
{emu_settings_type::PPUDebug, {"Core", "PPU Debug"}},
{emu_settings_type::SPUDebug, {"Core", "SPU Debug"}},
{emu_settings_type::MFCDebug, {"Core", "MFC Debug"}},
{emu_settings_type::MaxLLVMThreads, {"Core", "Max LLVM Compile Threads"}},
{emu_settings_type::LLVMPrecompilation, {"Core", "LLVM Precompilation"}},
{emu_settings_type::EnableTSX, {"Core", "Enable TSX"}},
{emu_settings_type::AccurateSpuDMA, {"Core", "Accurate SPU DMA"}},
{emu_settings_type::AccurateClineStores, {"Core", "Accurate Cache Line Stores"}},
{emu_settings_type::AccurateRSXAccess, {"Core", "Accurate RSX reservation access"}},
{emu_settings_type::FIFOAccuracy, {"Core", "RSX FIFO Accuracy"}},
{emu_settings_type::XFloatAccuracy, {"Core", "XFloat Accuracy"}},
{emu_settings_type::MFCCommandsShuffling, {"Core", "MFC Commands Shuffling Limit"}},
{emu_settings_type::SetDAZandFTZ, {"Core", "Set DAZ and FTZ"}},
{emu_settings_type::SPUBlockSize, {"Core", "SPU Block Size"}},
{emu_settings_type::SPUCache, {"Core", "SPU Cache"}},
{emu_settings_type::DebugConsoleMode, {"Core", "Debug Console Mode"}},
{emu_settings_type::MaxSPURSThreads, {"Core", "Max SPURS Threads"}},
{emu_settings_type::SleepTimersAccuracy, {"Core", "Sleep Timers Accuracy"}},
{emu_settings_type::ClocksScale, {"Core", "Clocks scale"}},
{emu_settings_type::AccuratePPU128Loop, {"Core", "Accurate PPU 128-byte Reservation Op Max Length"}},
{emu_settings_type::PerformanceReport, {"Core", "Enable Performance Report"}},
{emu_settings_type::FullWidthAVX512, {"Core", "Full Width AVX-512"}},
{emu_settings_type::NumPPUThreads, {"Core", "PPU Threads"}},
{emu_settings_type::PPUNJFixup, {"Core", "PPU LLVM Java Mode Handling"}},
{emu_settings_type::AccurateDFMA, {"Core", "Use Accurate DFMA"}},
{emu_settings_type::AccuratePPUSAT, {"Core", "PPU Set Saturation Bit"}},
{emu_settings_type::AccuratePPUNJ, {"Core", "PPU Accurate Non-Java Mode"}},
{emu_settings_type::FixupPPUVNAN, {"Core", "PPU Fixup Vector NaN Values"}},
{emu_settings_type::AccuratePPUVNAN, {"Core", "PPU Accurate Vector NaN Values"}},
{emu_settings_type::AccuratePPUFPCC, {"Core", "PPU Set FPCC Bits"}},
{emu_settings_type::MaxPreemptCount, {"Core", "Max CPU Preempt Count"}},
{emu_settings_type::SPUProfiler, {"Core", "SPU Profiler"}},
{emu_settings_type::DisableSpinOptimization, {"Core", "Disable SPU GETLLAR Spin Optimization"}},
// Graphics Tab
{emu_settings_type::Renderer, {"Video", "Renderer"}},
{emu_settings_type::Resolution, {"Video", "Resolution"}},
{emu_settings_type::AspectRatio, {"Video", "Aspect ratio"}},
{emu_settings_type::FrameLimit, {"Video", "Frame limit"}},
{emu_settings_type::MSAA, {"Video", "MSAA"}},
{emu_settings_type::LogShaderPrograms, {"Video", "Log shader programs"}},
{emu_settings_type::WriteDepthBuffer, {"Video", "Write Depth Buffer"}},
{emu_settings_type::WriteColorBuffers, {"Video", "Write Color Buffers"}},
{emu_settings_type::ReadColorBuffers, {"Video", "Read Color Buffers"}},
{emu_settings_type::ReadDepthBuffer, {"Video", "Read Depth Buffer"}},
{emu_settings_type::HandleRSXTiledMemory, {"Video", "Handle RSX Memory Tiling"}},
{emu_settings_type::VSync, {"Video", "VSync"}},
{emu_settings_type::DebugOutput, {"Video", "Debug output"}},
{emu_settings_type::DebugOverlay, {"Video", "Debug overlay"}},
{emu_settings_type::RenderdocCompatibility, {"Video", "Renderdoc Compatibility Mode"}},
{emu_settings_type::GPUTextureScaling, {"Video", "Use GPU texture scaling"}},
{emu_settings_type::StretchToDisplayArea, {"Video", "Stretch To Display Area"}},
{emu_settings_type::ForceHighpZ, {"Video", "Force High Precision Z buffer"}},
{emu_settings_type::StrictRenderingMode, {"Video", "Strict Rendering Mode"}},
{emu_settings_type::DisableVertexCache, {"Video", "Disable Vertex Cache"}},
{emu_settings_type::DisableOcclusionQueries, {"Video", "Disable ZCull Occlusion Queries"}},
{emu_settings_type::DisableVideoOutput, {"Video", "Disable Video Output"}},
{emu_settings_type::DisableFIFOReordering, {"Video", "Disable FIFO Reordering"}},
{emu_settings_type::StereoRenderMode, {"Video", "3D Display Mode"}},
{emu_settings_type::StrictTextureFlushing, {"Video", "Strict Texture Flushing"}},
{emu_settings_type::ForceCPUBlitEmulation, {"Video", "Force CPU Blit"}},
{emu_settings_type::DisableOnDiskShaderCache, {"Video", "Disable On-Disk Shader Cache"}},
{emu_settings_type::DisableVulkanMemAllocator, {"Video", "Disable Vulkan Memory Allocator"}},
{emu_settings_type::ShaderMode, {"Video", "Shader Mode"}},
{emu_settings_type::ShaderCompilerNumThreads, {"Video", "Shader Compiler Threads"}},
{emu_settings_type::ShaderPrecisionQuality, {"Video", "Shader Precision"}},
{emu_settings_type::MultithreadedRSX, {"Video", "Multithreaded RSX"}},
{emu_settings_type::RelaxedZCULL, {"Video", "Relaxed ZCULL Sync"}},
{emu_settings_type::PreciseZCULL, {"Video", "Accurate ZCULL stats"}},
{emu_settings_type::AnisotropicFilterOverride, {"Video", "Anisotropic Filter Override"}},
{emu_settings_type::TextureLodBias, {"Video", "Texture LOD Bias Addend"}},
{emu_settings_type::ResolutionScale, {"Video", "Resolution Scale"}},
{emu_settings_type::MinimumScalableDimension, {"Video", "Minimum Scalable Dimension"}},
{emu_settings_type::VulkanAdapter, {"Video", "Vulkan", "Adapter"}},
{emu_settings_type::VBlankRate, {"Video", "Vblank Rate"}},
{emu_settings_type::VBlankNTSCFixup, {"Video", "Vblank NTSC Fixup"}},
{emu_settings_type::DriverWakeUpDelay, {"Video", "Driver Wake-Up Delay"}},
{emu_settings_type::AllowHostGPULabels, {"Video", "Allow Host GPU Labels"}},
{emu_settings_type::DisableMSLFastMath, {"Video", "Disable MSL Fast Math"}},
{emu_settings_type::OutputScalingMode, {"Video", "Output Scaling Mode"}},
{emu_settings_type::ForceHwMSAAResolve, {"Video", "Force Hardware MSAA Resolve"}},
{emu_settings_type::DisableAsyncHostMM, {"Video", "Disable Asynchronous Memory Manager"}},
// Vulkan
{emu_settings_type::VulkanAsyncTextureUploads, {"Video", "Vulkan", "Asynchronous Texture Streaming 2"}},
{emu_settings_type::VulkanAsyncSchedulerDriver, {"Video", "Vulkan", "Asynchronous Queue Scheduler"}},
{emu_settings_type::FsrSharpeningStrength, {"Video", "Vulkan", "FidelityFX CAS Sharpening Intensity"}},
{emu_settings_type::ExclusiveFullscreenMode, {"Video", "Vulkan", "Exclusive Fullscreen Mode"}},
// Performance Overlay
{emu_settings_type::PerfOverlayEnabled, {"Video", "Performance Overlay", "Enabled"}},
{emu_settings_type::PerfOverlayFramerateGraphEnabled, {"Video", "Performance Overlay", "Enable Framerate Graph"}},
{emu_settings_type::PerfOverlayFrametimeGraphEnabled, {"Video", "Performance Overlay", "Enable Frametime Graph"}},
{emu_settings_type::PerfOverlayFramerateDatapoints, {"Video", "Performance Overlay", "Framerate datapoints"}},
{emu_settings_type::PerfOverlayFrametimeDatapoints, {"Video", "Performance Overlay", "Frametime datapoints"}},
{emu_settings_type::PerfOverlayDetailLevel, {"Video", "Performance Overlay", "Detail level"}},
{emu_settings_type::PerfOverlayFramerateDetailLevel, {"Video", "Performance Overlay", "Framerate graph detail level"}},
{emu_settings_type::PerfOverlayFrametimeDetailLevel, {"Video", "Performance Overlay", "Frametime graph detail level"}},
{emu_settings_type::PerfOverlayPosition, {"Video", "Performance Overlay", "Position"}},
{emu_settings_type::PerfOverlayUpdateInterval, {"Video", "Performance Overlay", "Metrics update interval (ms)"}},
{emu_settings_type::PerfOverlayFontSize, {"Video", "Performance Overlay", "Font size (px)"}},
{emu_settings_type::PerfOverlayOpacity, {"Video", "Performance Overlay", "Opacity (%)"}},
{emu_settings_type::PerfOverlayMarginX, {"Video", "Performance Overlay", "Horizontal Margin (px)"}},
{emu_settings_type::PerfOverlayMarginY, {"Video", "Performance Overlay", "Vertical Margin (px)"}},
{emu_settings_type::PerfOverlayCenterX, {"Video", "Performance Overlay", "Center Horizontally"}},
{emu_settings_type::PerfOverlayCenterY, {"Video", "Performance Overlay", "Center Vertically"}},
// Shader Loading Dialog
{emu_settings_type::ShaderLoadBgEnabled, {"Video", "Shader Loading Dialog", "Allow custom background"}},
{emu_settings_type::ShaderLoadBgDarkening, {"Video", "Shader Loading Dialog", "Darkening effect strength"}},
{emu_settings_type::ShaderLoadBgBlur, {"Video", "Shader Loading Dialog", "Blur effect strength"}},
// Audio
{emu_settings_type::AudioRenderer, {"Audio", "Renderer"}},
{emu_settings_type::DumpToFile, {"Audio", "Dump to file"}},
{emu_settings_type::ConvertTo16Bit, {"Audio", "Convert to 16 bit"}},
{emu_settings_type::AudioFormat, {"Audio", "Audio Format"}},
{emu_settings_type::AudioFormats, {"Audio", "Audio Formats"}},
{emu_settings_type::AudioProvider, {"Audio", "Audio Provider"}},
{emu_settings_type::AudioAvport, {"Audio", "RSXAudio Avport"}},
{emu_settings_type::AudioDevice, {"Audio", "Audio Device"}},
{emu_settings_type::AudioChannelLayout, {"Audio", "Audio Channel Layout"}},
{emu_settings_type::MasterVolume, {"Audio", "Master Volume"}},
{emu_settings_type::EnableBuffering, {"Audio", "Enable Buffering"}},
{emu_settings_type::AudioBufferDuration, {"Audio", "Desired Audio Buffer Duration"}},
{emu_settings_type::EnableTimeStretching, {"Audio", "Enable Time Stretching"}},
{emu_settings_type::TimeStretchingThreshold, {"Audio", "Time Stretching Threshold"}},
{emu_settings_type::MicrophoneType, {"Audio", "Microphone Type"}},
{emu_settings_type::MicrophoneDevices, {"Audio", "Microphone Devices"}},
{emu_settings_type::MusicHandler, {"Audio", "Music Handler"}},
// Input / Output
{emu_settings_type::BackgroundInput, {"Input/Output", "Background input enabled"}},
{emu_settings_type::ShowMoveCursor, {"Input/Output", "Show move cursor"}},
{emu_settings_type::LockOvlIptToP1, {"Input/Output", "Lock overlay input to player one"}},
{emu_settings_type::PadHandlerMode, {"Input/Output", "Pad handler mode"}},
{emu_settings_type::PadConnection, {"Input/Output", "Keep pads connected"}},
{emu_settings_type::KeyboardHandler, {"Input/Output", "Keyboard"}},
{emu_settings_type::MouseHandler, {"Input/Output", "Mouse"}},
{emu_settings_type::Camera, {"Input/Output", "Camera"}},
{emu_settings_type::CameraType, {"Input/Output", "Camera type"}},
{emu_settings_type::CameraFlip, {"Input/Output", "Camera flip"}},
{emu_settings_type::CameraID, {"Input/Output", "Camera ID"}},
{emu_settings_type::Move, {"Input/Output", "Move"}},
{emu_settings_type::Buzz, {"Input/Output", "Buzz emulated controller"}},
{emu_settings_type::Turntable, {"Input/Output", "Turntable emulated controller"}},
{emu_settings_type::GHLtar, {"Input/Output", "GHLtar emulated controller"}},
{emu_settings_type::MidiDevices, {"Input/Output", "Emulated Midi devices"}},
{emu_settings_type::SDLMappings, {"Input/Output", "Load SDL GameController Mappings"}},
{emu_settings_type::IoDebugOverlay, {"Input/Output", "IO Debug overlay"}},
// Misc
{emu_settings_type::ExitRPCS3OnFinish, {"Miscellaneous", "Exit RPCS3 when process finishes"}},
{emu_settings_type::StartOnBoot, {"Miscellaneous", "Automatically start games after boot"}},
{emu_settings_type::PauseOnFocusLoss, {"Miscellaneous", "Pause emulation on RPCS3 focus loss"}},
{emu_settings_type::StartGameFullscreen, {"Miscellaneous", "Start games in fullscreen mode"}},
{emu_settings_type::PreventDisplaySleep, {"Miscellaneous", "Prevent display sleep while running games"}},
{emu_settings_type::ShowTrophyPopups, {"Miscellaneous", "Show trophy popups"}},
{emu_settings_type::ShowRpcnPopups, {"Miscellaneous", "Show RPCN popups"}},
{emu_settings_type::UseNativeInterface, {"Miscellaneous", "Use native user interface"}},
{emu_settings_type::ShowShaderCompilationHint, {"Miscellaneous", "Show shader compilation hint"}},
{emu_settings_type::ShowPPUCompilationHint, {"Miscellaneous", "Show PPU compilation hint"}},
{emu_settings_type::ShowAutosaveAutoloadHint, {"Miscellaneous", "Show autosave/autoload hint"}},
{emu_settings_type::ShowPressureIntensityToggleHint, {"Miscellaneous", "Show pressure intensity toggle hint"}},
{emu_settings_type::ShowAnalogLimiterToggleHint, {"Miscellaneous", "Show analog limiter toggle hint"}},
{emu_settings_type::ShowMouseAndKeyboardToggleHint, {"Miscellaneous", "Show mouse and keyboard toggle hint"}},
{emu_settings_type::SilenceAllLogs, {"Miscellaneous", "Silence All Logs"}},
{emu_settings_type::WindowTitleFormat, {"Miscellaneous", "Window Title Format"}},
{emu_settings_type::PauseDuringHomeMenu, {"Miscellaneous", "Pause Emulation During Home Menu"}},
// Networking
{emu_settings_type::InternetStatus, {"Net", "Internet enabled"}},
{emu_settings_type::DNSAddress, {"Net", "DNS address"}},
{emu_settings_type::IpSwapList, {"Net", "IP swap list"}},
{emu_settings_type::PSNStatus, {"Net", "PSN status"}},
{emu_settings_type::BindAddress, {"Net", "Bind address"}},
{emu_settings_type::EnableUpnp, {"Net", "UPNP Enabled"}},
{emu_settings_type::PSNCountry, {"Net", "PSN Country"}},
// System
{emu_settings_type::LicenseArea, {"System", "License Area"}},
{emu_settings_type::Language, {"System", "Language"}},
{emu_settings_type::KeyboardType, {"System", "Keyboard Type"}},
{emu_settings_type::EnterButtonAssignment, {"System", "Enter button assignment"}},
{emu_settings_type::EnableHostRoot, {"VFS", "Enable /host_root/"}},
{emu_settings_type::EmptyHdd0Tmp, {"VFS", "Empty /dev_hdd0/tmp/"}},
{emu_settings_type::LimitCacheSize, {"VFS", "Limit disk cache size"}},
{emu_settings_type::MaximumCacheSize, {"VFS", "Disk cache maximum size (MB)"}},
{emu_settings_type::ConsoleTimeOffset, {"System", "Console time offset (s)"}},
// Savestates
{emu_settings_type::SuspendEmulationSavestateMode, {"Savestate", "Suspend Emulation Savestate Mode"}},
{emu_settings_type::CompatibleEmulationSavestateMode, {"Savestate", "Compatible Savestate Mode"}},
{emu_settings_type::StartSavestatePaused, {"Savestate", "Start Paused"}},
};

View file

@ -1,609 +0,0 @@
#include "stdafx.h"
#include "emulated_pad_settings_dialog.h"
#include "localized_emu.h"
#include "Input/raw_mouse_config.h"
#include "Emu/Io/mouse_config.h"
#include "Emu/Io/buzz_config.h"
#include "Emu/Io/gem_config.h"
#include "Emu/Io/ghltar_config.h"
#include "Emu/Io/guncon3_config.h"
#include "Emu/Io/topshotelite_config.h"
#include "Emu/Io/topshotfearmaster_config.h"
#include "Emu/Io/turntable_config.h"
#include "Emu/Io/usio_config.h"
#include "util/asm.hpp"
#include <QDialogButtonBox>
#include <QGroupBox>
#include <QLabel>
#include <QMessageBox>
#include <QPushButton>
#include <QVBoxLayout>
enum button_role
{
button = Qt::UserRole,
emulated_button
};
emulated_pad_settings_dialog::emulated_pad_settings_dialog(pad_type type, QWidget* parent)
: QDialog(parent), m_type(type)
{
setObjectName("emulated_pad_settings_dialog");
setAttribute(Qt::WA_DeleteOnClose);
setAttribute(Qt::WA_StyledBackground);
setModal(true);
QVBoxLayout* v_layout = new QVBoxLayout(this);
QTabWidget* tabs = new QTabWidget();
tabs->setUsesScrollButtons(false);
QDialogButtonBox* buttons = new QDialogButtonBox(this);
buttons->setStandardButtons(QDialogButtonBox::Apply | QDialogButtonBox::Cancel | QDialogButtonBox::Save | QDialogButtonBox::RestoreDefaults);
connect(buttons, &QDialogButtonBox::clicked, this, [this, buttons](QAbstractButton* button)
{
if (button == buttons->button(QDialogButtonBox::Apply))
{
save_config();
}
else if (button == buttons->button(QDialogButtonBox::Save))
{
save_config();
accept();
}
else if (button == buttons->button(QDialogButtonBox::RestoreDefaults))
{
if (QMessageBox::question(this, tr("Confirm Reset"), tr("Reset all buttons of all players?")) != QMessageBox::Yes)
return;
reset_config();
}
else if (button == buttons->button(QDialogButtonBox::Cancel))
{
// Restore config
load_config();
reject();
}
});
load_config();
switch (m_type)
{
case emulated_pad_settings_dialog::pad_type::buzz:
setWindowTitle(tr("Configure Emulated Buzz"));
add_tabs<buzz_btn>(tabs);
break;
case emulated_pad_settings_dialog::pad_type::turntable:
setWindowTitle(tr("Configure Emulated Turntable"));
add_tabs<turntable_btn>(tabs);
break;
case emulated_pad_settings_dialog::pad_type::ghltar:
setWindowTitle(tr("Configure Emulated GHLtar"));
add_tabs<ghltar_btn>(tabs);
break;
case emulated_pad_settings_dialog::pad_type::usio:
setWindowTitle(tr("Configure Emulated USIO"));
add_tabs<usio_btn>(tabs);
break;
case emulated_pad_settings_dialog::pad_type::gem:
setWindowTitle(tr("Configure Emulated PS Move (Real)"));
add_tabs<gem_btn>(tabs);
break;
case emulated_pad_settings_dialog::pad_type::ds3gem:
setWindowTitle(tr("Configure Emulated PS Move (Fake)"));
add_tabs<gem_btn>(tabs);
break;
case emulated_pad_settings_dialog::pad_type::mousegem:
setWindowTitle(tr("Configure Emulated PS Move (Mouse)"));
add_tabs<gem_btn>(tabs);
break;
case emulated_pad_settings_dialog::pad_type::guncon3:
setWindowTitle(tr("Configure Emulated GunCon 3"));
add_tabs<guncon3_btn>(tabs);
break;
case emulated_pad_settings_dialog::pad_type::topshotelite:
setWindowTitle(tr("Configure Emulated Top Shot Elite"));
add_tabs<topshotelite_btn>(tabs);
break;
case emulated_pad_settings_dialog::pad_type::topshotfearmaster:
setWindowTitle(tr("Configure Emulated Top Shot Fearmaster"));
add_tabs<topshotfearmaster_btn>(tabs);
break;
}
v_layout->addWidget(tabs);
v_layout->addWidget(buttons);
setLayout(v_layout);
}
template <typename T>
void emulated_pad_settings_dialog::add_tabs(QTabWidget* tabs)
{
ensure(!!tabs);
std::set<int> ignored_values;
const auto remove_value = [&ignored_values](int value)
{
ignored_values.insert(static_cast<int>(value));
};
usz players = 0;
switch (m_type)
{
case pad_type::buzz:
players = g_cfg_buzz.players.size();
break;
case pad_type::turntable:
players = g_cfg_turntable.players.size();
break;
case pad_type::ghltar:
players = g_cfg_ghltar.players.size();
break;
case pad_type::usio:
players = g_cfg_usio.players.size();
break;
case pad_type::gem:
players = g_cfg_gem_real.players.size();
// Ignore combo, x and y axis
remove_value(static_cast<int>(gem_btn::x_axis));
remove_value(static_cast<int>(gem_btn::y_axis));
for (int i = static_cast<int>(gem_btn::combo_begin); i <= static_cast<int>(gem_btn::combo_end); i++)
{
remove_value(i);
}
break;
case pad_type::ds3gem:
players = g_cfg_gem_fake.players.size();
// Ignore combo
for (int i = static_cast<int>(gem_btn::combo_begin); i <= static_cast<int>(gem_btn::combo_end); i++)
{
remove_value(i);
}
break;
case pad_type::mousegem:
players = g_cfg_gem_mouse.players.size();
// Ignore x and y axis
remove_value(static_cast<int>(gem_btn::x_axis));
remove_value(static_cast<int>(gem_btn::y_axis));
break;
case pad_type::guncon3:
players = g_cfg_guncon3.players.size();
break;
case pad_type::topshotelite:
players = g_cfg_topshotelite.players.size();
break;
case pad_type::topshotfearmaster:
players = g_cfg_topshotfearmaster.players.size();
break;
}
constexpr u32 max_items_per_column = 6;
const int count = static_cast<int>(T::count) - static_cast<int>(ignored_values.size());
int rows = count;
for (u32 cols = 1; utils::aligned_div(static_cast<u32>(count), cols) > max_items_per_column;)
{
rows = utils::aligned_div(static_cast<u32>(count), ++cols);
}
m_combos.resize(players);
const bool show_mouse_legend = m_type == pad_type::mousegem;
if (show_mouse_legend)
{
if (!g_cfg_mouse.load())
{
cfg_log.notice("Could not restore mouse config. Using defaults.");
}
if (!g_cfg_raw_mouse.load())
{
cfg_log.notice("Could not restore raw mouse config. Using defaults.");
}
}
for (usz player = 0; player < players; player++)
{
// Create grid with all buttons
QGridLayout* grid_layout = new QGridLayout(this);
for (int i = 0, row = 0, col = 0; i < static_cast<int>(T::count); i++)
{
if (ignored_values.contains(i))
continue;
const T id = static_cast<T>(i);
const QString name = QString::fromStdString(fmt::format("%s", id));
QHBoxLayout* h_layout = new QHBoxLayout(this);
QGroupBox* gb = new QGroupBox(name, this);
QComboBox* combo = new QComboBox;
if constexpr (std::is_same_v<T, gem_btn>)
{
const gem_btn btn = static_cast<gem_btn>(i);
if (btn >= gem_btn::combo_begin && btn <= gem_btn::combo_end)
{
gb->setToolTip(tr("Press the \"Combo\" button in combination with any of the other combo buttons to trigger their related PS Move button.\n"
"This can be useful if your device does not have enough regular buttons."));
}
}
// Add empty value
combo->addItem("");
const int index = combo->findText("");
combo->setItemData(index, static_cast<int>(pad_button::pad_button_max_enum), button_role::button);
combo->setItemData(index, i, button_role::emulated_button);
if (m_type != pad_type::mousegem)
{
for (int p = 0; p < static_cast<int>(pad_button::pad_button_max_enum); p++)
{
const QString translated = localized_emu::translated_pad_button(static_cast<pad_button>(p));
combo->addItem(translated);
const int index = combo->findText(translated);
combo->setItemData(index, p, button_role::button);
combo->setItemData(index, i, button_role::emulated_button);
}
}
if (std::is_same_v<T, guncon3_btn> || std::is_same_v<T, topshotelite_btn> || std::is_same_v<T, topshotfearmaster_btn> || m_type == pad_type::mousegem)
{
for (int p = static_cast<int>(pad_button::mouse_button_1); p <= static_cast<int>(pad_button::mouse_button_8); p++)
{
const QString translated = localized_emu::translated_pad_button(static_cast<pad_button>(p));
combo->addItem(translated);
const int index = combo->findText(translated);
combo->setItemData(index, p, button_role::button);
combo->setItemData(index, i, button_role::emulated_button);
}
}
pad_button saved_btn_id = pad_button::pad_button_max_enum;
switch (m_type)
{
case pad_type::buzz:
saved_btn_id = ::at32(g_cfg_buzz.players, player)->get_pad_button(static_cast<buzz_btn>(id));
break;
case pad_type::turntable:
saved_btn_id = ::at32(g_cfg_turntable.players, player)->get_pad_button(static_cast<turntable_btn>(id));
break;
case pad_type::ghltar:
saved_btn_id = ::at32(g_cfg_ghltar.players, player)->get_pad_button(static_cast<ghltar_btn>(id));
break;
case pad_type::usio:
saved_btn_id = ::at32(g_cfg_usio.players, player)->get_pad_button(static_cast<usio_btn>(id));
break;
case pad_type::gem:
saved_btn_id = ::at32(g_cfg_gem_real.players, player)->get_pad_button(static_cast<gem_btn>(id));
break;
case pad_type::ds3gem:
saved_btn_id = ::at32(g_cfg_gem_fake.players, player)->get_pad_button(static_cast<gem_btn>(id));
break;
case pad_type::mousegem:
saved_btn_id = ::at32(g_cfg_gem_mouse.players, player)->get_pad_button(static_cast<gem_btn>(id));
break;
case pad_type::guncon3:
saved_btn_id = ::at32(g_cfg_guncon3.players, player)->get_pad_button(static_cast<guncon3_btn>(id));
break;
case pad_type::topshotelite:
saved_btn_id = ::at32(g_cfg_topshotelite.players, player)->get_pad_button(static_cast<topshotelite_btn>(id));
break;
case pad_type::topshotfearmaster:
saved_btn_id = ::at32(g_cfg_topshotfearmaster.players, player)->get_pad_button(static_cast<topshotfearmaster_btn>(id));
break;
}
combo->setCurrentIndex(combo->findData(static_cast<int>(saved_btn_id)));
connect(combo, QOverload<int>::of(&QComboBox::currentIndexChanged), this, [this, player, id, combo](int index)
{
if (index < 0 || !combo)
return;
const QVariant data = combo->itemData(index, button_role::button);
if (!data.isValid() || !data.canConvert<int>())
return;
const pad_button btn_id = static_cast<pad_button>(data.toInt());
switch (m_type)
{
case pad_type::buzz:
::at32(g_cfg_buzz.players, player)->set_button(static_cast<buzz_btn>(id), btn_id);
break;
case pad_type::turntable:
::at32(g_cfg_turntable.players, player)->set_button(static_cast<turntable_btn>(id), btn_id);
break;
case pad_type::ghltar:
::at32(g_cfg_ghltar.players, player)->set_button(static_cast<ghltar_btn>(id), btn_id);
break;
case pad_type::usio:
::at32(g_cfg_usio.players, player)->set_button(static_cast<usio_btn>(id), btn_id);
break;
case pad_type::gem:
::at32(g_cfg_gem_real.players, player)->set_button(static_cast<gem_btn>(id), btn_id);
break;
case pad_type::ds3gem:
::at32(g_cfg_gem_fake.players, player)->set_button(static_cast<gem_btn>(id), btn_id);
break;
case pad_type::mousegem:
::at32(g_cfg_gem_mouse.players, player)->set_button(static_cast<gem_btn>(id), btn_id);
break;
case pad_type::guncon3:
::at32(g_cfg_guncon3.players, player)->set_button(static_cast<guncon3_btn>(id), btn_id);
break;
case pad_type::topshotelite:
::at32(g_cfg_topshotelite.players, player)->set_button(static_cast<topshotelite_btn>(id), btn_id);
break;
case pad_type::topshotfearmaster:
::at32(g_cfg_topshotfearmaster.players, player)->set_button(static_cast<topshotfearmaster_btn>(id), btn_id);
break;
}
});
if (row >= rows)
{
row = 0;
col++;
}
::at32(m_combos, player).push_back(combo);
h_layout->addWidget(combo);
gb->setLayout(h_layout);
grid_layout->addWidget(gb, row, col);
row++;
}
QVBoxLayout* v_layout = new QVBoxLayout(this);
// Create a legend of the current mouse settings
if (show_mouse_legend)
{
QHBoxLayout* legend_layout = new QHBoxLayout(this);
if (player == 0)
{
std::string basic_mouse_settings;
fmt::append(basic_mouse_settings, "1: %s\n", g_cfg_mouse.mouse_button_1.to_string());
fmt::append(basic_mouse_settings, "2: %s\n", g_cfg_mouse.mouse_button_2.to_string());
fmt::append(basic_mouse_settings, "3: %s\n", g_cfg_mouse.mouse_button_3.to_string());
fmt::append(basic_mouse_settings, "4: %s\n", g_cfg_mouse.mouse_button_4.to_string());
fmt::append(basic_mouse_settings, "5: %s\n", g_cfg_mouse.mouse_button_5.to_string());
fmt::append(basic_mouse_settings, "6: %s\n", g_cfg_mouse.mouse_button_6.to_string());
fmt::append(basic_mouse_settings, "7: %s\n", g_cfg_mouse.mouse_button_7.to_string());
fmt::append(basic_mouse_settings, "8: %s", g_cfg_mouse.mouse_button_8.to_string());
QGroupBox* gb_legend_basic = new QGroupBox(tr("Current Basic Mouse Config"), this);
QVBoxLayout* gb_legend_basic_layout = new QVBoxLayout(this);
gb_legend_basic_layout->addWidget(new QLabel(QString::fromStdString(basic_mouse_settings), this));
gb_legend_basic->setLayout(gb_legend_basic_layout);
legend_layout->addWidget(gb_legend_basic);
}
{
std::string raw_mouse_settings;
const auto& raw_cfg = *ensure(::at32(g_cfg_raw_mouse.players, player));
fmt::append(raw_mouse_settings, "1: %s\n", raw_mouse_config::get_button_name(raw_cfg.mouse_button_1.to_string()));
fmt::append(raw_mouse_settings, "2: %s\n", raw_mouse_config::get_button_name(raw_cfg.mouse_button_2.to_string()));
fmt::append(raw_mouse_settings, "3: %s\n", raw_mouse_config::get_button_name(raw_cfg.mouse_button_3.to_string()));
fmt::append(raw_mouse_settings, "4: %s\n", raw_mouse_config::get_button_name(raw_cfg.mouse_button_4.to_string()));
fmt::append(raw_mouse_settings, "5: %s\n", raw_mouse_config::get_button_name(raw_cfg.mouse_button_5.to_string()));
fmt::append(raw_mouse_settings, "6: %s\n", raw_mouse_config::get_button_name(raw_cfg.mouse_button_6.to_string()));
fmt::append(raw_mouse_settings, "7: %s\n", raw_mouse_config::get_button_name(raw_cfg.mouse_button_7.to_string()));
fmt::append(raw_mouse_settings, "8: %s", raw_mouse_config::get_button_name(raw_cfg.mouse_button_8.to_string()));
QGroupBox* gb_legend_raw = new QGroupBox(tr("Current Raw Mouse Config"), this);
QVBoxLayout* gb_legend_raw_layout = new QVBoxLayout(this);
gb_legend_raw_layout->addWidget(new QLabel(QString::fromStdString(raw_mouse_settings), this));
gb_legend_raw->setLayout(gb_legend_raw_layout);
legend_layout->addWidget(gb_legend_raw);
}
v_layout->addLayout(legend_layout);
}
v_layout->addLayout(grid_layout);
QWidget* widget = new QWidget(this);
widget->setLayout(v_layout);
tabs->addTab(widget, tr("Player %0").arg(player + 1));
}
}
void emulated_pad_settings_dialog::load_config()
{
switch (m_type)
{
case emulated_pad_settings_dialog::pad_type::buzz:
if (!g_cfg_buzz.load())
{
cfg_log.notice("Could not load buzz config. Using defaults.");
}
break;
case emulated_pad_settings_dialog::pad_type::turntable:
if (!g_cfg_turntable.load())
{
cfg_log.notice("Could not load turntable config. Using defaults.");
}
break;
case emulated_pad_settings_dialog::pad_type::ghltar:
if (!g_cfg_ghltar.load())
{
cfg_log.notice("Could not load ghltar config. Using defaults.");
}
break;
case emulated_pad_settings_dialog::pad_type::usio:
if (!g_cfg_usio.load())
{
cfg_log.notice("Could not load usio config. Using defaults.");
}
break;
case emulated_pad_settings_dialog::pad_type::gem:
if (!g_cfg_gem_real.load())
{
cfg_log.notice("Could not load gem config. Using defaults.");
}
break;
case emulated_pad_settings_dialog::pad_type::ds3gem:
if (!g_cfg_gem_fake.load())
{
cfg_log.notice("Could not load fake gem config. Using defaults.");
}
break;
case emulated_pad_settings_dialog::pad_type::mousegem:
if (!g_cfg_gem_mouse.load())
{
cfg_log.notice("Could not load mouse gem config. Using defaults.");
}
break;
case emulated_pad_settings_dialog::pad_type::guncon3:
if (!g_cfg_guncon3.load())
{
cfg_log.notice("Could not load guncon3 config. Using defaults.");
}
break;
case emulated_pad_settings_dialog::pad_type::topshotelite:
if (!g_cfg_topshotelite.load())
{
cfg_log.notice("Could not load topshotelite config. Using defaults.");
}
break;
case emulated_pad_settings_dialog::pad_type::topshotfearmaster:
if (!g_cfg_topshotfearmaster.load())
{
cfg_log.notice("Could not load topshotfearmaster config. Using defaults.");
}
break;
}
}
void emulated_pad_settings_dialog::save_config()
{
switch (m_type)
{
case emulated_pad_settings_dialog::pad_type::buzz:
g_cfg_buzz.save();
break;
case emulated_pad_settings_dialog::pad_type::turntable:
g_cfg_turntable.save();
break;
case emulated_pad_settings_dialog::pad_type::ghltar:
g_cfg_ghltar.save();
break;
case emulated_pad_settings_dialog::pad_type::usio:
g_cfg_usio.save();
break;
case emulated_pad_settings_dialog::pad_type::gem:
g_cfg_gem_real.save();
break;
case emulated_pad_settings_dialog::pad_type::ds3gem:
g_cfg_gem_fake.save();
break;
case emulated_pad_settings_dialog::pad_type::mousegem:
g_cfg_gem_mouse.save();
break;
case emulated_pad_settings_dialog::pad_type::guncon3:
g_cfg_guncon3.save();
break;
case emulated_pad_settings_dialog::pad_type::topshotelite:
g_cfg_topshotelite.save();
break;
case emulated_pad_settings_dialog::pad_type::topshotfearmaster:
g_cfg_topshotfearmaster.save();
break;
}
}
void emulated_pad_settings_dialog::reset_config()
{
switch (m_type)
{
case emulated_pad_settings_dialog::pad_type::buzz:
g_cfg_buzz.from_default();
break;
case emulated_pad_settings_dialog::pad_type::turntable:
g_cfg_turntable.from_default();
break;
case emulated_pad_settings_dialog::pad_type::ghltar:
g_cfg_ghltar.from_default();
break;
case emulated_pad_settings_dialog::pad_type::usio:
g_cfg_usio.from_default();
break;
case emulated_pad_settings_dialog::pad_type::gem:
g_cfg_gem_real.from_default();
break;
case emulated_pad_settings_dialog::pad_type::ds3gem:
g_cfg_gem_fake.from_default();
break;
case emulated_pad_settings_dialog::pad_type::mousegem:
g_cfg_gem_mouse.from_default();
break;
case emulated_pad_settings_dialog::pad_type::guncon3:
g_cfg_guncon3.from_default();
break;
case emulated_pad_settings_dialog::pad_type::topshotelite:
g_cfg_topshotelite.from_default();
break;
case emulated_pad_settings_dialog::pad_type::topshotfearmaster:
g_cfg_topshotfearmaster.from_default();
break;
}
for (usz player = 0; player < m_combos.size(); player++)
{
for (QComboBox* combo : m_combos.at(player))
{
if (!combo)
continue;
const QVariant data = combo->itemData(0, button_role::emulated_button);
if (!data.isValid() || !data.canConvert<int>())
continue;
pad_button def_btn_id = pad_button::pad_button_max_enum;
switch (m_type)
{
case pad_type::buzz:
def_btn_id = ::at32(g_cfg_buzz.players, player)->default_pad_button(static_cast<buzz_btn>(data.toInt()));
break;
case pad_type::turntable:
def_btn_id = ::at32(g_cfg_turntable.players, player)->default_pad_button(static_cast<turntable_btn>(data.toInt()));
break;
case pad_type::ghltar:
def_btn_id = ::at32(g_cfg_ghltar.players, player)->default_pad_button(static_cast<ghltar_btn>(data.toInt()));
break;
case pad_type::usio:
def_btn_id = ::at32(g_cfg_usio.players, player)->default_pad_button(static_cast<usio_btn>(data.toInt()));
break;
case pad_type::gem:
def_btn_id = ::at32(g_cfg_gem_real.players, player)->default_pad_button(static_cast<gem_btn>(data.toInt()));
break;
case pad_type::ds3gem:
def_btn_id = ::at32(g_cfg_gem_fake.players, player)->default_pad_button(static_cast<gem_btn>(data.toInt()));
break;
case pad_type::mousegem:
def_btn_id = ::at32(g_cfg_gem_mouse.players, player)->default_pad_button(static_cast<gem_btn>(data.toInt()));
break;
case pad_type::guncon3:
def_btn_id = ::at32(g_cfg_guncon3.players, player)->default_pad_button(static_cast<guncon3_btn>(data.toInt()));
break;
case pad_type::topshotelite:
def_btn_id = ::at32(g_cfg_topshotelite.players, player)->default_pad_button(static_cast<topshotelite_btn>(data.toInt()));
break;
case pad_type::topshotfearmaster:
def_btn_id = ::at32(g_cfg_topshotfearmaster.players, player)->default_pad_button(static_cast<topshotfearmaster_btn>(data.toInt()));
break;
}
combo->setCurrentIndex(combo->findData(static_cast<int>(def_btn_id)));
}
}
}

View file

@ -1,41 +0,0 @@
#pragma once
#include <QComboBox>
#include <QDialog>
#include <QTabWidget>
#include <vector>
class emulated_pad_settings_dialog : public QDialog
{
Q_OBJECT
public:
enum class pad_type
{
buzz,
turntable,
ghltar,
usio,
gem,
ds3gem,
mousegem,
guncon3,
topshotelite,
topshotfearmaster,
};
emulated_pad_settings_dialog(pad_type type, QWidget* parent = nullptr);
private:
template <typename T>
void add_tabs(QTabWidget* tabs);
void load_config();
void save_config();
void reset_config();
pad_type m_type;
std::vector<std::vector<QComboBox*>> m_combos;
};

View file

@ -1,54 +0,0 @@
#include "fatal_error_dialog.h"
#include <QLayout>
#include <QTextDocument>
#include <QIcon>
const QString document_with_help_text = R"(
<style>
p {white-space: nowrap;}
</style>
<p>
%1<br>
%2<br>
<a href='https://github.com/RPCS3/rpcs3/wiki/How-to-ask-for-Support'>https://github.com/RPCS3/rpcs3/wiki/How-to-ask-for-Support</a><br>
%3<br>
</p>
)";
const QString document_without_help_text = R"(
<style>
p {white-space: nowrap;}
</style>
<p>
%1<br>
</p>
)";
fatal_error_dialog::fatal_error_dialog(std::string_view text, bool is_html, bool include_help_text) : QMessageBox()
{
const QString qstr = QString::fromUtf8(text.data(), text.size());
const QString msg = is_html ? qstr : Qt::convertFromPlainText(qstr);
QString document_body;
if (include_help_text) [[likely]]
{
document_body = document_with_help_text
.arg(msg)
.arg(tr("HOW TO REPORT ERRORS:"))
.arg(tr("Please, don't send incorrect reports. Thanks for understanding."));
}
else
{
document_body = document_without_help_text.arg(msg);
}
#ifndef __APPLE__
setWindowIcon(QIcon(":/rpcs3.ico"));
#endif
setWindowTitle(tr("RPCS3: Fatal Error"));
setIcon(QMessageBox::Icon::Critical);
setTextFormat(Qt::TextFormat::RichText);
setText(document_body);
layout()->setSizeConstraint(QLayout::SetFixedSize);
}

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