Split split rpcs3 and qt ui
4
.github/readme.md
vendored
|
|
@ -29,3 +29,7 @@ If you want to contribute as a developer, please contact us in the [Discord](htt
|
||||||
RPCSX is licensed under GPLv2 license except directories containing their own LICENSE file, or files containing their own license.
|
RPCSX is licensed under GPLv2 license except directories containing their own LICENSE file, or files containing their own license.
|
||||||
Thus, orbis-kernel is licensed under the MIT license.
|
Thus, orbis-kernel is licensed under the MIT license.
|
||||||
|
|
||||||
|
## RPCS3
|
||||||
|
|
||||||
|
This project uses modified source code of [RPCS3](https://github.com/RPCS3/rpcs3)
|
||||||
|
|
||||||
|
|
|
||||||
4
.gitmodules
vendored
|
|
@ -35,10 +35,6 @@
|
||||||
path = rpcs3/3rdparty/llvm/llvm
|
path = rpcs3/3rdparty/llvm/llvm
|
||||||
url = ../../llvm/llvm-project.git
|
url = ../../llvm/llvm-project.git
|
||||||
ignore = dirty
|
ignore = dirty
|
||||||
[submodule "rpcs3/3rdparty/glslang"]
|
|
||||||
path = rpcs3/3rdparty/glslang/glslang
|
|
||||||
url = ../../KhronosGroup/glslang.git
|
|
||||||
ignore = dirty
|
|
||||||
[submodule "rpcs3/3rdparty/zlib"]
|
[submodule "rpcs3/3rdparty/zlib"]
|
||||||
path = rpcs3/3rdparty/zlib/zlib
|
path = rpcs3/3rdparty/zlib/zlib
|
||||||
url = ../../madler/zlib
|
url = ../../madler/zlib
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,12 @@
|
||||||
cmake_minimum_required(VERSION 3.20)
|
cmake_minimum_required(VERSION 3.20)
|
||||||
project(rpcsx)
|
project(rpcsx)
|
||||||
|
|
||||||
|
option(WITH_RPCSX "Enable RPCSX" ON)
|
||||||
|
option(WITH_RPCS3 "Enable RPCS3" OFF)
|
||||||
|
option(WITH_RPCS3_QT_UI "Enable RPCS3 UI" OFF)
|
||||||
|
option(WITHOUT_OPENGL "Disable OpenGL" OFF)
|
||||||
|
option(WITHOUT_OPENGLEW "Disable OpenGLEW" OFF)
|
||||||
|
|
||||||
set(CMAKE_CXX_EXTENSIONS off)
|
set(CMAKE_CXX_EXTENSIONS off)
|
||||||
set(CMAKE_CXX_STANDARD 23)
|
set(CMAKE_CXX_STANDARD 23)
|
||||||
set(CMAKE_CXX_STANDARD_REQUIRED on)
|
set(CMAKE_CXX_STANDARD_REQUIRED on)
|
||||||
|
|
@ -8,10 +14,12 @@ set(CMAKE_BUILD_RPATH_USE_ORIGIN on)
|
||||||
|
|
||||||
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
|
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
|
||||||
|
|
||||||
find_package(nlohmann_json CONFIG)
|
|
||||||
add_subdirectory(3rdparty EXCLUDE_FROM_ALL)
|
add_subdirectory(3rdparty EXCLUDE_FROM_ALL)
|
||||||
|
|
||||||
function(add_precompiled_vulkan_spirv target)
|
if (WITH_RPCSX)
|
||||||
|
find_package(nlohmann_json CONFIG)
|
||||||
|
|
||||||
|
function(add_precompiled_vulkan_spirv target)
|
||||||
add_library(${target} INTERFACE)
|
add_library(${target} INTERFACE)
|
||||||
set(SPIRV_GEN_ROOT_DIR "spirv-gen/include/")
|
set(SPIRV_GEN_ROOT_DIR "spirv-gen/include/")
|
||||||
set(SPIRV_GEN_DIR "${SPIRV_GEN_ROOT_DIR}/shaders")
|
set(SPIRV_GEN_DIR "${SPIRV_GEN_ROOT_DIR}/shaders")
|
||||||
|
|
@ -42,9 +50,9 @@ function(add_precompiled_vulkan_spirv target)
|
||||||
add_custom_target(${subtarget} DEPENDS ${outputpath})
|
add_custom_target(${subtarget} DEPENDS ${outputpath})
|
||||||
add_dependencies(${target} ${subtarget})
|
add_dependencies(${target} ${subtarget})
|
||||||
endforeach()
|
endforeach()
|
||||||
endfunction()
|
endfunction()
|
||||||
|
|
||||||
function(target_base_address target address)
|
function(target_base_address target address)
|
||||||
set_target_properties(${target} PROPERTIES POSITION_INDEPENDENT_CODE off)
|
set_target_properties(${target} PROPERTIES POSITION_INDEPENDENT_CODE off)
|
||||||
|
|
||||||
if(CMAKE_CXX_COMPILER_LINKER_ID MATCHES "^(LLD|MOLD)$")
|
if(CMAKE_CXX_COMPILER_LINKER_ID MATCHES "^(LLD|MOLD)$")
|
||||||
|
|
@ -52,15 +60,25 @@ function(target_base_address target address)
|
||||||
else()
|
else()
|
||||||
target_link_options(${target} PUBLIC "LINKER:-Ttext-segment,${address}")
|
target_link_options(${target} PUBLIC "LINKER:-Ttext-segment,${address}")
|
||||||
endif()
|
endif()
|
||||||
endfunction()
|
endfunction()
|
||||||
|
|
||||||
add_subdirectory(tools)
|
add_subdirectory(tools)
|
||||||
|
|
||||||
|
add_subdirectory(orbis-kernel)
|
||||||
|
add_subdirectory(rpcsx)
|
||||||
|
endif()
|
||||||
|
|
||||||
add_subdirectory(orbis-kernel)
|
|
||||||
add_subdirectory(rpcsx)
|
|
||||||
add_subdirectory(rx)
|
add_subdirectory(rx)
|
||||||
|
|
||||||
target_compile_definitions(rx PRIVATE
|
target_compile_definitions(rx PRIVATE
|
||||||
RX_TAG=0
|
RX_TAG=0
|
||||||
RX_TAG_VERSION=0
|
RX_TAG_VERSION=0
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if (WITH_RPCS3)
|
||||||
|
add_subdirectory(rpcs3)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if (NOT ANDROID AND WITH_RPCS3_QT_UI AND WITH_RPCS3)
|
||||||
|
add_subdirectory(rpcs3qt-legacy)
|
||||||
|
endif()
|
||||||
|
|
|
||||||
|
|
@ -1,153 +0,0 @@
|
||||||
env:
|
|
||||||
CIRRUS_CLONE_DEPTH: 0 # Unshallow clone to obtain proper GIT_VERSION
|
|
||||||
BUILD_REPOSITORY_NAME: $CIRRUS_REPO_FULL_NAME
|
|
||||||
SYSTEM_PULLREQUEST_SOURCEBRANCH: $CIRRUS_BRANCH
|
|
||||||
SYSTEM_PULLREQUEST_PULLREQUESTID: $CIRRUS_PR
|
|
||||||
BUILD_SOURCEVERSION: $CIRRUS_CHANGE_IN_REPO
|
|
||||||
BUILD_SOURCEBRANCHNAME: $CIRRUS_BRANCH
|
|
||||||
RPCS3_TOKEN: ENCRYPTED[100ebb8e3552bf2021d0ef55dccda3e58d27be5b6cab0b0b92843ef490195d3c4edaefa087e4a3b425caa6392300b9b1]
|
|
||||||
QT_VER_MAIN: '6'
|
|
||||||
QT_VER: '6.8.3'
|
|
||||||
LLVM_COMPILER_VER: '19'
|
|
||||||
LLVM_VER: '19.1.7'
|
|
||||||
|
|
||||||
# windows_task:
|
|
||||||
# matrix:
|
|
||||||
# - name: Cirrus Windows
|
|
||||||
# windows_container:
|
|
||||||
# image: cirrusci/windowsservercore:visualstudio2019
|
|
||||||
# cpu: 8
|
|
||||||
# memory: 16G
|
|
||||||
# env:
|
|
||||||
# CIRRUS_SHELL: "bash"
|
|
||||||
# COMPILER: msvc
|
|
||||||
# BUILD_ARTIFACTSTAGINGDIRECTORY: ${CIRRUS_WORKING_DIR}\artifacts\
|
|
||||||
# QT_VER_MSVC: 'msvc2022'
|
|
||||||
# QT_DATE: '202503201308'
|
|
||||||
# QTDIR: C:\Qt\${QT_VER}\${QT_VER_MSVC}_64
|
|
||||||
# VULKAN_VER: '1.3.268.0'
|
|
||||||
# VULKAN_SDK_SHA: '8459ef49bd06b697115ddd3d97c9aec729e849cd775f5be70897718a9b3b9db5'
|
|
||||||
# VULKAN_SDK: C:\VulkanSDK\${VULKAN_VER}
|
|
||||||
# CACHE_DIR: "./cache"
|
|
||||||
# UPLOAD_COMMIT_HASH: 7d09e3be30805911226241afbb14f8cdc2eb054e
|
|
||||||
# UPLOAD_REPO_FULL_NAME: "rpcs3/rpcs3-binaries-win"
|
|
||||||
# deps_cache:
|
|
||||||
# folder: "./cache"
|
|
||||||
# #obj_cache:
|
|
||||||
# # folder: "./tmp"
|
|
||||||
# #obj2_cache:
|
|
||||||
# # folder: "./rpcs3/x64"
|
|
||||||
# setup_script:
|
|
||||||
# - './.ci/get_keys-windows.sh'
|
|
||||||
# - './.ci/setup-windows.sh'
|
|
||||||
# rpcs3_script:
|
|
||||||
# - export PATH=${PATH}:"C:\Program Files (x86)\Microsoft Visual Studio\2019\BuildTools\MSBuild\Current\Bin"
|
|
||||||
# - msbuild.exe rpcs3.sln //p:Configuration=Release //m
|
|
||||||
# deploy_script:
|
|
||||||
# - mkdir artifacts
|
|
||||||
# - source './.ci/export-cirrus-vars.sh'
|
|
||||||
# - './.ci/deploy-windows.sh'
|
|
||||||
# artifacts:
|
|
||||||
# name: Artifact
|
|
||||||
# path: "*.7z*"
|
|
||||||
# push_script: |
|
|
||||||
# if [ "$CIRRUS_REPO_OWNER" = "RPCS3" ] && [ -z "$CIRRUS_PR" ] && [ "$CIRRUS_BRANCH" = "master" ]; then
|
|
||||||
# source './.ci/export-cirrus-vars.sh'
|
|
||||||
# './.ci/github-upload.sh'
|
|
||||||
# fi;
|
|
||||||
|
|
||||||
# linux_task:
|
|
||||||
# container:
|
|
||||||
# image: rpcs3/rpcs3-ci-jammy:1.2
|
|
||||||
# cpu: 4
|
|
||||||
# memory: 16G
|
|
||||||
# env:
|
|
||||||
# BUILD_ARTIFACTSTAGINGDIRECTORY: ${CIRRUS_WORKING_DIR}/artifacts
|
|
||||||
# ARTDIR: ${CIRRUS_WORKING_DIR}/artifacts/
|
|
||||||
# CCACHE_DIR: "/tmp/ccache_dir"
|
|
||||||
# CCACHE_MAXSIZE: 300M
|
|
||||||
# CI_HAS_ARTIFACTS: true
|
|
||||||
# UPLOAD_COMMIT_HASH: d812f1254a1157c80fd402f94446310560f54e5f
|
|
||||||
# UPLOAD_REPO_FULL_NAME: "rpcs3/rpcs3-binaries-linux"
|
|
||||||
# DEPLOY_APPIMAGE: true
|
|
||||||
# APPDIR: "./appdir"
|
|
||||||
# RELEASE_MESSAGE: "../GitHubReleaseMessage.txt"
|
|
||||||
# ccache_cache:
|
|
||||||
# folder: "/tmp/ccache_dir"
|
|
||||||
# matrix:
|
|
||||||
# - name: Cirrus Linux GCC
|
|
||||||
# env:
|
|
||||||
# COMPILER: gcc
|
|
||||||
# gcc_script:
|
|
||||||
# - mkdir artifacts
|
|
||||||
# - ".ci/build-linux.sh"
|
|
||||||
# - name: Cirrus Linux Clang
|
|
||||||
# env:
|
|
||||||
# COMPILER: clang
|
|
||||||
# clang_script:
|
|
||||||
# - mkdir artifacts
|
|
||||||
# - ".ci/build-linux.sh"
|
|
||||||
# artifacts:
|
|
||||||
# name: Artifact
|
|
||||||
# path: "artifacts/*"
|
|
||||||
# push_script: |
|
|
||||||
# if [ "$CIRRUS_REPO_OWNER" = "RPCS3" ] && [ -z "$CIRRUS_PR" ] && [ "$CIRRUS_BRANCH" = "master" ] && [ "$COMPILER" = "gcc" ]; then
|
|
||||||
# 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)
|
|
||||||
|
|
||||||
# export AVVER="${COMM_TAG}-${COMM_COUNT}"
|
|
||||||
|
|
||||||
# .ci/github-upload.sh
|
|
||||||
# fi;
|
|
||||||
|
|
||||||
freebsd_task:
|
|
||||||
matrix:
|
|
||||||
- name: Cirrus FreeBSD
|
|
||||||
freebsd_instance:
|
|
||||||
image_family: freebsd-13-5
|
|
||||||
cpu: 8
|
|
||||||
memory: 8G
|
|
||||||
env:
|
|
||||||
CCACHE_MAXSIZE: 300M # 3x clean build, rounded
|
|
||||||
CCACHE_DIR: /tmp/ccache_dir
|
|
||||||
ccache_cache:
|
|
||||||
folder: /tmp/ccache_dir
|
|
||||||
install_script: "sh -ex ./.ci/install-freebsd.sh"
|
|
||||||
script: "./.ci/build-freebsd.sh"
|
|
||||||
|
|
||||||
# linux_aarch64_task:
|
|
||||||
# env:
|
|
||||||
# BUILD_ARTIFACTSTAGINGDIRECTORY: ${CIRRUS_WORKING_DIR}/artifacts
|
|
||||||
# ARTDIR: ${CIRRUS_WORKING_DIR}/artifacts/
|
|
||||||
# CCACHE_DIR: "/tmp/ccache_dir"
|
|
||||||
# CCACHE_MAXSIZE: 300M
|
|
||||||
# CI_HAS_ARTIFACTS: true
|
|
||||||
# UPLOAD_COMMIT_HASH: a1d35836e8d45bfc6f63c26f0a3e5d46ef622fe1
|
|
||||||
# UPLOAD_REPO_FULL_NAME: "rpcs3/rpcs3-binaries-linux-arm64"
|
|
||||||
# DEPLOY_APPIMAGE: true
|
|
||||||
# APPDIR: "./appdir"
|
|
||||||
# RELEASE_MESSAGE: "../GitHubReleaseMessage.txt"
|
|
||||||
# COMPILER: clang
|
|
||||||
# ccache_cache:
|
|
||||||
# folder: "/tmp/ccache_dir"
|
|
||||||
# matrix:
|
|
||||||
# - name: Cirrus Linux AArch64 Clang
|
|
||||||
# arm_container:
|
|
||||||
# image: 'docker.io/rpcs3/rpcs3-ci-jammy-aarch64:1.2'
|
|
||||||
# cpu: 8
|
|
||||||
# memory: 8G
|
|
||||||
# clang_script:
|
|
||||||
# - mkdir artifacts
|
|
||||||
# - "sh -ex ./.ci/build-linux-aarch64.sh"
|
|
||||||
# artifacts:
|
|
||||||
# name: Artifact
|
|
||||||
# path: "artifacts/*"
|
|
||||||
# push_script: |
|
|
||||||
# if [ "$CIRRUS_REPO_OWNER" = "RPCS3" ] && [ -z "$CIRRUS_PR" ] && [ "$CIRRUS_BRANCH" = "master" ]; then
|
|
||||||
# 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)
|
|
||||||
# export AVVER="${COMM_TAG}-${COMM_COUNT}"
|
|
||||||
# .ci/github-upload.sh
|
|
||||||
# fi;
|
|
||||||
1
rpcs3/3rdparty/CMakeLists.txt
vendored
|
|
@ -91,7 +91,6 @@ endif()
|
||||||
add_subdirectory(hidapi)
|
add_subdirectory(hidapi)
|
||||||
|
|
||||||
# glslang
|
# glslang
|
||||||
add_subdirectory(glslang EXCLUDE_FROM_ALL)
|
|
||||||
add_library(3rdparty_glslang INTERFACE)
|
add_library(3rdparty_glslang INTERFACE)
|
||||||
target_link_libraries(3rdparty_glslang INTERFACE SPIRV)
|
target_link_libraries(3rdparty_glslang INTERFACE SPIRV)
|
||||||
|
|
||||||
|
|
|
||||||
2
rpcs3/3rdparty/glslang/.gitignore
vendored
|
|
@ -1,2 +0,0 @@
|
||||||
/build
|
|
||||||
/x64
|
|
||||||
11
rpcs3/3rdparty/glslang/CMakeLists.txt
vendored
|
|
@ -1,11 +0,0 @@
|
||||||
#glslang
|
|
||||||
|
|
||||||
set(ENABLE_PCH OFF CACHE BOOL "Enables Precompiled header" FORCE)
|
|
||||||
set(BUILD_EXTERNAL OFF CACHE BOOL "Build external dependencies in /External" FORCE)
|
|
||||||
set(SKIP_GLSLANG_INSTALL ON CACHE BOOL "Skip installation" FORCE)
|
|
||||||
set(ENABLE_SPVREMAPPER OFF CACHE BOOL "Enables building of SPVRemapper" FORCE)
|
|
||||||
set(ENABLE_GLSLANG_BINARIES OFF CACHE BOOL "Builds glslangValidator and spirv-remap" FORCE)
|
|
||||||
set(ENABLE_HLSL OFF CACHE BOOL "Enables HLSL input support" FORCE)
|
|
||||||
set(ENABLE_OPT OFF CACHE BOOL "Enables spirv-opt capability if present" FORCE)
|
|
||||||
set(ENABLE_CTEST OFF CACHE BOOL "Enables testing" FORCE)
|
|
||||||
add_subdirectory(glslang)
|
|
||||||
1
rpcs3/3rdparty/glslang/glslang
vendored
|
|
@ -1 +0,0 @@
|
||||||
Subproject commit 36d08c0d940cf307a23928299ef52c7970d8cee6
|
|
||||||
|
|
@ -33,7 +33,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)
|
||||||
|
|
||||||
set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/buildfiles/cmake")
|
set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
|
||||||
|
|
||||||
include(CheckCXXCompilerFlag)
|
include(CheckCXXCompilerFlag)
|
||||||
|
|
||||||
|
|
|
||||||
339
rpcs3/LICENSE
|
|
@ -1,339 +0,0 @@
|
||||||
GNU GENERAL PUBLIC LICENSE
|
|
||||||
Version 2, June 1991
|
|
||||||
|
|
||||||
Copyright (C) 1989, 1991 Free Software Foundation, Inc., <http://fsf.org/>
|
|
||||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
||||||
Everyone is permitted to copy and distribute verbatim copies
|
|
||||||
of this license document, but changing it is not allowed.
|
|
||||||
|
|
||||||
Preamble
|
|
||||||
|
|
||||||
The licenses for most software are designed to take away your
|
|
||||||
freedom to share and change it. By contrast, the GNU General Public
|
|
||||||
License is intended to guarantee your freedom to share and change free
|
|
||||||
software--to make sure the software is free for all its users. This
|
|
||||||
General Public License applies to most of the Free Software
|
|
||||||
Foundation's software and to any other program whose authors commit to
|
|
||||||
using it. (Some other Free Software Foundation software is covered by
|
|
||||||
the GNU Lesser General Public License instead.) You can apply it to
|
|
||||||
your programs, too.
|
|
||||||
|
|
||||||
When we speak of free software, we are referring to freedom, not
|
|
||||||
price. Our General Public Licenses are designed to make sure that you
|
|
||||||
have the freedom to distribute copies of free software (and charge for
|
|
||||||
this service if you wish), that you receive source code or can get it
|
|
||||||
if you want it, that you can change the software or use pieces of it
|
|
||||||
in new free programs; and that you know you can do these things.
|
|
||||||
|
|
||||||
To protect your rights, we need to make restrictions that forbid
|
|
||||||
anyone to deny you these rights or to ask you to surrender the rights.
|
|
||||||
These restrictions translate to certain responsibilities for you if you
|
|
||||||
distribute copies of the software, or if you modify it.
|
|
||||||
|
|
||||||
For example, if you distribute copies of such a program, whether
|
|
||||||
gratis or for a fee, you must give the recipients all the rights that
|
|
||||||
you have. You must make sure that they, too, receive or can get the
|
|
||||||
source code. And you must show them these terms so they know their
|
|
||||||
rights.
|
|
||||||
|
|
||||||
We protect your rights with two steps: (1) copyright the software, and
|
|
||||||
(2) offer you this license which gives you legal permission to copy,
|
|
||||||
distribute and/or modify the software.
|
|
||||||
|
|
||||||
Also, for each author's protection and ours, we want to make certain
|
|
||||||
that everyone understands that there is no warranty for this free
|
|
||||||
software. If the software is modified by someone else and passed on, we
|
|
||||||
want its recipients to know that what they have is not the original, so
|
|
||||||
that any problems introduced by others will not reflect on the original
|
|
||||||
authors' reputations.
|
|
||||||
|
|
||||||
Finally, any free program is threatened constantly by software
|
|
||||||
patents. We wish to avoid the danger that redistributors of a free
|
|
||||||
program will individually obtain patent licenses, in effect making the
|
|
||||||
program proprietary. To prevent this, we have made it clear that any
|
|
||||||
patent must be licensed for everyone's free use or not licensed at all.
|
|
||||||
|
|
||||||
The precise terms and conditions for copying, distribution and
|
|
||||||
modification follow.
|
|
||||||
|
|
||||||
GNU GENERAL PUBLIC LICENSE
|
|
||||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
|
||||||
|
|
||||||
0. This License applies to any program or other work which contains
|
|
||||||
a notice placed by the copyright holder saying it may be distributed
|
|
||||||
under the terms of this General Public License. The "Program", below,
|
|
||||||
refers to any such program or work, and a "work based on the Program"
|
|
||||||
means either the Program or any derivative work under copyright law:
|
|
||||||
that is to say, a work containing the Program or a portion of it,
|
|
||||||
either verbatim or with modifications and/or translated into another
|
|
||||||
language. (Hereinafter, translation is included without limitation in
|
|
||||||
the term "modification".) Each licensee is addressed as "you".
|
|
||||||
|
|
||||||
Activities other than copying, distribution and modification are not
|
|
||||||
covered by this License; they are outside its scope. The act of
|
|
||||||
running the Program is not restricted, and the output from the Program
|
|
||||||
is covered only if its contents constitute a work based on the
|
|
||||||
Program (independent of having been made by running the Program).
|
|
||||||
Whether that is true depends on what the Program does.
|
|
||||||
|
|
||||||
1. You may copy and distribute verbatim copies of the Program's
|
|
||||||
source code as you receive it, in any medium, provided that you
|
|
||||||
conspicuously and appropriately publish on each copy an appropriate
|
|
||||||
copyright notice and disclaimer of warranty; keep intact all the
|
|
||||||
notices that refer to this License and to the absence of any warranty;
|
|
||||||
and give any other recipients of the Program a copy of this License
|
|
||||||
along with the Program.
|
|
||||||
|
|
||||||
You may charge a fee for the physical act of transferring a copy, and
|
|
||||||
you may at your option offer warranty protection in exchange for a fee.
|
|
||||||
|
|
||||||
2. You may modify your copy or copies of the Program or any portion
|
|
||||||
of it, thus forming a work based on the Program, and copy and
|
|
||||||
distribute such modifications or work under the terms of Section 1
|
|
||||||
above, provided that you also meet all of these conditions:
|
|
||||||
|
|
||||||
a) You must cause the modified files to carry prominent notices
|
|
||||||
stating that you changed the files and the date of any change.
|
|
||||||
|
|
||||||
b) You must cause any work that you distribute or publish, that in
|
|
||||||
whole or in part contains or is derived from the Program or any
|
|
||||||
part thereof, to be licensed as a whole at no charge to all third
|
|
||||||
parties under the terms of this License.
|
|
||||||
|
|
||||||
c) If the modified program normally reads commands interactively
|
|
||||||
when run, you must cause it, when started running for such
|
|
||||||
interactive use in the most ordinary way, to print or display an
|
|
||||||
announcement including an appropriate copyright notice and a
|
|
||||||
notice that there is no warranty (or else, saying that you provide
|
|
||||||
a warranty) and that users may redistribute the program under
|
|
||||||
these conditions, and telling the user how to view a copy of this
|
|
||||||
License. (Exception: if the Program itself is interactive but
|
|
||||||
does not normally print such an announcement, your work based on
|
|
||||||
the Program is not required to print an announcement.)
|
|
||||||
|
|
||||||
These requirements apply to the modified work as a whole. If
|
|
||||||
identifiable sections of that work are not derived from the Program,
|
|
||||||
and can be reasonably considered independent and separate works in
|
|
||||||
themselves, then this License, and its terms, do not apply to those
|
|
||||||
sections when you distribute them as separate works. But when you
|
|
||||||
distribute the same sections as part of a whole which is a work based
|
|
||||||
on the Program, the distribution of the whole must be on the terms of
|
|
||||||
this License, whose permissions for other licensees extend to the
|
|
||||||
entire whole, and thus to each and every part regardless of who wrote it.
|
|
||||||
|
|
||||||
Thus, it is not the intent of this section to claim rights or contest
|
|
||||||
your rights to work written entirely by you; rather, the intent is to
|
|
||||||
exercise the right to control the distribution of derivative or
|
|
||||||
collective works based on the Program.
|
|
||||||
|
|
||||||
In addition, mere aggregation of another work not based on the Program
|
|
||||||
with the Program (or with a work based on the Program) on a volume of
|
|
||||||
a storage or distribution medium does not bring the other work under
|
|
||||||
the scope of this License.
|
|
||||||
|
|
||||||
3. You may copy and distribute the Program (or a work based on it,
|
|
||||||
under Section 2) in object code or executable form under the terms of
|
|
||||||
Sections 1 and 2 above provided that you also do one of the following:
|
|
||||||
|
|
||||||
a) Accompany it with the complete corresponding machine-readable
|
|
||||||
source code, which must be distributed under the terms of Sections
|
|
||||||
1 and 2 above on a medium customarily used for software interchange; or,
|
|
||||||
|
|
||||||
b) Accompany it with a written offer, valid for at least three
|
|
||||||
years, to give any third party, for a charge no more than your
|
|
||||||
cost of physically performing source distribution, a complete
|
|
||||||
machine-readable copy of the corresponding source code, to be
|
|
||||||
distributed under the terms of Sections 1 and 2 above on a medium
|
|
||||||
customarily used for software interchange; or,
|
|
||||||
|
|
||||||
c) Accompany it with the information you received as to the offer
|
|
||||||
to distribute corresponding source code. (This alternative is
|
|
||||||
allowed only for noncommercial distribution and only if you
|
|
||||||
received the program in object code or executable form with such
|
|
||||||
an offer, in accord with Subsection b above.)
|
|
||||||
|
|
||||||
The source code for a work means the preferred form of the work for
|
|
||||||
making modifications to it. For an executable work, complete source
|
|
||||||
code means all the source code for all modules it contains, plus any
|
|
||||||
associated interface definition files, plus the scripts used to
|
|
||||||
control compilation and installation of the executable. However, as a
|
|
||||||
special exception, the source code distributed need not include
|
|
||||||
anything that is normally distributed (in either source or binary
|
|
||||||
form) with the major components (compiler, kernel, and so on) of the
|
|
||||||
operating system on which the executable runs, unless that component
|
|
||||||
itself accompanies the executable.
|
|
||||||
|
|
||||||
If distribution of executable or object code is made by offering
|
|
||||||
access to copy from a designated place, then offering equivalent
|
|
||||||
access to copy the source code from the same place counts as
|
|
||||||
distribution of the source code, even though third parties are not
|
|
||||||
compelled to copy the source along with the object code.
|
|
||||||
|
|
||||||
4. You may not copy, modify, sublicense, or distribute the Program
|
|
||||||
except as expressly provided under this License. Any attempt
|
|
||||||
otherwise to copy, modify, sublicense or distribute the Program is
|
|
||||||
void, and will automatically terminate your rights under this License.
|
|
||||||
However, parties who have received copies, or rights, from you under
|
|
||||||
this License will not have their licenses terminated so long as such
|
|
||||||
parties remain in full compliance.
|
|
||||||
|
|
||||||
5. You are not required to accept this License, since you have not
|
|
||||||
signed it. However, nothing else grants you permission to modify or
|
|
||||||
distribute the Program or its derivative works. These actions are
|
|
||||||
prohibited by law if you do not accept this License. Therefore, by
|
|
||||||
modifying or distributing the Program (or any work based on the
|
|
||||||
Program), you indicate your acceptance of this License to do so, and
|
|
||||||
all its terms and conditions for copying, distributing or modifying
|
|
||||||
the Program or works based on it.
|
|
||||||
|
|
||||||
6. Each time you redistribute the Program (or any work based on the
|
|
||||||
Program), the recipient automatically receives a license from the
|
|
||||||
original licensor to copy, distribute or modify the Program subject to
|
|
||||||
these terms and conditions. You may not impose any further
|
|
||||||
restrictions on the recipients' exercise of the rights granted herein.
|
|
||||||
You are not responsible for enforcing compliance by third parties to
|
|
||||||
this License.
|
|
||||||
|
|
||||||
7. If, as a consequence of a court judgment or allegation of patent
|
|
||||||
infringement or for any other reason (not limited to patent issues),
|
|
||||||
conditions are imposed on you (whether by court order, agreement or
|
|
||||||
otherwise) that contradict the conditions of this License, they do not
|
|
||||||
excuse you from the conditions of this License. If you cannot
|
|
||||||
distribute so as to satisfy simultaneously your obligations under this
|
|
||||||
License and any other pertinent obligations, then as a consequence you
|
|
||||||
may not distribute the Program at all. For example, if a patent
|
|
||||||
license would not permit royalty-free redistribution of the Program by
|
|
||||||
all those who receive copies directly or indirectly through you, then
|
|
||||||
the only way you could satisfy both it and this License would be to
|
|
||||||
refrain entirely from distribution of the Program.
|
|
||||||
|
|
||||||
If any portion of this section is held invalid or unenforceable under
|
|
||||||
any particular circumstance, the balance of the section is intended to
|
|
||||||
apply and the section as a whole is intended to apply in other
|
|
||||||
circumstances.
|
|
||||||
|
|
||||||
It is not the purpose of this section to induce you to infringe any
|
|
||||||
patents or other property right claims or to contest validity of any
|
|
||||||
such claims; this section has the sole purpose of protecting the
|
|
||||||
integrity of the free software distribution system, which is
|
|
||||||
implemented by public license practices. Many people have made
|
|
||||||
generous contributions to the wide range of software distributed
|
|
||||||
through that system in reliance on consistent application of that
|
|
||||||
system; it is up to the author/donor to decide if he or she is willing
|
|
||||||
to distribute software through any other system and a licensee cannot
|
|
||||||
impose that choice.
|
|
||||||
|
|
||||||
This section is intended to make thoroughly clear what is believed to
|
|
||||||
be a consequence of the rest of this License.
|
|
||||||
|
|
||||||
8. If the distribution and/or use of the Program is restricted in
|
|
||||||
certain countries either by patents or by copyrighted interfaces, the
|
|
||||||
original copyright holder who places the Program under this License
|
|
||||||
may add an explicit geographical distribution limitation excluding
|
|
||||||
those countries, so that distribution is permitted only in or among
|
|
||||||
countries not thus excluded. In such case, this License incorporates
|
|
||||||
the limitation as if written in the body of this License.
|
|
||||||
|
|
||||||
9. The Free Software Foundation may publish revised and/or new versions
|
|
||||||
of the General Public License from time to time. Such new versions will
|
|
||||||
be similar in spirit to the present version, but may differ in detail to
|
|
||||||
address new problems or concerns.
|
|
||||||
|
|
||||||
Each version is given a distinguishing version number. If the Program
|
|
||||||
specifies a version number of this License which applies to it and "any
|
|
||||||
later version", you have the option of following the terms and conditions
|
|
||||||
either of that version or of any later version published by the Free
|
|
||||||
Software Foundation. If the Program does not specify a version number of
|
|
||||||
this License, you may choose any version ever published by the Free Software
|
|
||||||
Foundation.
|
|
||||||
|
|
||||||
10. If you wish to incorporate parts of the Program into other free
|
|
||||||
programs whose distribution conditions are different, write to the author
|
|
||||||
to ask for permission. For software which is copyrighted by the Free
|
|
||||||
Software Foundation, write to the Free Software Foundation; we sometimes
|
|
||||||
make exceptions for this. Our decision will be guided by the two goals
|
|
||||||
of preserving the free status of all derivatives of our free software and
|
|
||||||
of promoting the sharing and reuse of software generally.
|
|
||||||
|
|
||||||
NO WARRANTY
|
|
||||||
|
|
||||||
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
|
|
||||||
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
|
|
||||||
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
|
|
||||||
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
|
|
||||||
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
|
||||||
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
|
|
||||||
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
|
|
||||||
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
|
|
||||||
REPAIR OR CORRECTION.
|
|
||||||
|
|
||||||
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
|
|
||||||
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
|
|
||||||
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
|
|
||||||
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
|
|
||||||
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
|
|
||||||
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
|
|
||||||
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
|
|
||||||
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
|
|
||||||
POSSIBILITY OF SUCH DAMAGES.
|
|
||||||
|
|
||||||
END OF TERMS AND CONDITIONS
|
|
||||||
|
|
||||||
How to Apply These Terms to Your New Programs
|
|
||||||
|
|
||||||
If you develop a new program, and you want it to be of the greatest
|
|
||||||
possible use to the public, the best way to achieve this is to make it
|
|
||||||
free software which everyone can redistribute and change under these terms.
|
|
||||||
|
|
||||||
To do so, attach the following notices to the program. It is safest
|
|
||||||
to attach them to the start of each source file to most effectively
|
|
||||||
convey the exclusion of warranty; and each file should have at least
|
|
||||||
the "copyright" line and a pointer to where the full notice is found.
|
|
||||||
|
|
||||||
{description}
|
|
||||||
Copyright (C) {year} {fullname}
|
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify
|
|
||||||
it under the terms of the GNU General Public License as published by
|
|
||||||
the Free Software Foundation; either version 2 of the License, or
|
|
||||||
(at your option) any later version.
|
|
||||||
|
|
||||||
This program is distributed in the hope that it will be useful,
|
|
||||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
GNU General Public License for more details.
|
|
||||||
|
|
||||||
You should have received a copy of the GNU General Public License along
|
|
||||||
with this program; if not, write to the Free Software Foundation, Inc.,
|
|
||||||
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
||||||
|
|
||||||
Also add information on how to contact you by electronic and paper mail.
|
|
||||||
|
|
||||||
If the program is interactive, make it output a short notice like this
|
|
||||||
when it starts in an interactive mode:
|
|
||||||
|
|
||||||
Gnomovision version 69, Copyright (C) year name of author
|
|
||||||
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
|
|
||||||
This is free software, and you are welcome to redistribute it
|
|
||||||
under certain conditions; type `show c' for details.
|
|
||||||
|
|
||||||
The hypothetical commands `show w' and `show c' should show the appropriate
|
|
||||||
parts of the General Public License. Of course, the commands you use may
|
|
||||||
be called something other than `show w' and `show c'; they could even be
|
|
||||||
mouse-clicks or menu items--whatever suits your program.
|
|
||||||
|
|
||||||
You should also get your employer (if you work as a programmer) or your
|
|
||||||
school, if any, to sign a "copyright disclaimer" for the program, if
|
|
||||||
necessary. Here is a sample; alter the names:
|
|
||||||
|
|
||||||
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
|
|
||||||
`Gnomovision' (which makes passes at compilers) written by James Hacker.
|
|
||||||
|
|
||||||
{signature of Ty Coon}, 1 April 1989
|
|
||||||
Ty Coon, President of Vice
|
|
||||||
|
|
||||||
This General Public License does not permit incorporating your program into
|
|
||||||
proprietary programs. If your program is a subroutine library, you may
|
|
||||||
consider it more useful to permit linking proprietary applications with the
|
|
||||||
library. If this is what you want to do, use the GNU Lesser General
|
|
||||||
Public License instead of this License.
|
|
||||||
|
|
@ -1,41 +0,0 @@
|
||||||
RPCS3
|
|
||||||
=====
|
|
||||||
|
|
||||||
[](https://dev.azure.com/nekotekina/nekotekina/_build?definitionId=8&_a=summary&repositoryFilter=4)
|
|
||||||
[](https://cirrus-ci.com/github/RPCS3/rpcs3)
|
|
||||||
[](https://github.com/RPCS3/rpcs3/actions/workflows/rpcs3.yml)
|
|
||||||
[](https://discord.me/rpcs3)
|
|
||||||
|
|
||||||
The world's first free and open-source PlayStation 3 emulator/debugger, written in C++ for Windows, Linux, macOS and FreeBSD.
|
|
||||||
|
|
||||||
You can find some basic information on our [**website**](https://rpcs3.net/). Game info is being populated on the [**Wiki**](https://wiki.rpcs3.net/).
|
|
||||||
For discussion about this emulator, PS3 emulation, and game compatibility reports, please visit our [**forums**](https://forums.rpcs3.net) and our [**Discord server**](https://discord.gg/RPCS3).
|
|
||||||
|
|
||||||
[**Support Lead Developers Nekotekina and kd-11 on Patreon**](https://www.patreon.com/Nekotekina)
|
|
||||||
|
|
||||||
## Contributing
|
|
||||||
|
|
||||||
If you want to help the project but do not code, the best way to help out is to test games and make bug reports. See:
|
|
||||||
* [Quickstart](https://rpcs3.net/quickstart)
|
|
||||||
|
|
||||||
If you want to contribute as a developer, please take a look at the following pages:
|
|
||||||
|
|
||||||
* [Coding Style](https://github.com/RPCS3/rpcs3/wiki/Coding-Style)
|
|
||||||
* [Developer Information](https://github.com/RPCS3/rpcs3/wiki/Developer-Information)
|
|
||||||
* [Roadmap](https://rpcs3.net/roadmap)
|
|
||||||
|
|
||||||
You should also contact any of the developers in the forums or in the Discord server to learn more about the current state of the emulator.
|
|
||||||
|
|
||||||
## Building
|
|
||||||
|
|
||||||
See [BUILDING.md](BUILDING.md) for more information about how to setup an environment to build RPCS3.
|
|
||||||
|
|
||||||
## Running
|
|
||||||
|
|
||||||
Check our friendly [quickstart](https://rpcs3.net/quickstart) guide to make sure your computer meets the minimum system requirements to run RPCS3.
|
|
||||||
|
|
||||||
Don't forget to have your graphics driver up to date and to install the [Visual C++ Redistributable Packages for Visual Studio 2019](https://aka.ms/vs/16/release/VC_redist.x64.exe) if you are a Windows user.
|
|
||||||
|
|
||||||
## License
|
|
||||||
|
|
||||||
Most files are licensed under the terms of GNU GPL-2.0-only License; see LICENSE file for details. Some files may be licensed differently; check appropriate file headers for details.
|
|
||||||
|
|
@ -226,7 +226,7 @@ void* jit_runtime_base::_add(asmjit::CodeHolder* code, usz align) noexcept
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
auto p = ensure(this->_alloc(codeSize, align));
|
auto p = ensure(this->_alloc(codeSize, align));
|
||||||
ensure(!code->relocateToBase(uptr(p)));
|
code->relocateToBase(uptr(p));
|
||||||
|
|
||||||
{
|
{
|
||||||
// We manage rw <-> rx transitions manually on Apple
|
// We manage rw <-> rx transitions manually on Apple
|
||||||
|
|
|
||||||
|
|
@ -1,260 +0,0 @@
|
||||||
trigger:
|
|
||||||
branches:
|
|
||||||
include:
|
|
||||||
- master
|
|
||||||
tags:
|
|
||||||
exclude:
|
|
||||||
- '*'
|
|
||||||
pr:
|
|
||||||
branches:
|
|
||||||
include:
|
|
||||||
- master
|
|
||||||
jobs:
|
|
||||||
# - job: Linux_Build
|
|
||||||
# strategy:
|
|
||||||
# matrix:
|
|
||||||
# Clang:
|
|
||||||
# COMPILER: clang
|
|
||||||
# GCC:
|
|
||||||
# COMPILER: gcc
|
|
||||||
# variables:
|
|
||||||
# CCACHE_DIR: $(Pipeline.Workspace)/ccache
|
|
||||||
# CI_HAS_ARTIFACTS: true
|
|
||||||
# UPLOAD_COMMIT_HASH: d812f1254a1157c80fd402f94446310560f54e5f
|
|
||||||
# UPLOAD_REPO_FULL_NAME: "RPCS3/rpcs3-binaries-linux"
|
|
||||||
# DEPLOY_APPIMAGE: true
|
|
||||||
# APPDIR: "/rpcs3/build/appdir"
|
|
||||||
# ARTDIR: "/root/artifacts"
|
|
||||||
# RELEASE_MESSAGE: "/rpcs3/GitHubReleaseMessage.txt"
|
|
||||||
|
|
||||||
# pool:
|
|
||||||
# vmImage: 'ubuntu-latest'
|
|
||||||
|
|
||||||
# steps:
|
|
||||||
# - task: Cache@2
|
|
||||||
# inputs:
|
|
||||||
# key: ccache | $(Agent.OS) | $(COMPILER) | $(Build.SourceVersion)
|
|
||||||
# restoreKeys: |
|
|
||||||
# ccache | $(Agent.OS) | $(COMPILER)
|
|
||||||
# path: $(CCACHE_DIR)
|
|
||||||
# displayName: ccache
|
|
||||||
|
|
||||||
# - bash: |
|
|
||||||
# docker pull --quiet rpcs3/rpcs3-ci-jammy:1.4
|
|
||||||
# docker run \
|
|
||||||
# -v $(pwd):/rpcs3 \
|
|
||||||
# --env-file .ci/docker.env \
|
|
||||||
# -v $CCACHE_DIR:/root/.ccache \
|
|
||||||
# -v $BUILD_ARTIFACTSTAGINGDIRECTORY:/root/artifacts \
|
|
||||||
# rpcs3/rpcs3-ci-jammy:1.4 \
|
|
||||||
# /rpcs3/.ci/build-linux.sh
|
|
||||||
# displayName: Docker setup and build
|
|
||||||
|
|
||||||
# - publish: $(Build.ArtifactStagingDirectory)
|
|
||||||
# condition: succeeded()
|
|
||||||
# artifact: RPCS3 for Linux ($(COMPILER))
|
|
||||||
|
|
||||||
# - bash: |
|
|
||||||
# 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)
|
|
||||||
|
|
||||||
# export AVVER="${COMM_TAG}-${COMM_COUNT}"
|
|
||||||
|
|
||||||
# .ci/github-upload.sh
|
|
||||||
# condition: and(ne(variables['Build.Reason'], 'PullRequest'), eq(variables['Build.Repository.Name'], 'RPCS3/rpcs3'), eq(variables['Build.SourceBranch'], 'refs/heads/master'), eq(variables['COMPILER'], 'clang'))
|
|
||||||
# displayName: Push build to GitHub
|
|
||||||
# env:
|
|
||||||
# RPCS3_TOKEN: $(RPCS3-Token)
|
|
||||||
|
|
||||||
# - job: Windows_Build
|
|
||||||
# variables:
|
|
||||||
# COMPILER: msvc
|
|
||||||
# QT_VER_MAIN: '6'
|
|
||||||
# QT_VER: '6.8.3'
|
|
||||||
# QT_VER_MSVC: 'msvc2022'
|
|
||||||
# QT_DATE: '202503201308'
|
|
||||||
# QTDIR: C:\Qt\$(QT_VER)\$(QT_VER_MSVC)_64
|
|
||||||
# LLVM_VER: '19.1.7'
|
|
||||||
# VULKAN_VER: '1.3.268.0'
|
|
||||||
# VULKAN_SDK_SHA: '8459ef49bd06b697115ddd3d97c9aec729e849cd775f5be70897718a9b3b9db5'
|
|
||||||
# VULKAN_SDK: C:\VulkanSDK\$(VULKAN_VER)
|
|
||||||
# CCACHE_SHA: '6252f081876a9a9f700fae13a5aec5d0d486b28261d7f1f72ac11c7ad9df4da9'
|
|
||||||
# CCACHE_BIN_DIR: 'C:\ccache_bin'
|
|
||||||
# CCACHE_DIR: 'C:\ccache'
|
|
||||||
# CCACHE_INODECACHE: 'true'
|
|
||||||
# CCACHE_SLOPPINESS: 'time_macros'
|
|
||||||
# DEPS_CACHE_DIR: ./dependency_cache
|
|
||||||
# UPLOAD_COMMIT_HASH: 7d09e3be30805911226241afbb14f8cdc2eb054e
|
|
||||||
# UPLOAD_REPO_FULL_NAME: "RPCS3/rpcs3-binaries-win"
|
|
||||||
|
|
||||||
# pool:
|
|
||||||
# vmImage: "windows-latest"
|
|
||||||
|
|
||||||
# steps:
|
|
||||||
# - bash: .ci/get_keys-windows.sh
|
|
||||||
# displayName: Get Cache Keys
|
|
||||||
|
|
||||||
# - task: Cache@2
|
|
||||||
# inputs:
|
|
||||||
# key: ccache | $(Agent.OS) | $(COMPILER) | "$(Build.SourceVersion)"
|
|
||||||
# path: $(CCACHE_DIR)
|
|
||||||
# restoreKeys:
|
|
||||||
# ccache | $(Agent.OS) | $(COMPILER)
|
|
||||||
# displayName: Build Ccache
|
|
||||||
|
|
||||||
# - task: Cache@2
|
|
||||||
# inputs:
|
|
||||||
# key: $(Agent.OS) | $(COMPILER) | "$(QT_VER)" | $(VULKAN_SDK_SHA) | $(CCACHE_SHA) | llvm.lock | glslang.lock
|
|
||||||
# path: $(DEPS_CACHE_DIR)
|
|
||||||
# displayName: Dependencies Cache
|
|
||||||
|
|
||||||
# - bash: .ci/setup-windows.sh
|
|
||||||
# displayName: Download and unpack dependencies
|
|
||||||
|
|
||||||
# - bash: .ci/export-azure-vars.sh
|
|
||||||
# displayName: Export Variables
|
|
||||||
|
|
||||||
# - task: VSBuild@1
|
|
||||||
# inputs:
|
|
||||||
# solution: 'rpcs3.sln'
|
|
||||||
# maximumCpuCount: true
|
|
||||||
# platform: x64
|
|
||||||
# configuration: 'Release'
|
|
||||||
# msbuildArgs: /p:CLToolPath=$(CCACHE_BIN_DIR) /p:UseMultiToolTask=true /p:CustomAfterMicrosoftCommonTargets="$(Build.SourcesDirectory)\buildfiles\msvc\ci_only.targets"
|
|
||||||
# displayName: Compile RPCS3
|
|
||||||
|
|
||||||
# - bash: .ci/deploy-windows.sh
|
|
||||||
# displayName: Pack up build artifacts
|
|
||||||
|
|
||||||
# - publish: $(Build.ArtifactStagingDirectory)
|
|
||||||
# condition: succeeded()
|
|
||||||
# artifact: RPCS3 for Windows
|
|
||||||
|
|
||||||
# - bash: .ci/github-upload.sh
|
|
||||||
# condition: and(ne(variables['Build.Reason'], 'PullRequest'), eq(variables['Build.Repository.Name'], 'RPCS3/rpcs3'), eq(variables['Build.SourceBranch'], 'refs/heads/master'))
|
|
||||||
# displayName: Push build to GitHub
|
|
||||||
# env:
|
|
||||||
# RPCS3_TOKEN: $(RPCS3-Token)
|
|
||||||
|
|
||||||
- job: Mac_Build_x86_64
|
|
||||||
timeoutInMinutes: 180
|
|
||||||
variables:
|
|
||||||
CCACHE_DIR: "/tmp/ccache_dir"
|
|
||||||
CCACHE_MAXSIZE: 300M
|
|
||||||
CI_HAS_ARTIFACTS: true
|
|
||||||
UPLOAD_COMMIT_HASH: 51ae32f468089a8169aaf1567de355ff4a3e0842
|
|
||||||
UPLOAD_REPO_FULL_NAME: "RPCS3/rpcs3-binaries-mac"
|
|
||||||
RELEASE_MESSAGE: "../GitHubReleaseMessage.txt"
|
|
||||||
ARTDIR: $(Build.ArtifactStagingDirectory)
|
|
||||||
QT_VER: '6.7.3'
|
|
||||||
QT_VER_MAIN: '6'
|
|
||||||
LLVM_COMPILER_VER: '19'
|
|
||||||
|
|
||||||
pool:
|
|
||||||
vmImage: "macOS-14"
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- task: Cache@2
|
|
||||||
inputs:
|
|
||||||
key: ccache | "$(Agent.OS)" | "$(Agent.OSArchitecture)" | "$(Build.SourceVersion)"
|
|
||||||
path: $(CCACHE_DIR)
|
|
||||||
restoreKeys: |
|
|
||||||
ccache | "$(Agent.OS)" | "$(Agent.OSArchitecture)"
|
|
||||||
displayName: Ccache cache
|
|
||||||
|
|
||||||
- task: Cache@2
|
|
||||||
inputs:
|
|
||||||
key: qt | "$(Agent.OS)" | "$(Agent.OSArchitecture)" | "$(QT_VER)"
|
|
||||||
path: /tmp/Qt
|
|
||||||
restoreKeys: |
|
|
||||||
qt | "$(Agent.OS)" | "$(Agent.OSArchitecture)" | "$(QT_VER)"
|
|
||||||
displayName: Qt cache
|
|
||||||
|
|
||||||
# - task: Cache@2
|
|
||||||
# inputs:
|
|
||||||
# key: brew | "$(Agent.OS)"
|
|
||||||
# path: /Users/runner/Library/Caches/Homebrew
|
|
||||||
# restoreKeys: |
|
|
||||||
# brew | "$(Agent.OS)"
|
|
||||||
# displayName: Homebrew cache
|
|
||||||
|
|
||||||
- bash: |
|
|
||||||
chmod +x ".ci/build-mac.sh"
|
|
||||||
chmod +x ".ci/deploy-mac.sh"
|
|
||||||
chmod +x ".ci/optimize-mac.sh"
|
|
||||||
".ci/build-mac.sh"
|
|
||||||
displayName: Build macOS (x86_64)
|
|
||||||
|
|
||||||
- publish: $(Build.ArtifactStagingDirectory)
|
|
||||||
condition: succeeded()
|
|
||||||
artifact: RPCS3 for Mac (Intel)
|
|
||||||
|
|
||||||
- bash: |
|
|
||||||
source './.ci/export-cirrus-vars.sh'
|
|
||||||
.ci/github-upload.sh
|
|
||||||
condition: and(ne(variables['Build.Reason'], 'PullRequest'), eq(variables['Build.Repository.Name'], 'RPCS3/rpcs3'), eq(variables['Build.SourceBranch'], 'refs/heads/master'))
|
|
||||||
displayName: Push build to GitHub
|
|
||||||
env:
|
|
||||||
RPCS3_TOKEN: $(RPCS3-Token)
|
|
||||||
|
|
||||||
- job: Mac_Build_arm64
|
|
||||||
timeoutInMinutes: 180
|
|
||||||
variables:
|
|
||||||
CCACHE_DIR: "/tmp/ccache_dir"
|
|
||||||
CCACHE_MAXSIZE: 300M
|
|
||||||
CI_HAS_ARTIFACTS: true
|
|
||||||
UPLOAD_COMMIT_HASH: 8e21bdbc40711a3fccd18fbf17b742348b0f4281
|
|
||||||
UPLOAD_REPO_FULL_NAME: "RPCS3/rpcs3-binaries-mac-arm64"
|
|
||||||
RELEASE_MESSAGE: "../GitHubReleaseMessage.txt"
|
|
||||||
ARTDIR: $(Build.ArtifactStagingDirectory)
|
|
||||||
QT_VER: '6.7.3'
|
|
||||||
QT_VER_MAIN: '6'
|
|
||||||
LLVM_COMPILER_VER: '19'
|
|
||||||
|
|
||||||
pool:
|
|
||||||
vmImage: "macOS-14"
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- task: Cache@2
|
|
||||||
inputs:
|
|
||||||
key: ccache | "$(Agent.OS)" | "$(Agent.OSArchitecture)" | "$(Build.SourceVersion)"
|
|
||||||
path: $(CCACHE_DIR)
|
|
||||||
restoreKeys: |
|
|
||||||
ccache | "$(Agent.OS)" | "$(Agent.OSArchitecture)"
|
|
||||||
displayName: Ccache cache
|
|
||||||
|
|
||||||
- task: Cache@2
|
|
||||||
inputs:
|
|
||||||
key: qt | "$(Agent.OS)" | "$(Agent.OSArchitecture)" | "$(QT_VER)"
|
|
||||||
path: /tmp/Qt
|
|
||||||
restoreKeys: |
|
|
||||||
qt | "$(Agent.OS)" | "$(Agent.OSArchitecture)" | "$(QT_VER)"
|
|
||||||
displayName: Qt cache
|
|
||||||
|
|
||||||
# - task: Cache@2
|
|
||||||
# inputs:
|
|
||||||
# key: brew | "$(Agent.OS)"
|
|
||||||
# path: /Users/runner/Library/Caches/Homebrew
|
|
||||||
# restoreKeys: |
|
|
||||||
# brew | "$(Agent.OS)"
|
|
||||||
# displayName: Homebrew cache
|
|
||||||
|
|
||||||
- bash: |
|
|
||||||
chmod +x ".ci/build-mac-arm64.sh"
|
|
||||||
chmod +x ".ci/deploy-mac-arm64.sh"
|
|
||||||
chmod +x ".ci/optimize-mac.sh"
|
|
||||||
".ci/build-mac-arm64.sh"
|
|
||||||
displayName: Build macOS (arm64)
|
|
||||||
|
|
||||||
- publish: $(Build.ArtifactStagingDirectory)
|
|
||||||
condition: succeeded()
|
|
||||||
artifact: RPCS3 for Mac (Apple Silicon)
|
|
||||||
|
|
||||||
- bash: |
|
|
||||||
source './.ci/export-cirrus-vars.sh'
|
|
||||||
.ci/github-upload.sh
|
|
||||||
condition: and(ne(variables['Build.Reason'], 'PullRequest'), eq(variables['Build.Repository.Name'], 'RPCS3/rpcs3'), eq(variables['Build.SourceBranch'], 'refs/heads/master'))
|
|
||||||
displayName: Push build to GitHub
|
|
||||||
env:
|
|
||||||
RPCS3_TOKEN: $(RPCS3-Token)
|
|
||||||
|
|
@ -1,12 +0,0 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
|
||||||
<ItemDefinitionGroup>
|
|
||||||
<ClCompile>
|
|
||||||
<DebugInformationFormat>None</DebugInformationFormat>
|
|
||||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
|
||||||
</ClCompile>
|
|
||||||
<Link>
|
|
||||||
<LinkTimeCodeGeneration>UseLinkTimeCodeGeneration</LinkTimeCodeGeneration>
|
|
||||||
</Link>
|
|
||||||
</ItemDefinitionGroup>
|
|
||||||
</Project>
|
|
||||||
|
|
@ -1,10 +0,0 @@
|
||||||
#!/bin/bash
|
|
||||||
|
|
||||||
# git pre-commit hook that run git-clang-format when committing.
|
|
||||||
# To use it install clang-format and python 2.7 then copy this
|
|
||||||
# file to .git/hooks/ and remove the extension
|
|
||||||
|
|
||||||
git clang-format --style=file --diff > style.patch
|
|
||||||
git apply --index style.patch
|
|
||||||
rm style.patch
|
|
||||||
exit 0
|
|
||||||
|
|
@ -20,75 +20,38 @@ elseif(NOT WIN32 AND NOT CMAKE_CXX_FLAGS MATCHES "LIBICONV_PLUG")
|
||||||
set(ADDITIONAL_LIBS ${ADDITIONAL_LIBS} "iconv")
|
set(ADDITIONAL_LIBS ${ADDITIONAL_LIBS} "iconv")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
# subdirectories
|
||||||
|
add_subdirectory(Emu)
|
||||||
|
|
||||||
if(UNIX AND NOT APPLE AND NOT ANDROID)
|
if(UNIX AND NOT APPLE AND NOT ANDROID)
|
||||||
add_definitions(-DDATADIR="${CMAKE_INSTALL_FULL_DATADIR}/rpcs3")
|
add_definitions(-DDATADIR="${CMAKE_INSTALL_FULL_DATADIR}/rpcs3")
|
||||||
# Optionally enable X11 for window management
|
# Optionally enable X11 for window management
|
||||||
find_package(X11)
|
find_package(X11)
|
||||||
if(X11_FOUND)
|
if(X11_FOUND)
|
||||||
add_definitions(-DHAVE_X11)
|
target_compile_definitions(rpcs3_emu PUBLIC -DHAVE_X11)
|
||||||
endif()
|
endif()
|
||||||
find_package(Wayland)
|
find_package(Wayland)
|
||||||
if(WAYLAND_FOUND)
|
if(WAYLAND_FOUND)
|
||||||
add_definitions(-DHAVE_WAYLAND)
|
target_compile_definitions(rpcs3_emu PUBLIC -DHAVE_WAYLAND)
|
||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (NOT ANDROID)
|
|
||||||
# Qt
|
|
||||||
# finds Qt libraries and setups custom commands for MOC and UIC
|
|
||||||
# Must be done here because generated MOC and UIC targets cant
|
|
||||||
# be found otherwise
|
|
||||||
include(${CMAKE_SOURCE_DIR}/3rdparty/qt6.cmake)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
# subdirectories
|
|
||||||
add_subdirectory(Emu)
|
|
||||||
|
|
||||||
if (NOT ANDROID)
|
|
||||||
add_subdirectory(rpcs3qt)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
gen_git_version(${CMAKE_CURRENT_SOURCE_DIR})
|
gen_git_version(${CMAKE_CURRENT_SOURCE_DIR})
|
||||||
|
|
||||||
if (NOT ANDROID)
|
add_library(rpcs3 STATIC
|
||||||
if(WIN32)
|
|
||||||
add_executable(rpcs3 WIN32)
|
|
||||||
target_sources(rpcs3 PRIVATE rpcs3.rc)
|
|
||||||
target_compile_definitions(rpcs3 PRIVATE UNICODE _UNICODE)
|
|
||||||
elseif(APPLE)
|
|
||||||
add_executable(rpcs3 MACOSX_BUNDLE)
|
|
||||||
target_sources(rpcs3 PRIVATE rpcs3.icns update_helper.sh)
|
|
||||||
set_source_files_properties(update_helper.sh PROPERTIES MACOSX_PACKAGE_LOCATION Resources)
|
|
||||||
set_target_properties(rpcs3
|
|
||||||
PROPERTIES
|
|
||||||
MACOSX_BUNDLE_INFO_PLIST "${CMAKE_CURRENT_SOURCE_DIR}/rpcs3.plist.in")
|
|
||||||
else()
|
|
||||||
add_executable(rpcs3)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
target_sources(rpcs3
|
|
||||||
PRIVATE
|
|
||||||
display_sleep_control.cpp
|
|
||||||
headless_application.cpp
|
|
||||||
main.cpp
|
|
||||||
main_application.cpp
|
|
||||||
module_verifier.cpp
|
|
||||||
rpcs3_version.cpp
|
rpcs3_version.cpp
|
||||||
|
module_verifier.cpp
|
||||||
stb_image.cpp
|
stb_image.cpp
|
||||||
stdafx.cpp
|
|
||||||
|
|
||||||
dev/iso.cpp
|
dev/iso.cpp
|
||||||
|
|
||||||
Input/basic_keyboard_handler.cpp
|
|
||||||
Input/basic_mouse_handler.cpp
|
|
||||||
Input/ds3_pad_handler.cpp
|
Input/ds3_pad_handler.cpp
|
||||||
Input/ds4_pad_handler.cpp
|
Input/ds4_pad_handler.cpp
|
||||||
Input/dualsense_pad_handler.cpp
|
Input/dualsense_pad_handler.cpp
|
||||||
Input/evdev_joystick_handler.cpp
|
Input/evdev_joystick_handler.cpp
|
||||||
Input/evdev_gun_handler.cpp
|
Input/evdev_gun_handler.cpp
|
||||||
Input/gui_pad_thread.cpp
|
|
||||||
Input/hid_pad_handler.cpp
|
Input/hid_pad_handler.cpp
|
||||||
Input/keyboard_pad_handler.cpp
|
|
||||||
Input/mm_joystick_handler.cpp
|
Input/mm_joystick_handler.cpp
|
||||||
Input/pad_thread.cpp
|
Input/pad_thread.cpp
|
||||||
Input/product_info.cpp
|
Input/product_info.cpp
|
||||||
|
|
@ -102,105 +65,33 @@ if (NOT ANDROID)
|
||||||
Input/skateboard_pad_handler.cpp
|
Input/skateboard_pad_handler.cpp
|
||||||
Input/xinput_pad_handler.cpp
|
Input/xinput_pad_handler.cpp
|
||||||
Input/virtual_pad_handler.cpp
|
Input/virtual_pad_handler.cpp
|
||||||
)
|
)
|
||||||
|
|
||||||
set_target_properties(rpcs3
|
target_link_libraries(rpcs3 PUBLIC
|
||||||
PROPERTIES
|
|
||||||
AUTOMOC ON
|
|
||||||
AUTOUIC ON)
|
|
||||||
|
|
||||||
target_link_libraries(rpcs3
|
|
||||||
PRIVATE
|
|
||||||
rpcs3_emu
|
rpcs3_emu
|
||||||
rpcs3_ui
|
3rdparty::zlib
|
||||||
|
3rdparty::pugixml
|
||||||
3rdparty::discordRPC
|
3rdparty::discordRPC
|
||||||
3rdparty::qt6
|
|
||||||
3rdparty::hidapi
|
3rdparty::hidapi
|
||||||
3rdparty::libusb
|
3rdparty::libusb
|
||||||
|
3rdparty::libpng
|
||||||
|
3rdparty::7zip
|
||||||
3rdparty::wolfssl
|
3rdparty::wolfssl
|
||||||
3rdparty::libcurl
|
3rdparty::libcurl
|
||||||
3rdparty::zlib
|
|
||||||
3rdparty::opencv
|
3rdparty::opencv
|
||||||
3rdparty::fusion
|
3rdparty::fusion
|
||||||
${ADDITIONAL_LIBS})
|
3rdparty::rtmidi
|
||||||
|
${ADDITIONAL_LIBS}
|
||||||
|
)
|
||||||
|
|
||||||
# Unix display manager
|
if(USE_PRECOMPILED_HEADERS)
|
||||||
if(X11_FOUND)
|
target_precompile_headers(rpcs3 PUBLIC stdafx.h)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Unix display manager
|
||||||
|
if(X11_FOUND)
|
||||||
target_link_libraries(rpcs3 PRIVATE X11::X11)
|
target_link_libraries(rpcs3 PRIVATE X11::X11)
|
||||||
elseif(USE_VULKAN AND UNIX AND NOT WAYLAND_FOUND AND NOT APPLE AND NOT ANDROID)
|
elseif(USE_VULKAN AND UNIX AND NOT WAYLAND_FOUND AND NOT APPLE AND NOT ANDROID)
|
||||||
# Wayland has been checked in 3rdparty/CMakeLists.txt already.
|
# Wayland has been checked in 3rdparty/CMakeLists.txt already.
|
||||||
message(FATAL_ERROR "RPCS3 requires either X11 or Wayland (or both) for Vulkan.")
|
message(FATAL_ERROR "RPCS3 requires either X11 or Wayland (or both) for Vulkan.")
|
||||||
endif()
|
|
||||||
|
|
||||||
if(UNIX)
|
|
||||||
set(CMAKE_THREAD_PREFER_PTHREAD TRUE)
|
|
||||||
find_package(Threads REQUIRED)
|
|
||||||
target_link_libraries(rpcs3 PRIVATE Threads::Threads)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if(WIN32)
|
|
||||||
target_link_libraries(rpcs3 PRIVATE bcrypt ws2_32 Iphlpapi Winmm Psapi gdi32 setupapi pdh)
|
|
||||||
else()
|
|
||||||
target_link_libraries(rpcs3 PRIVATE ${CMAKE_DL_LIBS})
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if(USE_PRECOMPILED_HEADERS)
|
|
||||||
target_precompile_headers(rpcs3 PRIVATE stdafx.h)
|
|
||||||
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(rpcs3)
|
|
||||||
add_custom_command(TARGET rpcs3 POST_BUILD
|
|
||||||
COMMAND ${CMAKE_COMMAND} -E copy ${CMAKE_CURRENT_SOURCE_DIR}/rpcs3.icns $<TARGET_FILE_DIR:rpcs3>/../Resources/rpcs3.icns
|
|
||||||
COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/bin/Icons $<TARGET_FILE_DIR:rpcs3>/../Resources/Icons
|
|
||||||
COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/bin/GuiConfigs $<TARGET_FILE_DIR:rpcs3>/../Resources/GuiConfigs
|
|
||||||
COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/bin/git $<TARGET_FILE_DIR:rpcs3>/../Resources/git
|
|
||||||
COMMAND "${MACDEPLOYQT_EXECUTABLE}" "${PROJECT_BINARY_DIR}/bin/rpcs3.app" "${QT_DEPLOY_FLAGS}")
|
|
||||||
elseif(UNIX)
|
|
||||||
add_custom_command(TARGET rpcs3 POST_BUILD
|
|
||||||
COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/bin/Icons $<TARGET_FILE_DIR:rpcs3>/Icons
|
|
||||||
COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/bin/GuiConfigs $<TARGET_FILE_DIR:rpcs3>/GuiConfigs
|
|
||||||
COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/bin/git $<TARGET_FILE_DIR:rpcs3>/git)
|
|
||||||
elseif(WIN32)
|
|
||||||
add_custom_command(TARGET rpcs3 POST_BUILD
|
|
||||||
COMMAND ${CMAKE_COMMAND} -E copy $<TARGET_FILE:OpenAL::OpenAL> $<TARGET_FILE_DIR:rpcs3>
|
|
||||||
COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/bin/Icons $<TARGET_FILE_DIR:rpcs3>/Icons
|
|
||||||
COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/bin/GuiConfigs $<TARGET_FILE_DIR:rpcs3>/GuiConfigs
|
|
||||||
COMMAND ${CMAKE_COMMAND} -E copy_directory ${CMAKE_SOURCE_DIR}/bin/git $<TARGET_FILE_DIR:rpcs3>/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:rpcs3>/plugins,$<TARGET_FILE_DIR:rpcs3>/share/qt6/plugins>"
|
|
||||||
--verbose 0 "$<TARGET_FILE:rpcs3>")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
# Unix installation
|
|
||||||
if(UNIX AND NOT APPLE)
|
|
||||||
# Install the binary
|
|
||||||
install(TARGETS rpcs3 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 ../bin/Icons
|
|
||||||
DESTINATION ${CMAKE_INSTALL_DATADIR}/rpcs3)
|
|
||||||
install(DIRECTORY ../bin/GuiConfigs
|
|
||||||
DESTINATION ${CMAKE_INSTALL_DATADIR}/rpcs3)
|
|
||||||
install(DIRECTORY ../bin/git
|
|
||||||
DESTINATION ${CMAKE_INSTALL_DATADIR}/rpcs3)
|
|
||||||
install(DIRECTORY ../bin/test
|
|
||||||
DESTINATION ${CMAKE_INSTALL_DATADIR}/rpcs3)
|
|
||||||
endif()
|
|
||||||
endif()
|
endif()
|
||||||
|
|
|
||||||
|
|
@ -667,7 +667,3 @@ endif()
|
||||||
if(USE_PRECOMPILED_HEADERS)
|
if(USE_PRECOMPILED_HEADERS)
|
||||||
target_precompile_headers(rpcs3_emu PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/../stdafx.h")
|
target_precompile_headers(rpcs3_emu PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/../stdafx.h")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(WAYLAND_FOUND)
|
|
||||||
target_link_libraries(rpcs3_emu PRIVATE OpenGL::EGL)
|
|
||||||
endif()
|
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,9 @@
|
||||||
#pragma clang diagnostic ignored "-Winconsistent-missing-override"
|
#pragma clang diagnostic ignored "-Winconsistent-missing-override"
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
#include "3rdparty/glslang/glslang/SPIRV/GlslangToSpv.h"
|
#include "SPIRV/GlslangToSpv.h"
|
||||||
|
#include "glslang/Include/ResourceLimits.h"
|
||||||
|
#include "glslang/Public/ShaderLang.h"
|
||||||
#ifdef _MSC_VER
|
#ifdef _MSC_VER
|
||||||
#pragma warning(pop)
|
#pragma warning(pop)
|
||||||
#else
|
#else
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "Emu/Io/pad_config_types.h"
|
||||||
#include "util/types.hpp"
|
#include "util/types.hpp"
|
||||||
#include "util/atomic.hpp"
|
#include "util/atomic.hpp"
|
||||||
#include "util/shared_ptr.hpp"
|
#include "util/shared_ptr.hpp"
|
||||||
|
|
@ -89,6 +90,7 @@ struct EmuCallbacks
|
||||||
std::function<std::unique_ptr<class GSFrameBase>()> get_gs_frame;
|
std::function<std::unique_ptr<class GSFrameBase>()> get_gs_frame;
|
||||||
std::function<std::shared_ptr<class camera_handler_base>()> get_camera_handler;
|
std::function<std::shared_ptr<class camera_handler_base>()> get_camera_handler;
|
||||||
std::function<std::shared_ptr<class music_handler_base>()> get_music_handler;
|
std::function<std::shared_ptr<class music_handler_base>()> get_music_handler;
|
||||||
|
std::function<std::shared_ptr<class PadHandlerBase>(pad_handler type, void* thread, void* window)> create_pad_handler;
|
||||||
std::function<void(utils::serial*)> init_gs_render;
|
std::function<void(utils::serial*)> init_gs_render;
|
||||||
std::function<std::shared_ptr<class AudioBackend>()> get_audio;
|
std::function<std::shared_ptr<class AudioBackend>()> get_audio;
|
||||||
std::function<std::shared_ptr<class audio_device_enumerator>(u64)> get_audio_enumerator; // (audio_renderer)
|
std::function<std::shared_ptr<class audio_device_enumerator>(u64)> get_audio_enumerator; // (audio_renderer)
|
||||||
|
|
@ -107,7 +109,7 @@ struct EmuCallbacks
|
||||||
std::string (*resolve_path)(std::string_view) = [](std::string_view arg)
|
std::string (*resolve_path)(std::string_view) = [](std::string_view arg)
|
||||||
{
|
{
|
||||||
return std::string{arg};
|
return std::string{arg};
|
||||||
}; // Resolve path using Qt
|
};
|
||||||
std::function<std::vector<std::string>()> get_font_dirs;
|
std::function<std::vector<std::string>()> get_font_dirs;
|
||||||
std::function<bool(const std::vector<std::string>&)> on_install_pkgs;
|
std::function<bool(const std::vector<std::string>&)> on_install_pkgs;
|
||||||
std::function<void(u32)> add_breakpoint;
|
std::function<void(u32)> add_breakpoint;
|
||||||
|
|
|
||||||
|
|
@ -15,9 +15,6 @@
|
||||||
#ifdef HAVE_SDL3
|
#ifdef HAVE_SDL3
|
||||||
#include "sdl_pad_handler.h"
|
#include "sdl_pad_handler.h"
|
||||||
#endif
|
#endif
|
||||||
#ifndef ANDROID
|
|
||||||
#include "keyboard_pad_handler.h"
|
|
||||||
#endif
|
|
||||||
#include "virtual_pad_handler.h"
|
#include "virtual_pad_handler.h"
|
||||||
#include "Emu/Io/Null/NullPadHandler.h"
|
#include "Emu/Io/Null/NullPadHandler.h"
|
||||||
#include "Emu/Io/interception.h"
|
#include "Emu/Io/interception.h"
|
||||||
|
|
@ -150,10 +147,6 @@ void pad_thread::Init()
|
||||||
|
|
||||||
input_log.trace("Using pad config:\n%s", g_cfg_input);
|
input_log.trace("Using pad config:\n%s", g_cfg_input);
|
||||||
|
|
||||||
#ifndef ANDROID
|
|
||||||
std::shared_ptr<keyboard_pad_handler> keyptr;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Always have a Null Pad Handler
|
// Always have a Null Pad Handler
|
||||||
std::shared_ptr<NullPadHandler> nullpad = std::make_shared<NullPadHandler>();
|
std::shared_ptr<NullPadHandler> nullpad = std::make_shared<NullPadHandler>();
|
||||||
m_handlers.emplace(pad_handler::null, nullpad);
|
m_handlers.emplace(pad_handler::null, nullpad);
|
||||||
|
|
@ -171,21 +164,7 @@ void pad_thread::Init()
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (handler_type == pad_handler::keyboard)
|
cur_pad_handler = GetHandler(handler_type, m_curthread, m_curwindow);
|
||||||
{
|
|
||||||
#ifndef ANDROID
|
|
||||||
keyptr = std::make_shared<keyboard_pad_handler>();
|
|
||||||
keyptr->moveToThread(static_cast<QThread*>(m_curthread));
|
|
||||||
keyptr->SetTargetWindow(static_cast<QWindow*>(m_curwindow));
|
|
||||||
cur_pad_handler = keyptr;
|
|
||||||
#else
|
|
||||||
cur_pad_handler = nullpad;
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
cur_pad_handler = GetHandler(handler_type);
|
|
||||||
}
|
|
||||||
m_handlers.emplace(handler_type, cur_pad_handler);
|
m_handlers.emplace(handler_type, cur_pad_handler);
|
||||||
}
|
}
|
||||||
cur_pad_handler->Init();
|
cur_pad_handler->Init();
|
||||||
|
|
@ -647,54 +626,16 @@ void pad_thread::UnregisterLddPad(u32 handle)
|
||||||
num_ldd_pad--;
|
num_ldd_pad--;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<PadHandlerBase> pad_thread::GetHandler(pad_handler type)
|
std::shared_ptr<PadHandlerBase> pad_thread::GetHandler(pad_handler type, void* thread, void* window)
|
||||||
{
|
{
|
||||||
switch (type)
|
return Emu.GetCallbacks().create_pad_handler(type, thread, window);
|
||||||
{
|
|
||||||
case pad_handler::null:
|
|
||||||
return std::make_shared<NullPadHandler>();
|
|
||||||
case pad_handler::keyboard:
|
|
||||||
#ifdef ANDROID
|
|
||||||
return std::make_shared<NullPadHandler>();
|
|
||||||
#else
|
|
||||||
return std::make_shared<keyboard_pad_handler>();
|
|
||||||
#endif
|
|
||||||
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>();
|
|
||||||
case pad_handler::move:
|
|
||||||
return std::make_shared<ps_move_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
|
|
||||||
case pad_handler::virtual_pad:
|
|
||||||
return std::make_shared<virtual_pad_handler>();
|
|
||||||
}
|
|
||||||
|
|
||||||
return nullptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void pad_thread::InitPadConfig(cfg_pad& cfg, pad_handler type, std::shared_ptr<PadHandlerBase>& handler)
|
void pad_thread::InitPadConfig(cfg_pad& cfg, pad_handler type, std::shared_ptr<PadHandlerBase>& handler)
|
||||||
{
|
{
|
||||||
if (!handler)
|
if (!handler)
|
||||||
{
|
{
|
||||||
handler = GetHandler(type);
|
handler = GetHandler(type, nullptr, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
ensure(!!handler);
|
ensure(!!handler);
|
||||||
|
|
|
||||||
|
|
@ -45,7 +45,7 @@ public:
|
||||||
return m_handlers;
|
return m_handlers;
|
||||||
}
|
}
|
||||||
|
|
||||||
static std::shared_ptr<PadHandlerBase> GetHandler(pad_handler type);
|
static std::shared_ptr<PadHandlerBase> GetHandler(pad_handler type, void* thread = nullptr, void* window = nullptr);
|
||||||
static void InitPadConfig(cfg_pad& cfg, pad_handler type, std::shared_ptr<PadHandlerBase>& handler);
|
static void InitPadConfig(cfg_pad& cfg, pad_handler type, std::shared_ptr<PadHandlerBase>& handler);
|
||||||
|
|
||||||
static auto constexpr thread_name = "Pad Thread"sv;
|
static auto constexpr thread_name = "Pad Thread"sv;
|
||||||
|
|
|
||||||
|
|
@ -1,174 +0,0 @@
|
||||||
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 PRIVATE WIN32_LEAN_AND_MEAN)
|
|
||||||
|
|
||||||
target_link_libraries(rpcs3_ui
|
|
||||||
PUBLIC
|
|
||||||
3rdparty::qt6
|
|
||||||
3rdparty::yaml-cpp
|
|
||||||
|
|
||||||
PRIVATE
|
|
||||||
rpcs3_emu
|
|
||||||
3rdparty::zlib
|
|
||||||
3rdparty::pugixml
|
|
||||||
3rdparty::discordRPC
|
|
||||||
3rdparty::hidapi
|
|
||||||
3rdparty::libusb
|
|
||||||
3rdparty::libpng
|
|
||||||
3rdparty::7zip
|
|
||||||
3rdparty::wolfssl
|
|
||||||
3rdparty::libcurl
|
|
||||||
3rdparty::opencv
|
|
||||||
3rdparty::fusion
|
|
||||||
3rdparty::rtmidi)
|
|
||||||
32
rpcs3qt-legacy/.clang-format
Normal file
|
|
@ -0,0 +1,32 @@
|
||||||
|
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
|
||||||
277
rpcs3qt-legacy/CMakeLists.txt
Normal file
|
|
@ -0,0 +1,277 @@
|
||||||
|
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 PRIVATE WIN32_LEAN_AND_MEAN)
|
||||||
|
|
||||||
|
target_link_libraries(rpcs3_ui
|
||||||
|
PUBLIC
|
||||||
|
3rdparty::qt6
|
||||||
|
3rdparty::yaml-cpp
|
||||||
|
rpcs3)
|
||||||
|
|
||||||
|
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 PRIVATE 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)
|
||||||
|
|
||||||
|
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 rpcs3/bin/Icons
|
||||||
|
DESTINATION ${CMAKE_INSTALL_DATADIR}/rpcs3)
|
||||||
|
install(DIRECTORY rpcs3/bin/GuiConfigs
|
||||||
|
DESTINATION ${CMAKE_INSTALL_DATADIR}/rpcs3)
|
||||||
|
install(DIRECTORY rpcs3/bin/git
|
||||||
|
DESTINATION ${CMAKE_INSTALL_DATADIR}/rpcs3)
|
||||||
|
install(DIRECTORY rpcs3/bin/test
|
||||||
|
DESTINATION ${CMAKE_INSTALL_DATADIR}/rpcs3)
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
Before Width: | Height: | Size: 4.8 KiB After Width: | Height: | Size: 4.8 KiB |
|
Before Width: | Height: | Size: 30 KiB After Width: | Height: | Size: 30 KiB |
|
Before Width: | Height: | Size: 8.9 KiB After Width: | Height: | Size: 8.9 KiB |
|
Before Width: | Height: | Size: 24 KiB After Width: | Height: | Size: 24 KiB |
|
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 17 KiB |
|
Before Width: | Height: | Size: 4.2 KiB After Width: | Height: | Size: 4.2 KiB |
|
Before Width: | Height: | Size: 3.9 KiB After Width: | Height: | Size: 3.9 KiB |
|
Before Width: | Height: | Size: 9.2 KiB After Width: | Height: | Size: 9.2 KiB |
|
Before Width: | Height: | Size: 4.3 KiB After Width: | Height: | Size: 4.3 KiB |
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 7.3 KiB After Width: | Height: | Size: 7.3 KiB |
|
Before Width: | Height: | Size: 7.8 KiB After Width: | Height: | Size: 7.8 KiB |
|
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 13 KiB |
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 4.3 KiB After Width: | Height: | Size: 4.3 KiB |
347
rpcs3qt-legacy/Input/basic_keyboard_handler.cpp
Normal file
|
|
@ -0,0 +1,347 @@
|
||||||
|
#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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
26
rpcs3qt-legacy/Input/basic_keyboard_handler.h
Normal file
|
|
@ -0,0 +1,26 @@
|
||||||
|
#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;
|
||||||
|
};
|
||||||
280
rpcs3qt-legacy/Input/basic_mouse_handler.cpp
Normal file
|
|
@ -0,0 +1,280 @@
|
||||||
|
#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());
|
||||||
|
}
|
||||||
|
}
|
||||||
44
rpcs3qt-legacy/Input/basic_mouse_handler.h
Normal file
|
|
@ -0,0 +1,44 @@
|
||||||
|
#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;
|
||||||
|
};
|
||||||
815
rpcs3qt-legacy/Input/gui_pad_thread.cpp
Normal file
|
|
@ -0,0 +1,815 @@
|
||||||
|
#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
|
||||||
|
}
|
||||||
101
rpcs3qt-legacy/Input/gui_pad_thread.h
Normal file
|
|
@ -0,0 +1,101 @@
|
||||||
|
#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 "Utilities/Timer.h"
|
||||||
|
#include "Utilities/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
|
||||||
|
};
|
||||||
|
|
@ -1,10 +1,10 @@
|
||||||
#include "keyboard_pad_handler.h"
|
#include "keyboard_pad_handler.h"
|
||||||
#include "pad_thread.h"
|
#include "Input/pad_thread.h"
|
||||||
#include "Emu/Io/pad_config.h"
|
#include "Emu/Io/pad_config.h"
|
||||||
#include "Emu/Io/KeyboardHandler.h"
|
#include "Emu/Io/KeyboardHandler.h"
|
||||||
#include "Emu/Io/interception.h"
|
#include "Emu/Io/interception.h"
|
||||||
#include "Input/product_info.h"
|
#include "Input/product_info.h"
|
||||||
#include "rpcs3qt/gs_frame.h"
|
#include "../gs_frame.h"
|
||||||
|
|
||||||
#include <QApplication>
|
#include <QApplication>
|
||||||
|
|
||||||
|
|
@ -4,7 +4,7 @@
|
||||||
#include "Emu/CPU/CPUDisAsm.h"
|
#include "Emu/CPU/CPUDisAsm.h"
|
||||||
#include "Emu/Cell/PPUThread.h"
|
#include "Emu/Cell/PPUThread.h"
|
||||||
#include "Emu/Cell/SPUThread.h"
|
#include "Emu/Cell/SPUThread.h"
|
||||||
#include "rpcs3qt/debugger_add_bp_window.h"
|
#include "debugger_add_bp_window.h"
|
||||||
|
|
||||||
#include <QMenu>
|
#include <QMenu>
|
||||||
#include <QMessageBox>
|
#include <QMessageBox>
|
||||||
|
|
@ -34,7 +34,7 @@
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
|
|
||||||
#include "rpcs3qt/debugger_add_bp_window.h"
|
#include "debugger_add_bp_window.h"
|
||||||
#include "util/asm.hpp"
|
#include "util/asm.hpp"
|
||||||
|
|
||||||
constexpr auto qstr = QString::fromStdString;
|
constexpr auto qstr = QString::fromStdString;
|
||||||