Compare commits
64 Commits
95c6b5fc86
...
dc88326d60
Author | SHA1 | Date |
---|---|---|
cristian64 | dc88326d60 | |
Admiral H. Curtiss | 2c83a256ae | |
Jordan Woyak | c3f66e83e6 | |
OatmealDome | c344514ba2 | |
Admiral H. Curtiss | 3ea870ef8c | |
Admiral H. Curtiss | ede963d4db | |
Admiral H. Curtiss | b0e5ebc80d | |
JosJuice | da0a0c87c2 | |
Daniel Peukert | f28e134c88 | |
dreamsyntax | b9a2d89035 | |
Admiral H. Curtiss | 93fc5c02ac | |
Admiral H. Curtiss | 98a80239f1 | |
Admiral H. Curtiss | 75abda6a3a | |
Admiral H. Curtiss | d10cb9dfc4 | |
Tilka | e24e107b3c | |
Tilka | ffa312f8e8 | |
Admiral H. Curtiss | 0e5d7d0f2d | |
OatmealDome | 2633b84b98 | |
Admiral H. Curtiss | 8f9e3ffd83 | |
Admiral H. Curtiss | 22dc21cca4 | |
Admiral H. Curtiss | c567248b73 | |
Admiral H. Curtiss | 7133bfbb0e | |
OatmealDome | d525776ae6 | |
OatmealDome | 4dc368d8df | |
OatmealDome | 0b7f399436 | |
OatmealDome | b5918effeb | |
OatmealDome | 696b363f47 | |
Sintendo | 532e25be12 | |
JosJuice | b35f7af355 | |
JosJuice | eec2e2f07a | |
JosJuice | 43d5f61a60 | |
OatmealDome | 8d9ec2fde9 | |
Ferdinand Bachmann | b79bdb13c0 | |
Ferdinand Bachmann | 825092ad33 | |
Sepalani | bbf835b30b | |
Sepalani | 77e77863dc | |
Sepalani | 5778cb42db | |
Sepalani | 5c151c11ac | |
Jordan Woyak | f12846a0e9 | |
Jordan Woyak | bc95c001c8 | |
Jordan Woyak | 0938fca6e3 | |
CasualPokePlayer | c1698c93e2 | |
Sintendo | d81bfe94eb | |
Sintendo | c817b4779d | |
Sintendo | 14641b06fc | |
Sintendo | a4ba13b4c9 | |
Sintendo | d2bfa157dc | |
Sintendo | ad7dba5413 | |
Sintendo | 7410bc2025 | |
Sintendo | fa13457abb | |
Sintendo | 18dd3f69f1 | |
Sintendo | e54bfd6605 | |
Sintendo | 5cc9bde1c1 | |
Sintendo | 50d991780f | |
dreamsyntax | 07f712f8a0 | |
JosJuice | 6384ea97f1 | |
OatmealDome | e05b033dd2 | |
OatmealDome | 3c27c38e71 | |
TellowKrinkle | 613c959bda | |
TellowKrinkle | 432d4a2a06 | |
Jordan Woyak | bffc26da27 | |
Sintendo | e6fd843c0b | |
JosJuice | dcf8ab0189 | |
JosJuice | 2fdeb85f0e |
|
@ -0,0 +1,24 @@
|
||||||
|
function(dolphin_inject_version_info target)
|
||||||
|
set(INFO_PLIST_PATH "$<TARGET_BUNDLE_DIR:${target}>/Contents/Info.plist")
|
||||||
|
add_custom_command(TARGET ${target}
|
||||||
|
POST_BUILD
|
||||||
|
|
||||||
|
COMMAND /usr/libexec/PlistBuddy -c
|
||||||
|
"Delete :CFBundleShortVersionString"
|
||||||
|
"${INFO_PLIST_PATH}"
|
||||||
|
|| true
|
||||||
|
|
||||||
|
COMMAND /usr/libexec/PlistBuddy -c
|
||||||
|
"Delete :CFBundleLongVersionString"
|
||||||
|
"${INFO_PLIST_PATH}"
|
||||||
|
|| true
|
||||||
|
|
||||||
|
COMMAND /usr/libexec/PlistBuddy -c
|
||||||
|
"Delete :CFBundleVersion"
|
||||||
|
"${INFO_PLIST_PATH}"
|
||||||
|
|| true
|
||||||
|
|
||||||
|
COMMAND /usr/libexec/PlistBuddy -c
|
||||||
|
"Merge '${CMAKE_BINARY_DIR}/Source/Core/VersionInfo.plist'"
|
||||||
|
"${INFO_PLIST_PATH}")
|
||||||
|
endfunction()
|
|
@ -19,28 +19,27 @@ function(dolphin_make_imported_target_if_missing target lib)
|
||||||
endif()
|
endif()
|
||||||
endfunction()
|
endfunction()
|
||||||
|
|
||||||
function(dolphin_optional_system_library library)
|
function(dolphin_optional_system_library out_use_system library)
|
||||||
string(TOUPPER ${library} upperlib)
|
string(TOUPPER ${library} upperlib)
|
||||||
set(USE_SYSTEM_${upperlib} "" CACHE STRING "Use system ${library} instead of bundled. ON - Always use system and fail if unavailable, OFF - Always use bundled, AUTO - Use system if available, otherwise use bundled, blank - Delegate to USE_SYSTEM_LIBS. Default is blank.")
|
set(USE_SYSTEM_${upperlib} "" CACHE STRING "Use system ${library} instead of bundled. ON - Always use system and fail if unavailable, OFF - Always use bundled, AUTO - Use system if available, otherwise use bundled, blank - Delegate to USE_SYSTEM_LIBS. Default is blank.")
|
||||||
if("${USE_SYSTEM_${upperlib}}" STREQUAL "")
|
if("${USE_SYSTEM_${upperlib}}" STREQUAL "")
|
||||||
if(APPROVED_VENDORED_DEPENDENCIES)
|
if(APPROVED_VENDORED_DEPENDENCIES)
|
||||||
string(TOLOWER ${library} lowerlib)
|
string(TOLOWER ${library} lowerlib)
|
||||||
if(lowerlib IN_LIST APPROVED_VENDORED_DEPENDENCIES)
|
if(lowerlib IN_LIST APPROVED_VENDORED_DEPENDENCIES)
|
||||||
set(RESOLVED_USE_SYSTEM_${upperlib} AUTO PARENT_SCOPE)
|
set(${out_use_system} AUTO PARENT_SCOPE)
|
||||||
else()
|
else()
|
||||||
set(RESOLVED_USE_SYSTEM_${upperlib} ON PARENT_SCOPE)
|
set(${out_use_system} ON PARENT_SCOPE)
|
||||||
endif()
|
endif()
|
||||||
else()
|
else()
|
||||||
set(RESOLVED_USE_SYSTEM_${upperlib} ${USE_SYSTEM_LIBS} PARENT_SCOPE)
|
set(${out_use_system} ${USE_SYSTEM_LIBS} PARENT_SCOPE)
|
||||||
endif()
|
endif()
|
||||||
else()
|
else()
|
||||||
set(RESOLVED_USE_SYSTEM_${upperlib} ${USE_SYSTEM_${upperlib}} PARENT_SCOPE)
|
set(${out_use_system} ${USE_SYSTEM_${upperlib}} PARENT_SCOPE)
|
||||||
endif()
|
endif()
|
||||||
endfunction()
|
endfunction()
|
||||||
|
|
||||||
function(dolphin_add_bundled_library library bundled_path)
|
function(dolphin_add_bundled_library library use_system bundled_path)
|
||||||
string(TOUPPER ${library} upperlib)
|
if (${use_system} STREQUAL "AUTO")
|
||||||
if (${RESOLVED_USE_SYSTEM_${upperlib}} STREQUAL "AUTO")
|
|
||||||
message(STATUS "No system ${library} was found. Using static ${library} from Externals.")
|
message(STATUS "No system ${library} was found. Using static ${library} from Externals.")
|
||||||
else()
|
else()
|
||||||
message(STATUS "Using static ${library} from Externals")
|
message(STATUS "Using static ${library} from Externals")
|
||||||
|
@ -52,9 +51,9 @@ function(dolphin_add_bundled_library library bundled_path)
|
||||||
endfunction()
|
endfunction()
|
||||||
|
|
||||||
function(dolphin_find_optional_system_library library bundled_path)
|
function(dolphin_find_optional_system_library library bundled_path)
|
||||||
dolphin_optional_system_library(${library})
|
dolphin_optional_system_library(use_system ${library})
|
||||||
string(TOUPPER ${library} upperlib)
|
string(TOUPPER ${library} upperlib)
|
||||||
if(RESOLVED_USE_SYSTEM_${upperlib})
|
if(use_system)
|
||||||
find_package(${library} ${ARGN})
|
find_package(${library} ${ARGN})
|
||||||
# Yay for cmake packages being inconsistent
|
# Yay for cmake packages being inconsistent
|
||||||
if(DEFINED ${library}_FOUND)
|
if(DEFINED ${library}_FOUND)
|
||||||
|
@ -62,7 +61,7 @@ function(dolphin_find_optional_system_library library bundled_path)
|
||||||
else()
|
else()
|
||||||
set(prefix ${upperlib})
|
set(prefix ${upperlib})
|
||||||
endif()
|
endif()
|
||||||
if((NOT ${found}) AND (NOT ${RESOLVED_USE_SYSTEM_${upperlib}} STREQUAL "AUTO"))
|
if((NOT ${prefix}_FOUND) AND (NOT ${use_system} STREQUAL "AUTO"))
|
||||||
message(FATAL_ERROR "No system ${library} was found. Please install it or set USE_SYSTEM_${upperlib} to AUTO or OFF.")
|
message(FATAL_ERROR "No system ${library} was found. Please install it or set USE_SYSTEM_${upperlib} to AUTO or OFF.")
|
||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
@ -70,17 +69,17 @@ function(dolphin_find_optional_system_library library bundled_path)
|
||||||
message(STATUS "Using system ${library}")
|
message(STATUS "Using system ${library}")
|
||||||
set(${prefix}_TYPE "System" PARENT_SCOPE)
|
set(${prefix}_TYPE "System" PARENT_SCOPE)
|
||||||
else()
|
else()
|
||||||
dolphin_add_bundled_library(${library} ${bundled_path})
|
dolphin_add_bundled_library(${library} ${use_system} ${bundled_path})
|
||||||
set(${prefix}_TYPE "Bundled" PARENT_SCOPE)
|
set(${prefix}_TYPE "Bundled" PARENT_SCOPE)
|
||||||
endif()
|
endif()
|
||||||
endfunction()
|
endfunction()
|
||||||
|
|
||||||
function(dolphin_find_optional_system_library_pkgconfig library search alias bundled_path)
|
function(dolphin_find_optional_system_library_pkgconfig library search alias bundled_path)
|
||||||
dolphin_optional_system_library(${library})
|
dolphin_optional_system_library(use_system ${library})
|
||||||
string(TOUPPER ${library} upperlib)
|
string(TOUPPER ${library} upperlib)
|
||||||
if(RESOLVED_USE_SYSTEM_${upperlib})
|
if(use_system)
|
||||||
pkg_search_module(${library} ${search} ${ARGN} IMPORTED_TARGET)
|
pkg_search_module(${library} ${search} ${ARGN} IMPORTED_TARGET)
|
||||||
if((NOT ${library}_FOUND) AND (NOT ${RESOLVED_USE_SYSTEM_${upperlib}} STREQUAL "AUTO"))
|
if((NOT ${library}_FOUND) AND (NOT ${use_system} STREQUAL "AUTO"))
|
||||||
message(FATAL_ERROR "No system ${library} was found. Please install it or set USE_SYSTEM_${upperlib} to AUTO or OFF.")
|
message(FATAL_ERROR "No system ${library} was found. Please install it or set USE_SYSTEM_${upperlib} to AUTO or OFF.")
|
||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
@ -89,7 +88,7 @@ function(dolphin_find_optional_system_library_pkgconfig library search alias bun
|
||||||
dolphin_alias_library(${alias} PkgConfig::${library})
|
dolphin_alias_library(${alias} PkgConfig::${library})
|
||||||
set(${library}_TYPE "System" PARENT_SCOPE)
|
set(${library}_TYPE "System" PARENT_SCOPE)
|
||||||
else()
|
else()
|
||||||
dolphin_add_bundled_library(${library} ${bundled_path})
|
dolphin_add_bundled_library(${library} ${use_system} ${bundled_path})
|
||||||
set(${library}_TYPE "Bundled" PARENT_SCOPE)
|
set(${library}_TYPE "Bundled" PARENT_SCOPE)
|
||||||
endif()
|
endif()
|
||||||
endfunction()
|
endfunction()
|
||||||
|
|
|
@ -65,6 +65,5 @@ endfunction()
|
||||||
configure_source_file("Source/Core/Common/scmrev.h")
|
configure_source_file("Source/Core/Common/scmrev.h")
|
||||||
|
|
||||||
if(APPLE)
|
if(APPLE)
|
||||||
configure_source_file("Source/Core/DolphinQt/Info.plist")
|
configure_source_file("Source/Core/VersionInfo.plist")
|
||||||
configure_source_file("Source/Core/MacUpdater/Info.plist")
|
|
||||||
endif()
|
endif()
|
||||||
|
|
|
@ -783,14 +783,9 @@ if (NOT EXISTS ${CMAKE_CURRENT_BINARY_DIR}/Source/Core/Common/scmrev.h)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(APPLE)
|
if(APPLE)
|
||||||
file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/Source/Core/DolphinQt)
|
file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/Source/Core)
|
||||||
if (NOT EXISTS ${CMAKE_CURRENT_BINARY_DIR}/Source/Core/DolphinQt/Info.plist)
|
if (NOT EXISTS ${CMAKE_CURRENT_BINARY_DIR}/Source/Core/VersionInfo.plist)
|
||||||
file(TOUCH ${CMAKE_CURRENT_BINARY_DIR}/Source/Core/DolphinQt/Info.plist)
|
file(TOUCH ${CMAKE_CURRENT_BINARY_DIR}/Source/Core/VersionInfo.plist)
|
||||||
endif()
|
|
||||||
|
|
||||||
file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/Source/Core/MacUpdater)
|
|
||||||
if (NOT EXISTS ${CMAKE_CURRENT_BINARY_DIR}/Source/Core/MacUpdater/Info.plist)
|
|
||||||
file(TOUCH ${CMAKE_CURRENT_BINARY_DIR}/Source/Core/MacUpdater/Info.plist)
|
|
||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
|
|
@ -1,62 +1,53 @@
|
||||||
include_directories(${CMAKE_CURRENT_SOURCE_DIR})
|
set(BUILD_CURL_EXE OFF)
|
||||||
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/curl/include)
|
set(BUILD_EXAMPLES OFF)
|
||||||
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/curl/lib)
|
set(BUILD_LIBCURL_DOCS OFF)
|
||||||
|
set(BUILD_MISC_DOCS OFF)
|
||||||
|
set(BUILD_SHARED_LIBS OFF)
|
||||||
|
set(BUILD_STATIC_LIBS ON)
|
||||||
|
set(BUILD_TESTING OFF)
|
||||||
|
set(CURL_ENABLE_EXPORT_TARGET OFF)
|
||||||
|
|
||||||
set(CURL_LIBS MbedTLS::mbedtls zlibstatic)
|
set(HTTP_ONLY ON)
|
||||||
if(CMAKE_SYSTEM_NAME STREQUAL "Darwin")
|
|
||||||
set(use_core_foundation ON)
|
|
||||||
|
|
||||||
find_library(SYSTEMCONFIGURATION_FRAMEWORK "SystemConfiguration")
|
set(CURL_USE_LIBPSL OFF)
|
||||||
if(NOT SYSTEMCONFIGURATION_FRAMEWORK)
|
set(CURL_USE_LIBSSH2 OFF)
|
||||||
message(FATAL_ERROR "SystemConfiguration framework not found")
|
set(CURL_ZLIB OFF CACHE BOOL "" FORCE)
|
||||||
endif()
|
set(CURL_ZSTD OFF)
|
||||||
|
set(USE_LIBIDN2 OFF)
|
||||||
|
set(USE_NGHTTP2 OFF)
|
||||||
|
|
||||||
list(APPEND CURL_LIBS "-framework SystemConfiguration")
|
if(UNIX)
|
||||||
endif()
|
# We use mbedtls on Unix(-like) systems and Android.
|
||||||
|
set(CURL_USE_OPENSSL OFF)
|
||||||
|
|
||||||
file(GLOB SRCS curl/lib/*.c curl/lib/vauth/*.c curl/lib/vquic/*.c curl/lib/vssh/*.c curl/lib/vtls/*.c)
|
# This is set if the dolphin_find_optional_system_library call from the main CMakeLists.txt
|
||||||
add_library(
|
# is able to find mbedtls on the system.
|
||||||
curl
|
if(MBEDTLS_FOUND)
|
||||||
STATIC
|
# We can just enable CURL_USE_MBEDTLS.
|
||||||
curl/include/curl/curl.h
|
set(CURL_USE_MBEDTLS ON)
|
||||||
${SRCS}
|
|
||||||
)
|
|
||||||
|
|
||||||
set(SEARCH_CA_BUNDLE_PATHS
|
|
||||||
/etc/ssl/certs/ca-certificates.crt
|
|
||||||
/etc/pki/tls/certs/ca-bundle.crt
|
|
||||||
/usr/share/ssl/certs/ca-bundle.crt
|
|
||||||
/usr/local/share/certs/ca-root-nss.crt
|
|
||||||
/etc/ssl/cert.pem)
|
|
||||||
|
|
||||||
foreach(SEARCH_CA_BUNDLE_PATH ${SEARCH_CA_BUNDLE_PATHS})
|
|
||||||
if(EXISTS "${SEARCH_CA_BUNDLE_PATH}")
|
|
||||||
message(STATUS "Found CA bundle: ${SEARCH_CA_BUNDLE_PATH}")
|
|
||||||
set(CURL_CA_BUNDLE "${SEARCH_CA_BUNDLE_PATH}")
|
|
||||||
set(CURL_CA_BUNDLE_SET TRUE)
|
|
||||||
break()
|
|
||||||
endif()
|
|
||||||
endforeach()
|
|
||||||
|
|
||||||
if(NOT CURL_CA_PATH_SET)
|
|
||||||
if(EXISTS "/etc/ssl/certs")
|
|
||||||
set(CURL_CA_PATH "/etc/ssl/certs")
|
|
||||||
set(CURL_CA_PATH_SET TRUE)
|
|
||||||
endif()
|
|
||||||
endif()
|
|
||||||
|
|
||||||
dolphin_disable_warnings(curl)
|
|
||||||
target_link_libraries(curl ${CURL_LIBS})
|
|
||||||
target_include_directories(curl PUBLIC "${CMAKE_CURRENT_SOURCE_DIR}/curl/include")
|
|
||||||
target_compile_definitions(curl PRIVATE "BUILDING_LIBCURL=1")
|
|
||||||
if (WIN32)
|
|
||||||
target_compile_definitions(curl PUBLIC "CURL_STATICLIB=1" "CURL_DISABLE_LDAP" "USE_WINDOWS_SSPI" "USE_SCHANNEL")
|
|
||||||
target_link_libraries(curl Crypt32.lib)
|
|
||||||
else()
|
else()
|
||||||
target_compile_definitions(curl PUBLIC "CURL_STATICLIB=1" "USE_MBEDTLS=1" "HAVE_CONFIG_H=1" "CURL_DISABLE_LDAP")
|
# HACK: Set some internal variables to pretend like mbedtls was found on the system.
|
||||||
if (CURL_CA_PATH_SET)
|
# We can't use CURL_USE_MBEDTLS with our copy from Externals, as that flag expects
|
||||||
target_compile_definitions(curl PUBLIC CURL_CA_PATH="${CURL_CA_PATH}")
|
# mbedtls to be installed (the CMakeLists attempts to search for it with find_package).
|
||||||
|
set(_ssl_enabled ON)
|
||||||
|
set(USE_MBEDTLS ON)
|
||||||
|
set(_curl_ca_bundle_supported TRUE)
|
||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
add_library(CURL::libcurl ALIAS curl)
|
if(WIN32)
|
||||||
|
set(CURL_USE_SCHANNEL ON)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if(ANDROID)
|
||||||
|
set(CURL_CA_PATH "/system/etc/security/cacerts" CACHE STRING "")
|
||||||
|
endif()
|
||||||
|
|
||||||
|
add_subdirectory(curl)
|
||||||
|
|
||||||
|
if(UNIX AND NOT MBEDTLS_FOUND)
|
||||||
|
# HACK: Manually link with the mbedtls libraries.
|
||||||
|
target_link_libraries(libcurl_static PRIVATE
|
||||||
|
MbedTLS::mbedtls
|
||||||
|
MbedTLS::mbedx509)
|
||||||
|
endif()
|
||||||
|
|
|
@ -1,22 +0,0 @@
|
||||||
COPYRIGHT AND PERMISSION NOTICE
|
|
||||||
|
|
||||||
Copyright (c) 1996 - 2016, Daniel Stenberg, <daniel@haxx.se>, and many
|
|
||||||
contributors, see the THANKS file.
|
|
||||||
|
|
||||||
All rights reserved.
|
|
||||||
|
|
||||||
Permission to use, copy, modify, and distribute this software for any purpose
|
|
||||||
with or without fee is hereby granted, provided that the above copyright
|
|
||||||
notice and this permission notice appear in all copies.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
||||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
||||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF THIRD PARTY RIGHTS. IN
|
|
||||||
NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
|
||||||
DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
|
||||||
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
|
|
||||||
OR OTHER DEALINGS IN THE SOFTWARE.
|
|
||||||
|
|
||||||
Except as contained in this notice, the name of a copyright holder shall not
|
|
||||||
be used in advertising or otherwise to promote the sale, use or other dealings
|
|
||||||
in this Software without prior written authorization of the copyright holder.
|
|
|
@ -1 +1 @@
|
||||||
Subproject commit d755a5f7c009dd63a61b2c745180d8ba937cbfeb
|
Subproject commit 75a2079d5c28debb2eaa848ca9430f1fe0d7844c
|
|
@ -50,14 +50,14 @@
|
||||||
<ClCompile Include="curl\lib\curl_memrchr.c" />
|
<ClCompile Include="curl\lib\curl_memrchr.c" />
|
||||||
<ClCompile Include="curl\lib\curl_multibyte.c" />
|
<ClCompile Include="curl\lib\curl_multibyte.c" />
|
||||||
<ClCompile Include="curl\lib\curl_ntlm_core.c" />
|
<ClCompile Include="curl\lib\curl_ntlm_core.c" />
|
||||||
<ClCompile Include="curl\lib\curl_ntlm_wb.c" />
|
|
||||||
<ClCompile Include="curl\lib\curl_path.c" />
|
|
||||||
<ClCompile Include="curl\lib\curl_range.c" />
|
<ClCompile Include="curl\lib\curl_range.c" />
|
||||||
<ClCompile Include="curl\lib\curl_rtmp.c" />
|
<ClCompile Include="curl\lib\curl_rtmp.c" />
|
||||||
<ClCompile Include="curl\lib\curl_sasl.c" />
|
<ClCompile Include="curl\lib\curl_sasl.c" />
|
||||||
|
<ClCompile Include="curl\lib\curl_sha512_256.c" />
|
||||||
<ClCompile Include="curl\lib\curl_sspi.c" />
|
<ClCompile Include="curl\lib\curl_sspi.c" />
|
||||||
<ClCompile Include="curl\lib\curl_threads.c" />
|
<ClCompile Include="curl\lib\curl_threads.c" />
|
||||||
<ClCompile Include="curl\lib\curl_trc.c" />
|
<ClCompile Include="curl\lib\curl_trc.c" />
|
||||||
|
<ClCompile Include="curl\lib\cw-out.c" />
|
||||||
<ClCompile Include="curl\lib\dict.c" />
|
<ClCompile Include="curl\lib\dict.c" />
|
||||||
<ClCompile Include="curl\lib\doh.c" />
|
<ClCompile Include="curl\lib\doh.c" />
|
||||||
<ClCompile Include="curl\lib\dynbuf.c" />
|
<ClCompile Include="curl\lib\dynbuf.c" />
|
||||||
|
@ -120,6 +120,7 @@
|
||||||
<ClCompile Include="curl\lib\psl.c" />
|
<ClCompile Include="curl\lib\psl.c" />
|
||||||
<ClCompile Include="curl\lib\rand.c" />
|
<ClCompile Include="curl\lib\rand.c" />
|
||||||
<ClCompile Include="curl\lib\rename.c" />
|
<ClCompile Include="curl\lib\rename.c" />
|
||||||
|
<ClCompile Include="curl\lib\request.c" />
|
||||||
<ClCompile Include="curl\lib\rtsp.c" />
|
<ClCompile Include="curl\lib\rtsp.c" />
|
||||||
<ClCompile Include="curl\lib\select.c" />
|
<ClCompile Include="curl\lib\select.c" />
|
||||||
<ClCompile Include="curl\lib\sendf.c" />
|
<ClCompile Include="curl\lib\sendf.c" />
|
||||||
|
@ -167,12 +168,16 @@
|
||||||
<ClCompile Include="curl\lib\vauth\vauth.c" />
|
<ClCompile Include="curl\lib\vauth\vauth.c" />
|
||||||
<ClCompile Include="curl\lib\vquic\curl_msh3.c" />
|
<ClCompile Include="curl\lib\vquic\curl_msh3.c" />
|
||||||
<ClCompile Include="curl\lib\vquic\curl_ngtcp2.c" />
|
<ClCompile Include="curl\lib\vquic\curl_ngtcp2.c" />
|
||||||
|
<ClCompile Include="curl\lib\vquic\curl_osslq.c" />
|
||||||
<ClCompile Include="curl\lib\vquic\curl_quiche.c" />
|
<ClCompile Include="curl\lib\vquic\curl_quiche.c" />
|
||||||
<ClCompile Include="curl\lib\vquic\vquic.c" />
|
<ClCompile Include="curl\lib\vquic\vquic.c" />
|
||||||
|
<ClCompile Include="curl\lib\vquic\vquic-tls.c" />
|
||||||
|
<ClCompile Include="curl\lib\vssh\curl_path.c" />
|
||||||
<ClCompile Include="curl\lib\vssh\libssh.c" />
|
<ClCompile Include="curl\lib\vssh\libssh.c" />
|
||||||
<ClCompile Include="curl\lib\vssh\libssh2.c" />
|
<ClCompile Include="curl\lib\vssh\libssh2.c" />
|
||||||
<ClCompile Include="curl\lib\vssh\wolfssh.c" />
|
<ClCompile Include="curl\lib\vssh\wolfssh.c" />
|
||||||
<ClCompile Include="curl\lib\vtls\bearssl.c" />
|
<ClCompile Include="curl\lib\vtls\bearssl.c" />
|
||||||
|
<ClCompile Include="curl\lib\vtls\cipher_suite.c" />
|
||||||
<ClCompile Include="curl\lib\vtls\gtls.c" />
|
<ClCompile Include="curl\lib\vtls\gtls.c" />
|
||||||
<ClCompile Include="curl\lib\vtls\hostcheck.c" />
|
<ClCompile Include="curl\lib\vtls\hostcheck.c" />
|
||||||
<ClCompile Include="curl\lib\vtls\keylog.c" />
|
<ClCompile Include="curl\lib\vtls\keylog.c" />
|
||||||
|
@ -244,8 +249,6 @@
|
||||||
<ClInclude Include="curl\lib\curl_memrchr.h" />
|
<ClInclude Include="curl\lib\curl_memrchr.h" />
|
||||||
<ClInclude Include="curl\lib\curl_multibyte.h" />
|
<ClInclude Include="curl\lib\curl_multibyte.h" />
|
||||||
<ClInclude Include="curl\lib\curl_ntlm_core.h" />
|
<ClInclude Include="curl\lib\curl_ntlm_core.h" />
|
||||||
<ClInclude Include="curl\lib\curl_ntlm_wb.h" />
|
|
||||||
<ClInclude Include="curl\lib\curl_path.h" />
|
|
||||||
<ClInclude Include="curl\lib\curl_printf.h" />
|
<ClInclude Include="curl\lib\curl_printf.h" />
|
||||||
<ClInclude Include="curl\lib\curl_range.h" />
|
<ClInclude Include="curl\lib\curl_range.h" />
|
||||||
<ClInclude Include="curl\lib\curl_rtmp.h" />
|
<ClInclude Include="curl\lib\curl_rtmp.h" />
|
||||||
|
@ -253,9 +256,11 @@
|
||||||
<ClInclude Include="curl\lib\curl_setup.h" />
|
<ClInclude Include="curl\lib\curl_setup.h" />
|
||||||
<ClInclude Include="curl\lib\curl_setup_once.h" />
|
<ClInclude Include="curl\lib\curl_setup_once.h" />
|
||||||
<ClInclude Include="curl\lib\curl_sha256.h" />
|
<ClInclude Include="curl\lib\curl_sha256.h" />
|
||||||
|
<ClInclude Include="curl\lib\curl_sha512_256.h" />
|
||||||
<ClInclude Include="curl\lib\curl_sspi.h" />
|
<ClInclude Include="curl\lib\curl_sspi.h" />
|
||||||
<ClInclude Include="curl\lib\curl_threads.h" />
|
<ClInclude Include="curl\lib\curl_threads.h" />
|
||||||
<ClInclude Include="curl\lib\curl_trc.h" />
|
<ClInclude Include="curl\lib\curl_trc.h" />
|
||||||
|
<ClInclude Include="curl\lib\cw_out.h" />
|
||||||
<ClInclude Include="curl\lib\dict.h" />
|
<ClInclude Include="curl\lib\dict.h" />
|
||||||
<ClInclude Include="curl\lib\doh.h" />
|
<ClInclude Include="curl\lib\doh.h" />
|
||||||
<ClInclude Include="curl\lib\dynbuf.h" />
|
<ClInclude Include="curl\lib\dynbuf.h" />
|
||||||
|
@ -308,6 +313,7 @@
|
||||||
<ClInclude Include="curl\lib\psl.h" />
|
<ClInclude Include="curl\lib\psl.h" />
|
||||||
<ClInclude Include="curl\lib\rand.h" />
|
<ClInclude Include="curl\lib\rand.h" />
|
||||||
<ClInclude Include="curl\lib\rename.h" />
|
<ClInclude Include="curl\lib\rename.h" />
|
||||||
|
<ClInclude Include="curl\lib\request.h" />
|
||||||
<ClInclude Include="curl\lib\rtsp.h" />
|
<ClInclude Include="curl\lib\rtsp.h" />
|
||||||
<ClInclude Include="curl\lib\select.h" />
|
<ClInclude Include="curl\lib\select.h" />
|
||||||
<ClInclude Include="curl\lib\sendf.h" />
|
<ClInclude Include="curl\lib\sendf.h" />
|
||||||
|
@ -347,11 +353,15 @@
|
||||||
<ClInclude Include="curl\lib\vauth\vauth.h" />
|
<ClInclude Include="curl\lib\vauth\vauth.h" />
|
||||||
<ClInclude Include="curl\lib\vquic\curl_msh3.h" />
|
<ClInclude Include="curl\lib\vquic\curl_msh3.h" />
|
||||||
<ClInclude Include="curl\lib\vquic\curl_ngtcp2.h" />
|
<ClInclude Include="curl\lib\vquic\curl_ngtcp2.h" />
|
||||||
|
<ClInclude Include="curl\lib\vquic\curl_osslq.h" />
|
||||||
<ClInclude Include="curl\lib\vquic\curl_quiche.h" />
|
<ClInclude Include="curl\lib\vquic\curl_quiche.h" />
|
||||||
<ClInclude Include="curl\lib\vquic\vquic.h" />
|
<ClInclude Include="curl\lib\vquic\vquic.h" />
|
||||||
|
<ClInclude Include="curl\lib\vquic\vquic-tls.h" />
|
||||||
<ClInclude Include="curl\lib\vquic\vquic_int.h" />
|
<ClInclude Include="curl\lib\vquic\vquic_int.h" />
|
||||||
|
<ClInclude Include="curl\lib\vssh\curl_path.h" />
|
||||||
<ClInclude Include="curl\lib\vssh\ssh.h" />
|
<ClInclude Include="curl\lib\vssh\ssh.h" />
|
||||||
<ClInclude Include="curl\lib\vtls\bearssl.h" />
|
<ClInclude Include="curl\lib\vtls\bearssl.h" />
|
||||||
|
<ClInclude Include="curl\lib\vtls\cipher_suites.h" />
|
||||||
<ClInclude Include="curl\lib\vtls\gtls.h" />
|
<ClInclude Include="curl\lib\vtls\gtls.h" />
|
||||||
<ClInclude Include="curl\lib\vtls\hostcheck.h" />
|
<ClInclude Include="curl\lib\vtls\hostcheck.h" />
|
||||||
<ClInclude Include="curl\lib\vtls\keylog.h" />
|
<ClInclude Include="curl\lib\vtls\keylog.h" />
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -19,7 +19,9 @@ import android.widget.Toast
|
||||||
import androidx.appcompat.app.AppCompatActivity
|
import androidx.appcompat.app.AppCompatActivity
|
||||||
import androidx.appcompat.widget.PopupMenu
|
import androidx.appcompat.widget.PopupMenu
|
||||||
import androidx.core.view.ViewCompat
|
import androidx.core.view.ViewCompat
|
||||||
|
import androidx.core.view.WindowCompat
|
||||||
import androidx.core.view.WindowInsetsCompat
|
import androidx.core.view.WindowInsetsCompat
|
||||||
|
import androidx.core.view.WindowInsetsControllerCompat
|
||||||
import androidx.fragment.app.Fragment
|
import androidx.fragment.app.Fragment
|
||||||
import androidx.fragment.app.FragmentActivity
|
import androidx.fragment.app.FragmentActivity
|
||||||
import androidx.fragment.app.FragmentManager
|
import androidx.fragment.app.FragmentManager
|
||||||
|
@ -326,12 +328,11 @@ class EmulationActivity : AppCompatActivity(), ThemeProvider {
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun enableFullscreenImmersive() {
|
private fun enableFullscreenImmersive() {
|
||||||
window.decorView.systemUiVisibility = View.SYSTEM_UI_FLAG_LAYOUT_STABLE or
|
WindowCompat.setDecorFitsSystemWindows(window, false)
|
||||||
View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION or
|
WindowInsetsControllerCompat(window, window.decorView).let { controller ->
|
||||||
View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN or
|
controller.hide(WindowInsetsCompat.Type.systemBars())
|
||||||
View.SYSTEM_UI_FLAG_HIDE_NAVIGATION or
|
controller.systemBarsBehavior = WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE
|
||||||
View.SYSTEM_UI_FLAG_FULLSCREEN or
|
}
|
||||||
View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun updateDisplaySettings() {
|
private fun updateDisplaySettings() {
|
||||||
|
|
|
@ -191,7 +191,7 @@ Java_org_dolphinemu_dolphinemu_features_cheats_model_GeckoCheat_downloadCodes(JN
|
||||||
const std::string gametdb_id = GetJString(env, jGameTdbId);
|
const std::string gametdb_id = GetJString(env, jGameTdbId);
|
||||||
|
|
||||||
bool success = true;
|
bool success = true;
|
||||||
const std::vector<Gecko::GeckoCode> codes = Gecko::DownloadCodes(gametdb_id, &success, false);
|
const std::vector<Gecko::GeckoCode> codes = Gecko::DownloadCodes(gametdb_id, &success);
|
||||||
|
|
||||||
if (!success)
|
if (!success)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
|
@ -1,13 +1,9 @@
|
||||||
// Copyright 2003 Dolphin Emulator Project
|
// Copyright 2003 Dolphin Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
#include <EGL/egl.h>
|
#include <condition_variable>
|
||||||
#include <android/log.h>
|
|
||||||
#include <android/native_window_jni.h>
|
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <fmt/format.h>
|
|
||||||
#include <jni.h>
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
|
@ -15,6 +11,12 @@
|
||||||
#include <thread>
|
#include <thread>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
|
#include <EGL/egl.h>
|
||||||
|
#include <android/log.h>
|
||||||
|
#include <android/native_window_jni.h>
|
||||||
|
#include <fmt/format.h>
|
||||||
|
#include <jni.h>
|
||||||
|
|
||||||
#include "Common/AndroidAnalytics.h"
|
#include "Common/AndroidAnalytics.h"
|
||||||
#include "Common/Assert.h"
|
#include "Common/Assert.h"
|
||||||
#include "Common/CPUDetect.h"
|
#include "Common/CPUDetect.h"
|
||||||
|
@ -77,6 +79,8 @@ Common::Event s_update_main_frame_event;
|
||||||
// This exists to prevent surfaces from being destroyed during the boot process,
|
// This exists to prevent surfaces from being destroyed during the boot process,
|
||||||
// as that can lead to the boot process dereferencing nullptr.
|
// as that can lead to the boot process dereferencing nullptr.
|
||||||
std::mutex s_surface_lock;
|
std::mutex s_surface_lock;
|
||||||
|
std::condition_variable s_surface_cv;
|
||||||
|
|
||||||
bool s_need_nonblocking_alert_msg;
|
bool s_need_nonblocking_alert_msg;
|
||||||
|
|
||||||
Common::Flag s_is_booting;
|
Common::Flag s_is_booting;
|
||||||
|
@ -482,6 +486,8 @@ JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_SurfaceChang
|
||||||
|
|
||||||
if (g_presenter)
|
if (g_presenter)
|
||||||
g_presenter->ChangeSurface(s_surf);
|
g_presenter->ChangeSurface(s_surf);
|
||||||
|
|
||||||
|
s_surface_cv.notify_all();
|
||||||
}
|
}
|
||||||
|
|
||||||
JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_SurfaceDestroyed(JNIEnv*,
|
JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_SurfaceDestroyed(JNIEnv*,
|
||||||
|
@ -515,6 +521,8 @@ JNIEXPORT void JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_SurfaceDestr
|
||||||
ANativeWindow_release(s_surf);
|
ANativeWindow_release(s_surf);
|
||||||
s_surf = nullptr;
|
s_surf = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
s_surface_cv.notify_all();
|
||||||
}
|
}
|
||||||
|
|
||||||
JNIEXPORT jboolean JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_HasSurface(JNIEnv*, jclass)
|
JNIEXPORT jboolean JNICALL Java_org_dolphinemu_dolphinemu_NativeLibrary_HasSurface(JNIEnv*, jclass)
|
||||||
|
@ -606,12 +614,14 @@ static void Run(JNIEnv* env, std::unique_ptr<BootParameters>&& boot, bool riivol
|
||||||
volume.GetDiscNumber()));
|
volume.GetDiscNumber()));
|
||||||
}
|
}
|
||||||
|
|
||||||
WindowSystemInfo wsi(WindowSystemType::Android, nullptr, s_surf, s_surf);
|
|
||||||
wsi.render_surface_scale = GetRenderSurfaceScale(env);
|
|
||||||
|
|
||||||
s_need_nonblocking_alert_msg = true;
|
s_need_nonblocking_alert_msg = true;
|
||||||
std::unique_lock<std::mutex> surface_guard(s_surface_lock);
|
std::unique_lock<std::mutex> surface_guard(s_surface_lock);
|
||||||
|
|
||||||
|
s_surface_cv.wait(surface_guard, []() { return s_surf != nullptr; });
|
||||||
|
|
||||||
|
WindowSystemInfo wsi(WindowSystemType::Android, nullptr, s_surf, s_surf);
|
||||||
|
wsi.render_surface_scale = GetRenderSurfaceScale(env);
|
||||||
|
|
||||||
if (BootManager::BootCore(Core::System::GetInstance(), std::move(boot), wsi))
|
if (BootManager::BootCore(Core::System::GetInstance(), std::move(boot), wsi))
|
||||||
{
|
{
|
||||||
static constexpr int WAIT_STEP = 25;
|
static constexpr int WAIT_STEP = 25;
|
||||||
|
|
|
@ -85,7 +85,8 @@ bool IniFile::Section::Delete(std::string_view key)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
values.erase(it);
|
values.erase(it);
|
||||||
keys_order.erase(std::ranges::find(keys_order, key));
|
keys_order.erase(std::ranges::find_if(
|
||||||
|
keys_order, [&](std::string_view v) { return CaseInsensitiveEquals(key, v); }));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -99,7 +99,13 @@ void GenericLogFmt(LogLevel level, LogType type, const char* file, int line, con
|
||||||
static_assert(NumFields == sizeof...(args),
|
static_assert(NumFields == sizeof...(args),
|
||||||
"Unexpected number of replacement fields in format string; did you pass too few or "
|
"Unexpected number of replacement fields in format string; did you pass too few or "
|
||||||
"too many arguments?");
|
"too many arguments?");
|
||||||
GenericLogFmtImpl(level, type, file, line, format, fmt::make_format_args(args...));
|
|
||||||
|
#if FMT_VERSION >= 110000
|
||||||
|
auto&& format_str = fmt::format_string<Args...>(format);
|
||||||
|
#else
|
||||||
|
auto&& format_str = format;
|
||||||
|
#endif
|
||||||
|
GenericLogFmtImpl(level, type, file, line, format_str, fmt::make_format_args(args...));
|
||||||
}
|
}
|
||||||
} // namespace Common::Log
|
} // namespace Common::Log
|
||||||
|
|
||||||
|
|
|
@ -41,12 +41,17 @@ bool MsgAlertFmt(bool yes_no, MsgType style, Common::Log::LogType log_type, cons
|
||||||
static_assert(NumFields == sizeof...(args),
|
static_assert(NumFields == sizeof...(args),
|
||||||
"Unexpected number of replacement fields in format string; did you pass too few or "
|
"Unexpected number of replacement fields in format string; did you pass too few or "
|
||||||
"too many arguments?");
|
"too many arguments?");
|
||||||
#if FMT_VERSION >= 90000
|
#if FMT_VERSION >= 110000
|
||||||
|
static_assert(std::is_base_of_v<fmt::detail::compile_string, S>);
|
||||||
|
auto&& format_str = fmt::format_string<Args...>(format);
|
||||||
|
#elif FMT_VERSION >= 90000
|
||||||
static_assert(fmt::detail::is_compile_string<S>::value);
|
static_assert(fmt::detail::is_compile_string<S>::value);
|
||||||
|
auto&& format_str = format;
|
||||||
#else
|
#else
|
||||||
static_assert(fmt::is_compile_string<S>::value);
|
static_assert(fmt::is_compile_string<S>::value);
|
||||||
|
auto&& format_str = format;
|
||||||
#endif
|
#endif
|
||||||
return MsgAlertFmtImpl(yes_no, style, log_type, file, line, format,
|
return MsgAlertFmtImpl(yes_no, style, log_type, file, line, format_str,
|
||||||
fmt::make_format_args(args...));
|
fmt::make_format_args(args...));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -60,7 +65,9 @@ bool MsgAlertFmtT(bool yes_no, MsgType style, Common::Log::LogType log_type, con
|
||||||
static_assert(NumFields == sizeof...(args),
|
static_assert(NumFields == sizeof...(args),
|
||||||
"Unexpected number of replacement fields in format string; did you pass too few or "
|
"Unexpected number of replacement fields in format string; did you pass too few or "
|
||||||
"too many arguments?");
|
"too many arguments?");
|
||||||
#if FMT_VERSION >= 90000
|
#if FMT_VERSION >= 110000
|
||||||
|
static_assert(std::is_base_of_v<fmt::detail::compile_string, S>);
|
||||||
|
#elif FMT_VERSION >= 90000
|
||||||
static_assert(fmt::detail::is_compile_string<S>::value);
|
static_assert(fmt::detail::is_compile_string<S>::value);
|
||||||
#else
|
#else
|
||||||
static_assert(fmt::is_compile_string<S>::value);
|
static_assert(fmt::is_compile_string<S>::value);
|
||||||
|
|
|
@ -41,6 +41,7 @@ static void LoadFromDTM(Config::Layer* config_layer, Movie::DTMHeader* dtm)
|
||||||
else
|
else
|
||||||
config_layer->Set(Config::MAIN_GC_LANGUAGE, static_cast<int>(dtm->language));
|
config_layer->Set(Config::MAIN_GC_LANGUAGE, static_cast<int>(dtm->language));
|
||||||
config_layer->Set(Config::SYSCONF_WIDESCREEN, dtm->bWidescreen);
|
config_layer->Set(Config::SYSCONF_WIDESCREEN, dtm->bWidescreen);
|
||||||
|
config_layer->Set(Config::SYSCONF_COUNTRY, dtm->countryCode);
|
||||||
|
|
||||||
config_layer->Set(Config::GFX_HACK_EFB_ACCESS_ENABLE, dtm->bEFBAccessEnable);
|
config_layer->Set(Config::GFX_HACK_EFB_ACCESS_ENABLE, dtm->bEFBAccessEnable);
|
||||||
config_layer->Set(Config::GFX_HACK_SKIP_EFB_COPY_TO_RAM, dtm->bSkipEFBCopyToRam);
|
config_layer->Set(Config::GFX_HACK_SKIP_EFB_COPY_TO_RAM, dtm->bSkipEFBCopyToRam);
|
||||||
|
@ -69,6 +70,7 @@ void SaveToDTM(Movie::DTMHeader* dtm)
|
||||||
else
|
else
|
||||||
dtm->language = Config::Get(Config::MAIN_GC_LANGUAGE);
|
dtm->language = Config::Get(Config::MAIN_GC_LANGUAGE);
|
||||||
dtm->bWidescreen = Config::Get(Config::SYSCONF_WIDESCREEN);
|
dtm->bWidescreen = Config::Get(Config::SYSCONF_WIDESCREEN);
|
||||||
|
dtm->countryCode = Config::Get(Config::SYSCONF_COUNTRY);
|
||||||
|
|
||||||
dtm->bEFBAccessEnable = Config::Get(Config::GFX_HACK_EFB_ACCESS_ENABLE);
|
dtm->bEFBAccessEnable = Config::Get(Config::GFX_HACK_EFB_ACCESS_ENABLE);
|
||||||
dtm->bSkipEFBCopyToRam = Config::Get(Config::GFX_HACK_SKIP_EFB_COPY_TO_RAM);
|
dtm->bSkipEFBCopyToRam = Config::Get(Config::GFX_HACK_SKIP_EFB_COPY_TO_RAM);
|
||||||
|
|
|
@ -776,14 +776,11 @@ bool DSPAssembler::AssemblePass(const std::string& text, int pass)
|
||||||
m_location.line_num = 0;
|
m_location.line_num = 0;
|
||||||
m_cur_pass = pass;
|
m_cur_pass = pass;
|
||||||
|
|
||||||
#define LINEBUF_SIZE 1024
|
constexpr int LINEBUF_SIZE = 1024;
|
||||||
char line[LINEBUF_SIZE] = {0};
|
char line[LINEBUF_SIZE] = {};
|
||||||
while (!m_failed && !fsrc.fail() && !fsrc.eof())
|
while (!m_failed && fsrc.getline(line, LINEBUF_SIZE))
|
||||||
{
|
{
|
||||||
int opcode_size = 0;
|
int opcode_size = 0;
|
||||||
fsrc.getline(line, LINEBUF_SIZE);
|
|
||||||
if (fsrc.fail())
|
|
||||||
break;
|
|
||||||
|
|
||||||
m_location.line_text = line;
|
m_location.line_text = line;
|
||||||
m_location.line_num++;
|
m_location.line_num++;
|
||||||
|
|
|
@ -17,13 +17,10 @@
|
||||||
|
|
||||||
namespace Gecko
|
namespace Gecko
|
||||||
{
|
{
|
||||||
std::vector<GeckoCode> DownloadCodes(std::string gametdb_id, bool* succeeded, bool use_https)
|
std::vector<GeckoCode> DownloadCodes(std::string gametdb_id, bool* succeeded)
|
||||||
{
|
{
|
||||||
// TODO: Fix https://bugs.dolphin-emu.org/issues/11772 so we don't need this workaround
|
|
||||||
const std::string protocol = use_https ? "https://" : "http://";
|
|
||||||
|
|
||||||
// codes.rc24.xyz is a mirror of the now defunct geckocodes.org.
|
// codes.rc24.xyz is a mirror of the now defunct geckocodes.org.
|
||||||
std::string endpoint{protocol + "codes.rc24.xyz/txt.php?txt=" + gametdb_id};
|
std::string endpoint{"https://codes.rc24.xyz/txt.php?txt=" + gametdb_id};
|
||||||
Common::HttpRequest http;
|
Common::HttpRequest http;
|
||||||
|
|
||||||
// The server always redirects once to the same location.
|
// The server always redirects once to the same location.
|
||||||
|
|
|
@ -17,8 +17,7 @@ class IniFile;
|
||||||
namespace Gecko
|
namespace Gecko
|
||||||
{
|
{
|
||||||
std::vector<GeckoCode> LoadCodes(const Common::IniFile& globalIni, const Common::IniFile& localIni);
|
std::vector<GeckoCode> LoadCodes(const Common::IniFile& globalIni, const Common::IniFile& localIni);
|
||||||
std::vector<GeckoCode> DownloadCodes(std::string gametdb_id, bool* succeeded,
|
std::vector<GeckoCode> DownloadCodes(std::string gametdb_id, bool* succeeded);
|
||||||
bool use_https = true);
|
|
||||||
void SaveCodes(Common::IniFile& inifile, const std::vector<GeckoCode>& gcodes);
|
void SaveCodes(Common::IniFile& inifile, const std::vector<GeckoCode>& gcodes);
|
||||||
|
|
||||||
std::optional<GeckoCode::Code> DeserializeLine(const std::string& line);
|
std::optional<GeckoCode::Code> DeserializeLine(const std::string& line);
|
||||||
|
|
|
@ -686,7 +686,7 @@ bool CEXIETHERNET::BuiltInBBAInterface::SendFrame(const u8* frame, u32 size)
|
||||||
}
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
ERROR_LOG_FMT(SP1, "Unsupported EtherType {#06x}", *ethertype);
|
ERROR_LOG_FMT(SP1, "Unsupported EtherType {:#06x}", *ethertype);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -132,7 +132,8 @@ struct DTMHeader
|
||||||
bool bUseFMA;
|
bool bUseFMA;
|
||||||
u8 GBAControllers; // GBA Controllers plugged in (the bits are ports 1-4)
|
u8 GBAControllers; // GBA Controllers plugged in (the bits are ports 1-4)
|
||||||
bool bWidescreen; // true indicates SYSCONF aspect ratio is 16:9, false for 4:3
|
bool bWidescreen; // true indicates SYSCONF aspect ratio is 16:9, false for 4:3
|
||||||
std::array<u8, 6> reserved; // Padding for any new config options
|
u8 countryCode; // SYSCONF country code
|
||||||
|
std::array<u8, 5> reserved; // Padding for any new config options
|
||||||
std::array<char, 40> discChange; // Name of iso file to switch to, for two disc games.
|
std::array<char, 40> discChange; // Name of iso file to switch to, for two disc games.
|
||||||
std::array<u8, 20> revision; // Git hash
|
std::array<u8, 20> revision; // Git hash
|
||||||
u32 DSPiromHash;
|
u32 DSPiromHash;
|
||||||
|
|
|
@ -765,6 +765,14 @@ void JitArm64::rlwinmx_internal(UGeckoInstruction inst, u32 sh)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (mask == 0)
|
||||||
|
{
|
||||||
|
gpr.SetImmediate(a, 0);
|
||||||
|
if (inst.Rc)
|
||||||
|
ComputeRC0(0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
gpr.BindToRegister(a, a == s);
|
gpr.BindToRegister(a, a == s);
|
||||||
|
|
||||||
if (sh == 0 && mask == 0xFFFFFFFF)
|
if (sh == 0 && mask == 0xFFFFFFFF)
|
||||||
|
@ -1128,6 +1136,43 @@ void JitArm64::addzex(UGeckoInstruction inst)
|
||||||
|
|
||||||
int a = inst.RA, d = inst.RD;
|
int a = inst.RA, d = inst.RD;
|
||||||
|
|
||||||
|
if (gpr.IsImm(a) && (gpr.GetImm(a) == 0 || HasConstantCarry()))
|
||||||
|
{
|
||||||
|
const u32 imm = gpr.GetImm(a);
|
||||||
|
const bool is_all_ones = imm == 0xFFFFFFFF;
|
||||||
|
|
||||||
|
switch (js.carryFlag)
|
||||||
|
{
|
||||||
|
case CarryFlag::InPPCState:
|
||||||
|
{
|
||||||
|
gpr.BindToRegister(d, false);
|
||||||
|
LDRB(IndexType::Unsigned, gpr.R(d), PPC_REG, PPCSTATE_OFF(xer_ca));
|
||||||
|
ComputeCarry(false);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case CarryFlag::InHostCarry:
|
||||||
|
{
|
||||||
|
gpr.BindToRegister(d, false);
|
||||||
|
CSET(gpr.R(d), CCFlags::CC_CS);
|
||||||
|
ComputeCarry(false);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case CarryFlag::ConstantTrue:
|
||||||
|
{
|
||||||
|
gpr.SetImmediate(d, imm + 1);
|
||||||
|
ComputeCarry(is_all_ones);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case CarryFlag::ConstantFalse:
|
||||||
|
{
|
||||||
|
gpr.SetImmediate(d, imm);
|
||||||
|
ComputeCarry(false);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
switch (js.carryFlag)
|
switch (js.carryFlag)
|
||||||
{
|
{
|
||||||
case CarryFlag::InPPCState:
|
case CarryFlag::InPPCState:
|
||||||
|
@ -1170,6 +1215,7 @@ void JitArm64::addzex(UGeckoInstruction inst)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (inst.Rc)
|
if (inst.Rc)
|
||||||
ComputeRC0(gpr.R(d));
|
ComputeRC0(gpr.R(d));
|
||||||
|
@ -1216,40 +1262,62 @@ void JitArm64::subfex(UGeckoInstruction inst)
|
||||||
|
|
||||||
if (gpr.IsImm(a) && (mex || gpr.IsImm(b)))
|
if (gpr.IsImm(a) && (mex || gpr.IsImm(b)))
|
||||||
{
|
{
|
||||||
u32 i = gpr.GetImm(a), j = mex ? -1 : gpr.GetImm(b);
|
const u32 i = gpr.GetImm(a);
|
||||||
|
const u32 j = mex ? -1 : gpr.GetImm(b);
|
||||||
gpr.BindToRegister(d, false);
|
const u32 imm = ~i + j;
|
||||||
|
const bool is_zero = imm == 0;
|
||||||
|
const bool is_all_ones = imm == 0xFFFFFFFF;
|
||||||
|
|
||||||
switch (js.carryFlag)
|
switch (js.carryFlag)
|
||||||
{
|
{
|
||||||
case CarryFlag::InPPCState:
|
case CarryFlag::InPPCState:
|
||||||
|
{
|
||||||
|
gpr.BindToRegister(d, false);
|
||||||
|
ARM64Reg RD = gpr.R(d);
|
||||||
|
if (is_zero)
|
||||||
|
{
|
||||||
|
LDRB(IndexType::Unsigned, RD, PPC_REG, PPCSTATE_OFF(xer_ca));
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
auto WA = gpr.GetScopedReg();
|
auto WA = gpr.GetScopedReg();
|
||||||
LDRB(IndexType::Unsigned, WA, PPC_REG, PPCSTATE_OFF(xer_ca));
|
LDRB(IndexType::Unsigned, WA, PPC_REG, PPCSTATE_OFF(xer_ca));
|
||||||
ADDI2R(gpr.R(d), WA, ~i + j, gpr.R(d));
|
ADDI2R(RD, WA, imm, RD);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case CarryFlag::InHostCarry:
|
case CarryFlag::InHostCarry:
|
||||||
{
|
{
|
||||||
auto WA = gpr.GetScopedReg();
|
gpr.BindToRegister(d, false);
|
||||||
MOVI2R(WA, ~i + j);
|
ARM64Reg RD = gpr.R(d);
|
||||||
ADC(gpr.R(d), WA, ARM64Reg::WZR);
|
if (is_all_ones)
|
||||||
|
{
|
||||||
|
// RD = -1 + carry = carry ? 0 : -1
|
||||||
|
// CSETM sets the destination to -1 if the condition is true, 0
|
||||||
|
// otherwise. Hence, the condition must be carry clear.
|
||||||
|
CSETM(RD, CC_CC);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
MOVI2R(RD, imm);
|
||||||
|
ADC(RD, RD, ARM64Reg::WZR);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case CarryFlag::ConstantTrue:
|
case CarryFlag::ConstantTrue:
|
||||||
{
|
{
|
||||||
gpr.SetImmediate(d, ~i + j + 1);
|
gpr.SetImmediate(d, imm + 1);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case CarryFlag::ConstantFalse:
|
case CarryFlag::ConstantFalse:
|
||||||
{
|
{
|
||||||
gpr.SetImmediate(d, ~i + j);
|
gpr.SetImmediate(d, imm);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const bool must_have_carry = Interpreter::Helper_Carry(~i, j);
|
const bool must_have_carry = Interpreter::Helper_Carry(~i, j);
|
||||||
const bool might_have_carry = (~i + j) == 0xFFFFFFFF;
|
const bool might_have_carry = is_all_ones;
|
||||||
|
|
||||||
if (must_have_carry)
|
if (must_have_carry)
|
||||||
{
|
{
|
||||||
|
@ -1337,6 +1405,15 @@ void JitArm64::subfzex(UGeckoInstruction inst)
|
||||||
|
|
||||||
int a = inst.RA, d = inst.RD;
|
int a = inst.RA, d = inst.RD;
|
||||||
|
|
||||||
|
if (gpr.IsImm(a) && HasConstantCarry())
|
||||||
|
{
|
||||||
|
const u32 imm = ~gpr.GetImm(a);
|
||||||
|
const u32 carry = js.carryFlag == CarryFlag::ConstantTrue;
|
||||||
|
gpr.SetImmediate(d, imm + carry);
|
||||||
|
ComputeCarry(Interpreter::Helper_Carry(imm, carry));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
gpr.BindToRegister(d, d == a);
|
gpr.BindToRegister(d, d == a);
|
||||||
|
|
||||||
switch (js.carryFlag)
|
switch (js.carryFlag)
|
||||||
|
@ -1371,6 +1448,7 @@ void JitArm64::subfzex(UGeckoInstruction inst)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (inst.Rc)
|
if (inst.Rc)
|
||||||
ComputeRC0(gpr.R(d));
|
ComputeRC0(gpr.R(d));
|
||||||
|
@ -1436,40 +1514,66 @@ void JitArm64::addex(UGeckoInstruction inst)
|
||||||
|
|
||||||
if (gpr.IsImm(a) && (mex || gpr.IsImm(b)))
|
if (gpr.IsImm(a) && (mex || gpr.IsImm(b)))
|
||||||
{
|
{
|
||||||
u32 i = gpr.GetImm(a), j = mex ? -1 : gpr.GetImm(b);
|
const u32 i = gpr.GetImm(a), j = mex ? -1 : gpr.GetImm(b);
|
||||||
|
const u32 imm = i + j;
|
||||||
gpr.BindToRegister(d, false);
|
const bool is_zero = imm == 0;
|
||||||
|
const bool is_all_ones = imm == 0xFFFFFFFF;
|
||||||
|
|
||||||
switch (js.carryFlag)
|
switch (js.carryFlag)
|
||||||
{
|
{
|
||||||
case CarryFlag::InPPCState:
|
case CarryFlag::InPPCState:
|
||||||
|
{
|
||||||
|
gpr.BindToRegister(d, false);
|
||||||
|
ARM64Reg RD = gpr.R(d);
|
||||||
|
if (is_zero)
|
||||||
|
{
|
||||||
|
LDRB(IndexType::Unsigned, RD, PPC_REG, PPCSTATE_OFF(xer_ca));
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
auto WA = gpr.GetScopedReg();
|
auto WA = gpr.GetScopedReg();
|
||||||
LDRB(IndexType::Unsigned, WA, PPC_REG, PPCSTATE_OFF(xer_ca));
|
LDRB(IndexType::Unsigned, WA, PPC_REG, PPCSTATE_OFF(xer_ca));
|
||||||
ADDI2R(gpr.R(d), WA, i + j, gpr.R(d));
|
ADDI2R(RD, WA, imm, RD);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case CarryFlag::InHostCarry:
|
case CarryFlag::InHostCarry:
|
||||||
{
|
{
|
||||||
|
gpr.BindToRegister(d, false);
|
||||||
ARM64Reg RD = gpr.R(d);
|
ARM64Reg RD = gpr.R(d);
|
||||||
MOVI2R(RD, i + j);
|
if (is_zero)
|
||||||
|
{
|
||||||
|
// RD = 0 + carry = carry ? 1 : 0
|
||||||
|
CSET(RD, CC_CS);
|
||||||
|
}
|
||||||
|
else if (is_all_ones)
|
||||||
|
{
|
||||||
|
// RD = -1 + carry = carry ? 0 : -1
|
||||||
|
// Note that CSETM sets the destination to -1 if the condition is true,
|
||||||
|
// and 0 otherwise. Hence, the condition must be carry clear.
|
||||||
|
CSETM(RD, CC_CC);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
MOVI2R(RD, imm);
|
||||||
ADC(RD, RD, ARM64Reg::WZR);
|
ADC(RD, RD, ARM64Reg::WZR);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case CarryFlag::ConstantTrue:
|
case CarryFlag::ConstantTrue:
|
||||||
{
|
{
|
||||||
gpr.SetImmediate(d, i + j + 1);
|
gpr.SetImmediate(d, imm + 1);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case CarryFlag::ConstantFalse:
|
case CarryFlag::ConstantFalse:
|
||||||
{
|
{
|
||||||
gpr.SetImmediate(d, i + j);
|
gpr.SetImmediate(d, imm);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const bool must_have_carry = Interpreter::Helper_Carry(i, j);
|
const bool must_have_carry = Interpreter::Helper_Carry(i, j);
|
||||||
const bool might_have_carry = (i + j) == 0xFFFFFFFF;
|
const bool might_have_carry = is_all_ones;
|
||||||
|
|
||||||
if (must_have_carry)
|
if (must_have_carry)
|
||||||
{
|
{
|
||||||
|
|
|
@ -817,9 +817,8 @@ void JitArm64::dcbx(UGeckoInstruction inst)
|
||||||
STR(IndexType::Unsigned, loop_counter, PPC_REG, PPCSTATE_OFF_SPR(SPR_CTR));
|
STR(IndexType::Unsigned, loop_counter, PPC_REG, PPCSTATE_OFF_SPR(SPR_CTR));
|
||||||
|
|
||||||
// downcount -= (WA * reg_cycle_count)
|
// downcount -= (WA * reg_cycle_count)
|
||||||
MUL(WB, WA, reg_cycle_count);
|
MSUB(reg_downcount, WA, reg_cycle_count, reg_downcount);
|
||||||
// ^ Note that this cannot overflow because it's limited by (downcount/cycle_count).
|
// ^ Note that this cannot overflow because it's limited by (downcount/cycle_count).
|
||||||
SUB(reg_downcount, reg_downcount, WB);
|
|
||||||
STR(IndexType::Unsigned, reg_downcount, PPC_REG, PPCSTATE_OFF(downcount));
|
STR(IndexType::Unsigned, reg_downcount, PPC_REG, PPCSTATE_OFF(downcount));
|
||||||
|
|
||||||
SetJumpTarget(downcount_is_zero_or_negative);
|
SetJumpTarget(downcount_is_zero_or_negative);
|
||||||
|
|
|
@ -110,7 +110,7 @@ JitBase::~JitBase()
|
||||||
CPUThreadConfigCallback::RemoveConfigChangedCallback(m_registered_config_callback_id);
|
CPUThreadConfigCallback::RemoveConfigChangedCallback(m_registered_config_callback_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool JitBase::DoesConfigNeedRefresh()
|
bool JitBase::DoesConfigNeedRefresh() const
|
||||||
{
|
{
|
||||||
return std::ranges::any_of(JIT_SETTINGS, [this](const auto& pair) {
|
return std::ranges::any_of(JIT_SETTINGS, [this](const auto& pair) {
|
||||||
return this->*pair.first != Config::Get(*pair.second);
|
return this->*pair.first != Config::Get(*pair.second);
|
||||||
|
@ -276,7 +276,7 @@ bool JitBase::CanMergeNextInstructions(int count) const
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool JitBase::ShouldHandleFPExceptionForInstruction(const PPCAnalyst::CodeOp* op)
|
bool JitBase::ShouldHandleFPExceptionForInstruction(const PPCAnalyst::CodeOp* op) const
|
||||||
{
|
{
|
||||||
if (jo.fp_exceptions)
|
if (jo.fp_exceptions)
|
||||||
return (op->opinfo->flags & FL_FLOAT_EXCEPTION) != 0;
|
return (op->opinfo->flags & FL_FLOAT_EXCEPTION) != 0;
|
||||||
|
|
|
@ -167,7 +167,7 @@ protected:
|
||||||
|
|
||||||
static const std::array<std::pair<bool JitBase::*, const Config::Info<bool>*>, 23> JIT_SETTINGS;
|
static const std::array<std::pair<bool JitBase::*, const Config::Info<bool>*>, 23> JIT_SETTINGS;
|
||||||
|
|
||||||
bool DoesConfigNeedRefresh();
|
bool DoesConfigNeedRefresh() const;
|
||||||
void RefreshConfig();
|
void RefreshConfig();
|
||||||
|
|
||||||
void InitFastmemArena();
|
void InitFastmemArena();
|
||||||
|
@ -178,8 +178,16 @@ protected:
|
||||||
void CleanUpAfterStackFault();
|
void CleanUpAfterStackFault();
|
||||||
|
|
||||||
bool CanMergeNextInstructions(int count) const;
|
bool CanMergeNextInstructions(int count) const;
|
||||||
|
bool HasConstantCarry() const
|
||||||
|
{
|
||||||
|
#ifdef _M_ARM_64
|
||||||
|
return js.carryFlag == CarryFlag::ConstantTrue || js.carryFlag == CarryFlag::ConstantFalse;
|
||||||
|
#else
|
||||||
|
return false;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
bool ShouldHandleFPExceptionForInstruction(const PPCAnalyst::CodeOp* op);
|
bool ShouldHandleFPExceptionForInstruction(const PPCAnalyst::CodeOp* op) const;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit JitBase(Core::System& system);
|
explicit JitBase(Core::System& system);
|
||||||
|
|
|
@ -6,11 +6,11 @@
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <map>
|
#include <map>
|
||||||
|
#include <ranges>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <string_view>
|
#include <string_view>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
#include <fmt/format.h>
|
#include <fmt/format.h>
|
||||||
|
|
||||||
|
@ -18,6 +18,7 @@
|
||||||
#include "Common/IOFile.h"
|
#include "Common/IOFile.h"
|
||||||
#include "Common/Logging/Log.h"
|
#include "Common/Logging/Log.h"
|
||||||
#include "Common/StringUtil.h"
|
#include "Common/StringUtil.h"
|
||||||
|
#include "Common/Unreachable.h"
|
||||||
#include "Core/Core.h"
|
#include "Core/Core.h"
|
||||||
#include "Core/Debugger/DebugInterface.h"
|
#include "Core/Debugger/DebugInterface.h"
|
||||||
#include "Core/PowerPC/MMU.h"
|
#include "Core/PowerPC/MMU.h"
|
||||||
|
@ -251,7 +252,7 @@ bool PPCSymbolDB::LoadMap(const Core::CPUThreadGuard& guard, const std::string&
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// Support CodeWarrior and Dolphin map
|
// Support CodeWarrior and Dolphin map
|
||||||
if (std::string_view{line}.ends_with(" section layout\n") || strcmp(temp, ".text") == 0 ||
|
if (StripWhitespace(line).ends_with(" section layout") || strcmp(temp, ".text") == 0 ||
|
||||||
strcmp(temp, ".init") == 0)
|
strcmp(temp, ".init") == 0)
|
||||||
{
|
{
|
||||||
section_name = temp;
|
section_name = temp;
|
||||||
|
@ -310,7 +311,7 @@ bool PPCSymbolDB::LoadMap(const Core::CPUThreadGuard& guard, const std::string&
|
||||||
continue;
|
continue;
|
||||||
column_count = 2;
|
column_count = 2;
|
||||||
|
|
||||||
// Three columns format:
|
// Three columns format (with optional alignment):
|
||||||
// Starting Virtual
|
// Starting Virtual
|
||||||
// address Size address
|
// address Size address
|
||||||
// -----------------------
|
// -----------------------
|
||||||
|
@ -319,7 +320,7 @@ bool PPCSymbolDB::LoadMap(const Core::CPUThreadGuard& guard, const std::string&
|
||||||
else
|
else
|
||||||
iss.str("");
|
iss.str("");
|
||||||
|
|
||||||
// Four columns format:
|
// Four columns format (with optional alignment):
|
||||||
// Starting Virtual File
|
// Starting Virtual File
|
||||||
// address Size address offset
|
// address Size address offset
|
||||||
// ---------------------------------
|
// ---------------------------------
|
||||||
|
@ -327,85 +328,77 @@ bool PPCSymbolDB::LoadMap(const Core::CPUThreadGuard& guard, const std::string&
|
||||||
column_count = 4;
|
column_count = 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 address, vaddress, size, offset, alignment;
|
u32 address;
|
||||||
char name[512], container[512];
|
u32 vaddress;
|
||||||
if (column_count == 4)
|
u32 size = 0;
|
||||||
|
u32 offset = 0;
|
||||||
|
u32 alignment = 0;
|
||||||
|
char name[512]{};
|
||||||
|
static constexpr char ENTRY_OF_STRING[] = " (entry of ";
|
||||||
|
static constexpr std::string_view ENTRY_OF_VIEW(ENTRY_OF_STRING);
|
||||||
|
auto parse_entry_of = [](char* name) {
|
||||||
|
if (char* s1 = strstr(name, ENTRY_OF_STRING); s1 != nullptr)
|
||||||
{
|
{
|
||||||
// sometimes there is no alignment value, and sometimes it is because it is an entry of
|
char container[512];
|
||||||
// something else
|
char* ptr = s1 + ENTRY_OF_VIEW.size();
|
||||||
if (length > 37 && line[37] == ' ')
|
sscanf(ptr, "%511s", container);
|
||||||
|
// Skip sections, those start with a dot, e.g. (entry of .text)
|
||||||
|
if (char* s2 = strchr(container, ')'); s2 != nullptr && *container != '.')
|
||||||
{
|
{
|
||||||
alignment = 0;
|
ptr += strlen(container);
|
||||||
sscanf(line, "%08x %08x %08x %08x %511s", &address, &size, &vaddress, &offset, name);
|
// Preserve data after the entry part, usually it contains object names
|
||||||
char* s = strstr(line, "(entry of ");
|
strcpy(s1, ptr);
|
||||||
if (s)
|
*s2 = '\0';
|
||||||
{
|
|
||||||
sscanf(s + 10, "%511s", container);
|
|
||||||
char* s2 = (strchr(container, ')'));
|
|
||||||
if (s2 && container[0] != '.')
|
|
||||||
{
|
|
||||||
s2[0] = '\0';
|
|
||||||
strcat(container, "::");
|
strcat(container, "::");
|
||||||
strcat(container, name);
|
strcat(container, name);
|
||||||
strcpy(name, container);
|
strcpy(name, container);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
else
|
auto was_alignment = [](const char* name) {
|
||||||
{
|
return *name == ' ' || (*name >= '0' && *name <= '9');
|
||||||
sscanf(line, "%08x %08x %08x %08x %i %511s", &address, &size, &vaddress, &offset,
|
};
|
||||||
&alignment, name);
|
auto parse_alignment = [](char* name, u32* alignment) {
|
||||||
}
|
const std::string buffer(StripWhitespace(name));
|
||||||
}
|
return sscanf(buffer.c_str(), "%i %511[^\r\n]", alignment, name);
|
||||||
else if (column_count == 3)
|
};
|
||||||
|
switch (column_count)
|
||||||
{
|
{
|
||||||
|
case 4:
|
||||||
|
// sometimes there is no alignment value, and sometimes it is because it is an entry of
|
||||||
|
// something else
|
||||||
|
sscanf(line, "%08x %08x %08x %08x %511[^\r\n]", &address, &size, &vaddress, &offset, name);
|
||||||
|
if (was_alignment(name))
|
||||||
|
parse_alignment(name, &alignment);
|
||||||
|
// The `else` statement was omitted to handle symbol already saved in Dolphin symbol map
|
||||||
|
// since it doesn't omit the alignment on save for such case.
|
||||||
|
parse_entry_of(name);
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
// some entries in the table have a function name followed by " (entry of " followed by a
|
// some entries in the table have a function name followed by " (entry of " followed by a
|
||||||
// container name, followed by ")"
|
// container name, followed by ")"
|
||||||
// instead of a space followed by a number followed by a space followed by a name
|
// instead of a space followed by a number followed by a space followed by a name
|
||||||
if (length > 27 && line[27] != ' ' && strstr(line, "(entry of "))
|
sscanf(line, "%08x %08x %08x %511[^\r\n]", &address, &size, &vaddress, name);
|
||||||
{
|
if (was_alignment(name))
|
||||||
alignment = 0;
|
parse_alignment(name, &alignment);
|
||||||
sscanf(line, "%08x %08x %08x %511s", &address, &size, &vaddress, name);
|
// The `else` statement was omitted to handle symbol already saved in Dolphin symbol map
|
||||||
char* s = strstr(line, "(entry of ");
|
// since it doesn't omit the alignment on save for such case.
|
||||||
if (s)
|
parse_entry_of(name);
|
||||||
{
|
break;
|
||||||
sscanf(s + 10, "%511s", container);
|
case 2:
|
||||||
char* s2 = (strchr(container, ')'));
|
sscanf(line, "%08x %511[^\r\n]", &address, name);
|
||||||
if (s2 && container[0] != '.')
|
|
||||||
{
|
|
||||||
s2[0] = '\0';
|
|
||||||
strcat(container, "::");
|
|
||||||
strcat(container, name);
|
|
||||||
strcpy(name, container);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
sscanf(line, "%08x %08x %08x %i %511s", &address, &size, &vaddress, &alignment, name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (column_count == 2)
|
|
||||||
{
|
|
||||||
sscanf(line, "%08x %511s", &address, name);
|
|
||||||
vaddress = address;
|
vaddress = address;
|
||||||
size = 0;
|
break;
|
||||||
}
|
default:
|
||||||
else
|
// Should never happen
|
||||||
{
|
Common::Unreachable();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
const char* namepos = strstr(line, name);
|
|
||||||
if (namepos != nullptr) // would be odd if not :P
|
|
||||||
strcpy(name, namepos);
|
|
||||||
name[strlen(name) - 1] = 0;
|
|
||||||
if (name[strlen(name) - 1] == '\r')
|
|
||||||
name[strlen(name) - 1] = 0;
|
|
||||||
|
|
||||||
// Split the current name string into separate parts, and get the object name
|
// Split the current name string into separate parts, and get the object name
|
||||||
// if it exists.
|
// if it exists.
|
||||||
const std::vector<std::string> parts = SplitString(name, '\t');
|
const std::vector<std::string> parts = SplitString(name, '\t');
|
||||||
const std::string name_string(StripWhitespace(parts[0]));
|
const std::string name_string(StripWhitespace(parts.size() > 0 ? parts[0] : name));
|
||||||
const std::string object_filename_string =
|
const std::string object_filename_string =
|
||||||
parts.size() > 1 ? std::string(StripWhitespace(parts[1])) : "";
|
parts.size() > 1 ? std::string(StripWhitespace(parts[1])) : "";
|
||||||
|
|
||||||
|
@ -466,42 +459,38 @@ bool PPCSymbolDB::SaveSymbolMap(const std::string& filename) const
|
||||||
if (!f)
|
if (!f)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
std::vector<const Common::Symbol*> function_symbols;
|
|
||||||
std::vector<const Common::Symbol*> data_symbols;
|
|
||||||
|
|
||||||
for (const auto& function : m_functions)
|
|
||||||
{
|
|
||||||
const Common::Symbol& symbol = function.second;
|
|
||||||
if (symbol.type == Common::Symbol::Type::Function)
|
|
||||||
function_symbols.push_back(&symbol);
|
|
||||||
else
|
|
||||||
data_symbols.push_back(&symbol);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Write .text section
|
// Write .text section
|
||||||
|
auto function_symbols =
|
||||||
|
m_functions |
|
||||||
|
std::views::filter([](auto f) { return f.second.type == Common::Symbol::Type::Function; }) |
|
||||||
|
std::views::transform([](auto f) { return f.second; });
|
||||||
f.WriteString(".text section layout\n");
|
f.WriteString(".text section layout\n");
|
||||||
for (const auto& symbol : function_symbols)
|
for (const auto& symbol : function_symbols)
|
||||||
{
|
{
|
||||||
// Write symbol address, size, virtual address, alignment, name
|
// Write symbol address, size, virtual address, alignment, name
|
||||||
std::string line = fmt::format("{0:08x} {1:06x} {2:08x} {3} {4}", symbol->address, symbol->size,
|
std::string line = fmt::format("{:08x} {:06x} {:08x} {} {}", symbol.address, symbol.size,
|
||||||
symbol->address, 0, symbol->name);
|
symbol.address, 0, symbol.name);
|
||||||
// Also write the object name if it exists
|
// Also write the object name if it exists
|
||||||
if (!symbol->object_name.empty())
|
if (!symbol.object_name.empty())
|
||||||
line += fmt::format(" \t{0}", symbol->object_name);
|
line += fmt::format(" \t{0}", symbol.object_name);
|
||||||
line += "\n";
|
line += "\n";
|
||||||
f.WriteString(line);
|
f.WriteString(line);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Write .data section
|
// Write .data section
|
||||||
|
auto data_symbols =
|
||||||
|
m_functions |
|
||||||
|
std::views::filter([](auto f) { return f.second.type == Common::Symbol::Type::Data; }) |
|
||||||
|
std::views::transform([](auto f) { return f.second; });
|
||||||
f.WriteString("\n.data section layout\n");
|
f.WriteString("\n.data section layout\n");
|
||||||
for (const auto& symbol : data_symbols)
|
for (const auto& symbol : data_symbols)
|
||||||
{
|
{
|
||||||
// Write symbol address, size, virtual address, alignment, name
|
// Write symbol address, size, virtual address, alignment, name
|
||||||
std::string line = fmt::format("{0:08x} {1:06x} {2:08x} {3} {4}", symbol->address, symbol->size,
|
std::string line = fmt::format("{:08x} {:06x} {:08x} {} {}", symbol.address, symbol.size,
|
||||||
symbol->address, 0, symbol->name);
|
symbol.address, 0, symbol.name);
|
||||||
// Also write the object name if it exists
|
// Also write the object name if it exists
|
||||||
if (!symbol->object_name.empty())
|
if (!symbol.object_name.empty())
|
||||||
line += fmt::format(" \t{0}", symbol->object_name);
|
line += fmt::format(" \t{0}", symbol.object_name);
|
||||||
line += "\n";
|
line += "\n";
|
||||||
f.WriteString(line);
|
f.WriteString(line);
|
||||||
}
|
}
|
||||||
|
|
|
@ -467,12 +467,7 @@ OnlineSystemUpdater::Response OnlineSystemUpdater::GetSystemTitles()
|
||||||
// but the backing data CDN is still active and accessible from other URLs. We take advantage
|
// but the backing data CDN is still active and accessible from other URLs. We take advantage
|
||||||
// of this by hosting our own NetUpdateSOAP endpoint which serves the correct list of titles to
|
// of this by hosting our own NetUpdateSOAP endpoint which serves the correct list of titles to
|
||||||
// install along with URLs for the Wii U CDN.
|
// install along with URLs for the Wii U CDN.
|
||||||
#ifdef ANDROID
|
|
||||||
// HTTPS is unsupported on Android (https://bugs.dolphin-emu.org/issues/11772).
|
|
||||||
base_url = "http://fakenus.dolphin-emu.org";
|
|
||||||
#else
|
|
||||||
base_url = "https://fakenus.dolphin-emu.org";
|
base_url = "https://fakenus.dolphin-emu.org";
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const std::string url = fmt::format("{}/nus/services/NetUpdateSOAP", base_url);
|
const std::string url = fmt::format("{}/nus/services/NetUpdateSOAP", base_url);
|
||||||
|
|
|
@ -573,12 +573,11 @@ endif()
|
||||||
|
|
||||||
if(APPLE)
|
if(APPLE)
|
||||||
include(BundleUtilities)
|
include(BundleUtilities)
|
||||||
set(BUNDLE_PATH ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/DolphinQt.app)
|
|
||||||
|
|
||||||
# Ask for an application bundle.
|
# Ask for an application bundle.
|
||||||
set_target_properties(dolphin-emu PROPERTIES
|
set_target_properties(dolphin-emu PROPERTIES
|
||||||
MACOSX_BUNDLE true
|
MACOSX_BUNDLE true
|
||||||
MACOSX_BUNDLE_INFO_PLIST "${CMAKE_CURRENT_BINARY_DIR}/Info.plist"
|
MACOSX_BUNDLE_INFO_PLIST "${CMAKE_CURRENT_SOURCE_DIR}/Info.plist.in"
|
||||||
XCODE_ATTRIBUTE_CODE_SIGN_IDENTITY ""
|
XCODE_ATTRIBUTE_CODE_SIGN_IDENTITY ""
|
||||||
OUTPUT_NAME DolphinQt
|
OUTPUT_NAME DolphinQt
|
||||||
)
|
)
|
||||||
|
@ -615,6 +614,9 @@ if(APPLE)
|
||||||
source_group("Resources" FILES "${CMAKE_SOURCE_DIR}/Data/${res}")
|
source_group("Resources" FILES "${CMAKE_SOURCE_DIR}/Data/${res}")
|
||||||
endforeach()
|
endforeach()
|
||||||
|
|
||||||
|
include(DolphinInjectVersionInfo)
|
||||||
|
dolphin_inject_version_info(dolphin-emu)
|
||||||
|
|
||||||
# Copy MoltenVK into the bundle
|
# Copy MoltenVK into the bundle
|
||||||
if(ENABLE_VULKAN)
|
if(ENABLE_VULKAN)
|
||||||
if(USE_BUNDLED_MOLTENVK)
|
if(USE_BUNDLED_MOLTENVK)
|
||||||
|
@ -649,7 +651,7 @@ if(APPLE)
|
||||||
COMMAND "${CMAKE_SOURCE_DIR}/Tools/mac-codesign.sh"
|
COMMAND "${CMAKE_SOURCE_DIR}/Tools/mac-codesign.sh"
|
||||||
"-e" "${CMAKE_CURRENT_SOURCE_DIR}/DolphinEmu$<$<CONFIG:Debug>:Debug>.entitlements"
|
"-e" "${CMAKE_CURRENT_SOURCE_DIR}/DolphinEmu$<$<CONFIG:Debug>:Debug>.entitlements"
|
||||||
"${MACOS_CODE_SIGNING_IDENTITY}"
|
"${MACOS_CODE_SIGNING_IDENTITY}"
|
||||||
"${BUNDLE_PATH}"
|
"$<TARGET_BUNDLE_DIR:dolphin-emu>"
|
||||||
)
|
)
|
||||||
endif()
|
endif()
|
||||||
else()
|
else()
|
||||||
|
|
|
@ -74,7 +74,7 @@ void ConfigStringChoice::OnConfigChanged()
|
||||||
|
|
||||||
ConfigComplexChoice::ConfigComplexChoice(const InfoVariant setting1, const InfoVariant setting2,
|
ConfigComplexChoice::ConfigComplexChoice(const InfoVariant setting1, const InfoVariant setting2,
|
||||||
Config::Layer* layer)
|
Config::Layer* layer)
|
||||||
: m_setting1(setting1), m_setting2(setting2), m_layer(layer)
|
: m_layer(layer), m_setting1(setting1), m_setting2(setting2)
|
||||||
{
|
{
|
||||||
connect(&Settings::Instance(), &Settings::ConfigChanged, this, &ConfigComplexChoice::Refresh);
|
connect(&Settings::Instance(), &Settings::ConfigChanged, this, &ConfigComplexChoice::Refresh);
|
||||||
connect(this, &QComboBox::currentIndexChanged, this, &ConfigComplexChoice::SaveValue);
|
connect(this, &QComboBox::currentIndexChanged, this, &ConfigComplexChoice::SaveValue);
|
||||||
|
@ -115,7 +115,7 @@ void ConfigComplexChoice::Reset()
|
||||||
|
|
||||||
void ConfigComplexChoice::SaveValue(int choice)
|
void ConfigComplexChoice::SaveValue(int choice)
|
||||||
{
|
{
|
||||||
auto Set = [this, choice](auto& setting, auto& value) {
|
auto Set = [this](auto& setting, auto& value) {
|
||||||
if (m_layer != nullptr)
|
if (m_layer != nullptr)
|
||||||
{
|
{
|
||||||
m_layer->Set(setting.GetLocation(), value);
|
m_layer->Set(setting.GetLocation(), value);
|
||||||
|
|
|
@ -34,7 +34,8 @@ using SIDeviceName = std::pair<SerialInterface::SIDevices, const char*>;
|
||||||
static constexpr std::array s_gc_types = {
|
static constexpr std::array s_gc_types = {
|
||||||
SIDeviceName{SerialInterface::SIDEVICE_NONE, _trans("None")},
|
SIDeviceName{SerialInterface::SIDEVICE_NONE, _trans("None")},
|
||||||
SIDeviceName{SerialInterface::SIDEVICE_GC_CONTROLLER, _trans("Standard Controller")},
|
SIDeviceName{SerialInterface::SIDEVICE_GC_CONTROLLER, _trans("Standard Controller")},
|
||||||
SIDeviceName{SerialInterface::SIDEVICE_WIIU_ADAPTER, _trans("GameCube Adapter for Wii U")},
|
SIDeviceName{SerialInterface::SIDEVICE_WIIU_ADAPTER,
|
||||||
|
_trans("GameCube Controller Adapter (USB)")},
|
||||||
SIDeviceName{SerialInterface::SIDEVICE_GC_STEERING, _trans("Steering Wheel")},
|
SIDeviceName{SerialInterface::SIDEVICE_GC_STEERING, _trans("Steering Wheel")},
|
||||||
SIDeviceName{SerialInterface::SIDEVICE_DANCEMAT, _trans("Dance Mat")},
|
SIDeviceName{SerialInterface::SIDEVICE_DANCEMAT, _trans("Dance Mat")},
|
||||||
SIDeviceName{SerialInterface::SIDEVICE_GC_TARUKONGA, _trans("DK Bongos")},
|
SIDeviceName{SerialInterface::SIDEVICE_GC_TARUKONGA, _trans("DK Bongos")},
|
||||||
|
|
|
@ -36,7 +36,7 @@ AdvancedWidget::AdvancedWidget(GraphicsWindow* parent)
|
||||||
OnEmulationStateChanged(state != Core::State::Uninitialized);
|
OnEmulationStateChanged(state != Core::State::Uninitialized);
|
||||||
});
|
});
|
||||||
connect(m_manual_texture_sampling, &QCheckBox::toggled,
|
connect(m_manual_texture_sampling, &QCheckBox::toggled,
|
||||||
[this, parent] { emit parent->UseFastTextureSamplingChanged(); });
|
[parent] { emit parent->UseFastTextureSamplingChanged(); });
|
||||||
|
|
||||||
OnBackendChanged();
|
OnBackendChanged();
|
||||||
OnEmulationStateChanged(!Core::IsUninitialized(Core::System::GetInstance()));
|
OnEmulationStateChanged(!Core::IsUninitialized(Core::System::GetInstance()));
|
||||||
|
@ -262,7 +262,7 @@ void AdvancedWidget::ConnectWidgets()
|
||||||
m_dump_base_textures->setEnabled(checked);
|
m_dump_base_textures->setEnabled(checked);
|
||||||
});
|
});
|
||||||
connect(m_enable_graphics_mods, &QCheckBox::toggled, this,
|
connect(m_enable_graphics_mods, &QCheckBox::toggled, this,
|
||||||
[this](bool checked) { emit Settings::Instance().EnableGfxModsChanged(checked); });
|
[](bool checked) { emit Settings::Instance().EnableGfxModsChanged(checked); });
|
||||||
#if defined(HAVE_FFMPEG)
|
#if defined(HAVE_FFMPEG)
|
||||||
connect(m_dump_use_lossless, &QCheckBox::toggled, this,
|
connect(m_dump_use_lossless, &QCheckBox::toggled, this,
|
||||||
[this](bool checked) { m_dump_bitrate->setEnabled(!checked); });
|
[this](bool checked) { m_dump_bitrate->setEnabled(!checked); });
|
||||||
|
|
|
@ -32,7 +32,7 @@ GCPadWiiUConfigDialog::~GCPadWiiUConfigDialog()
|
||||||
|
|
||||||
void GCPadWiiUConfigDialog::CreateLayout()
|
void GCPadWiiUConfigDialog::CreateLayout()
|
||||||
{
|
{
|
||||||
setWindowTitle(tr("GameCube Adapter for Wii U at Port %1").arg(m_port + 1));
|
setWindowTitle(tr("GameCube Controller Adapter at Port %1").arg(m_port + 1));
|
||||||
|
|
||||||
m_layout = new QVBoxLayout();
|
m_layout = new QVBoxLayout();
|
||||||
m_status_label = new QLabel();
|
m_status_label = new QLabel();
|
||||||
|
|
|
@ -4,7 +4,6 @@
|
||||||
#include "DolphinQt/Config/Mapping/IOWindow.h"
|
#include "DolphinQt/Config/Mapping/IOWindow.h"
|
||||||
|
|
||||||
#include <optional>
|
#include <optional>
|
||||||
#include <thread>
|
|
||||||
|
|
||||||
#include <QBrush>
|
#include <QBrush>
|
||||||
#include <QColor>
|
#include <QColor>
|
||||||
|
@ -20,16 +19,15 @@
|
||||||
#include <QSlider>
|
#include <QSlider>
|
||||||
#include <QSpinBox>
|
#include <QSpinBox>
|
||||||
#include <QTableWidget>
|
#include <QTableWidget>
|
||||||
|
#include <QTimer>
|
||||||
#include <QVBoxLayout>
|
#include <QVBoxLayout>
|
||||||
|
|
||||||
#include "Core/Core.h"
|
|
||||||
|
|
||||||
#include "DolphinQt/Config/Mapping/MappingCommon.h"
|
#include "DolphinQt/Config/Mapping/MappingCommon.h"
|
||||||
#include "DolphinQt/Config/Mapping/MappingIndicator.h"
|
#include "DolphinQt/Config/Mapping/MappingIndicator.h"
|
||||||
#include "DolphinQt/Config/Mapping/MappingWidget.h"
|
|
||||||
#include "DolphinQt/Config/Mapping/MappingWindow.h"
|
#include "DolphinQt/Config/Mapping/MappingWindow.h"
|
||||||
#include "DolphinQt/QtUtils/BlockUserInputFilter.h"
|
#include "DolphinQt/QtUtils/BlockUserInputFilter.h"
|
||||||
#include "DolphinQt/QtUtils/ModalMessageBox.h"
|
#include "DolphinQt/QtUtils/ModalMessageBox.h"
|
||||||
|
#include "DolphinQt/QtUtils/SetWindowDecorations.h"
|
||||||
#include "DolphinQt/Settings.h"
|
#include "DolphinQt/Settings.h"
|
||||||
|
|
||||||
#include "InputCommon/ControlReference/ControlReference.h"
|
#include "InputCommon/ControlReference/ControlReference.h"
|
||||||
|
@ -40,6 +38,9 @@
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
|
constexpr auto INPUT_DETECT_TIME = std::chrono::seconds(2);
|
||||||
|
constexpr auto OUTPUT_TEST_TIME = std::chrono::seconds(2);
|
||||||
|
|
||||||
QTextCharFormat GetSpecialCharFormat()
|
QTextCharFormat GetSpecialCharFormat()
|
||||||
{
|
{
|
||||||
QTextCharFormat format;
|
QTextCharFormat format;
|
||||||
|
@ -228,15 +229,17 @@ private:
|
||||||
bool m_should_paint_state_indicator = false;
|
bool m_should_paint_state_indicator = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
IOWindow::IOWindow(MappingWidget* parent, ControllerEmu::EmulatedController* controller,
|
IOWindow::IOWindow(MappingWindow* window, ControllerEmu::EmulatedController* controller,
|
||||||
ControlReference* ref, IOWindow::Type type)
|
ControlReference* ref, IOWindow::Type type)
|
||||||
: QDialog(parent), m_reference(ref), m_original_expression(ref->GetExpression()),
|
: QDialog(window), m_reference(ref), m_original_expression(ref->GetExpression()),
|
||||||
m_controller(controller), m_type(type)
|
m_controller(controller), m_type(type)
|
||||||
{
|
{
|
||||||
|
SetQWidgetWindowDecorations(this);
|
||||||
|
|
||||||
CreateMainLayout();
|
CreateMainLayout();
|
||||||
|
|
||||||
connect(parent, &MappingWidget::Update, this, &IOWindow::Update);
|
connect(window, &MappingWindow::Update, this, &IOWindow::Update);
|
||||||
connect(parent->GetParent(), &MappingWindow::ConfigChanged, this, &IOWindow::ConfigChanged);
|
connect(window, &MappingWindow::ConfigChanged, this, &IOWindow::ConfigChanged);
|
||||||
connect(&Settings::Instance(), &Settings::ConfigChanged, this, &IOWindow::ConfigChanged);
|
connect(&Settings::Instance(), &Settings::ConfigChanged, this, &IOWindow::ConfigChanged);
|
||||||
|
|
||||||
setWindowTitle(type == IOWindow::Type::Input ? tr("Configure Input") : tr("Configure Output"));
|
setWindowTitle(type == IOWindow::Type::Input ? tr("Configure Input") : tr("Configure Output"));
|
||||||
|
@ -258,18 +261,29 @@ void IOWindow::CreateMainLayout()
|
||||||
|
|
||||||
m_devices_combo = new QComboBox();
|
m_devices_combo = new QComboBox();
|
||||||
m_option_list = new QTableWidget();
|
m_option_list = new QTableWidget();
|
||||||
m_select_button = new QPushButton(tr("Select"));
|
|
||||||
m_detect_button = new QPushButton(tr("Detect"), this);
|
m_select_button =
|
||||||
m_test_button = new QPushButton(tr("Test"), this);
|
new QPushButton(m_type == IOWindow::Type::Input ? tr("Insert Input") : tr("Insert Output"));
|
||||||
|
m_detect_button = new QPushButton(tr("Detect Input"), this);
|
||||||
|
m_test_button = new QPushButton(tr("Test Output"), this);
|
||||||
m_button_box = new QDialogButtonBox();
|
m_button_box = new QDialogButtonBox();
|
||||||
m_clear_button = new QPushButton(tr("Clear"));
|
m_clear_button = new QPushButton(tr("Clear"));
|
||||||
m_scalar_spinbox = new QSpinBox();
|
m_scalar_spinbox = new QSpinBox();
|
||||||
|
|
||||||
|
if (m_type == Type::Input)
|
||||||
|
{
|
||||||
m_parse_text = new InputStateLineEdit([this] {
|
m_parse_text = new InputStateLineEdit([this] {
|
||||||
const auto lock = m_controller->GetStateLock();
|
const auto lock = m_controller->GetStateLock();
|
||||||
return m_reference->GetState<ControlState>();
|
return m_reference->GetState<ControlState>();
|
||||||
});
|
});
|
||||||
m_parse_text->setReadOnly(true);
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_parse_text = new InputStateLineEdit([this] {
|
||||||
|
const auto lock = m_controller->GetStateLock();
|
||||||
|
return m_output_test_timer->isActive() * m_reference->range;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
m_expression_text = new QPlainTextEdit();
|
m_expression_text = new QPlainTextEdit();
|
||||||
m_expression_text->setFont(QFontDatabase::systemFont(QFontDatabase::FixedFont));
|
m_expression_text->setFont(QFontDatabase::systemFont(QFontDatabase::FixedFont));
|
||||||
|
@ -419,11 +433,17 @@ void IOWindow::CreateMainLayout()
|
||||||
m_button_box->addButton(m_clear_button, QDialogButtonBox::ActionRole);
|
m_button_box->addButton(m_clear_button, QDialogButtonBox::ActionRole);
|
||||||
m_button_box->addButton(QDialogButtonBox::Ok);
|
m_button_box->addButton(QDialogButtonBox::Ok);
|
||||||
|
|
||||||
|
m_output_test_timer = new QTimer(this);
|
||||||
|
m_output_test_timer->setSingleShot(true);
|
||||||
|
|
||||||
setLayout(m_main_layout);
|
setLayout(m_main_layout);
|
||||||
}
|
}
|
||||||
|
|
||||||
void IOWindow::ConfigChanged()
|
void IOWindow::ConfigChanged()
|
||||||
{
|
{
|
||||||
|
emit DetectInputComplete();
|
||||||
|
emit TestOutputComplete();
|
||||||
|
|
||||||
const QSignalBlocker blocker(this);
|
const QSignalBlocker blocker(this);
|
||||||
const auto lock = ControllerEmu::EmulatedController::GetStateLock();
|
const auto lock = ControllerEmu::EmulatedController::GetStateLock();
|
||||||
|
|
||||||
|
@ -444,6 +464,31 @@ void IOWindow::Update()
|
||||||
{
|
{
|
||||||
m_option_list->viewport()->update();
|
m_option_list->viewport()->update();
|
||||||
m_parse_text->update();
|
m_parse_text->update();
|
||||||
|
|
||||||
|
if (!m_input_detector)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (m_input_detector->IsComplete())
|
||||||
|
{
|
||||||
|
const auto results = m_input_detector->TakeResults();
|
||||||
|
|
||||||
|
emit DetectInputComplete();
|
||||||
|
|
||||||
|
if (results.empty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
// Select the first detected input.
|
||||||
|
auto list = m_option_list->findItems(QString::fromStdString(results.front().input->GetName()),
|
||||||
|
Qt::MatchFixedString);
|
||||||
|
if (list.empty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
m_option_list->setCurrentItem(list.front());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
m_input_detector->Update(INPUT_DETECT_TIME, {}, INPUT_DETECT_TIME);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void IOWindow::ConnectWidgets()
|
void IOWindow::ConnectWidgets()
|
||||||
|
@ -453,8 +498,50 @@ void IOWindow::ConnectWidgets()
|
||||||
connect(&Settings::Instance(), &Settings::ReleaseDevices, this, &IOWindow::ReleaseDevices);
|
connect(&Settings::Instance(), &Settings::ReleaseDevices, this, &IOWindow::ReleaseDevices);
|
||||||
connect(&Settings::Instance(), &Settings::DevicesChanged, this, &IOWindow::UpdateDeviceList);
|
connect(&Settings::Instance(), &Settings::DevicesChanged, this, &IOWindow::UpdateDeviceList);
|
||||||
|
|
||||||
connect(m_detect_button, &QPushButton::clicked, this, &IOWindow::OnDetectButtonPressed);
|
// Input detection:
|
||||||
connect(m_test_button, &QPushButton::clicked, this, &IOWindow::OnTestButtonPressed);
|
// Clicking "Detect" button starts a timer before the actual detection.
|
||||||
|
auto* const input_detect_start_timer = new QTimer(this);
|
||||||
|
input_detect_start_timer->setSingleShot(true);
|
||||||
|
connect(m_detect_button, &QPushButton::clicked, [this, input_detect_start_timer] {
|
||||||
|
m_detect_button->setText(tr("[ ... ]"));
|
||||||
|
input_detect_start_timer->start(MappingCommon::INPUT_DETECT_INITIAL_DELAY);
|
||||||
|
});
|
||||||
|
connect(input_detect_start_timer, &QTimer::timeout, [this] {
|
||||||
|
m_detect_button->setText(tr("[ Press Now ]"));
|
||||||
|
m_input_detector = std::make_unique<ciface::Core::InputDetector>();
|
||||||
|
const auto lock = m_controller->GetStateLock();
|
||||||
|
m_input_detector->Start(g_controller_interface, {m_devq.ToString()});
|
||||||
|
QtUtils::InstallKeyboardBlocker(m_detect_button, this, &IOWindow::DetectInputComplete);
|
||||||
|
});
|
||||||
|
connect(this, &IOWindow::DetectInputComplete,
|
||||||
|
[this, initial_text = m_detect_button->text(), input_detect_start_timer] {
|
||||||
|
input_detect_start_timer->stop();
|
||||||
|
m_input_detector.reset();
|
||||||
|
m_detect_button->setText(initial_text);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Rumble testing:
|
||||||
|
connect(m_test_button, &QPushButton::clicked, [this] {
|
||||||
|
// Stop if already started.
|
||||||
|
if (m_output_test_timer->isActive())
|
||||||
|
{
|
||||||
|
emit IOWindow::TestOutputComplete();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
m_test_button->setText(QStringLiteral("[ ... ]"));
|
||||||
|
m_output_test_timer->start(OUTPUT_TEST_TIME);
|
||||||
|
const auto lock = m_controller->GetStateLock();
|
||||||
|
m_reference->State(1.0);
|
||||||
|
});
|
||||||
|
connect(m_output_test_timer, &QTimer::timeout,
|
||||||
|
[this, initial_text = m_test_button->text()] { emit TestOutputComplete(); });
|
||||||
|
connect(this, &IOWindow::TestOutputComplete, [this, initial_text = m_test_button->text()] {
|
||||||
|
m_output_test_timer->stop();
|
||||||
|
m_test_button->setText(initial_text);
|
||||||
|
const auto lock = m_controller->GetStateLock();
|
||||||
|
m_reference->State(0.0);
|
||||||
|
});
|
||||||
|
connect(this, &IOWindow::closeEvent, this, &IOWindow::TestOutputComplete);
|
||||||
|
|
||||||
connect(m_button_box, &QDialogButtonBox::clicked, this, &IOWindow::OnDialogButtonPressed);
|
connect(m_button_box, &QDialogButtonBox::clicked, this, &IOWindow::OnDialogButtonPressed);
|
||||||
connect(m_devices_combo, &QComboBox::currentTextChanged, this, &IOWindow::OnDeviceChanged);
|
connect(m_devices_combo, &QComboBox::currentTextChanged, this, &IOWindow::OnDeviceChanged);
|
||||||
|
@ -546,30 +633,10 @@ void IOWindow::OnDialogButtonPressed(QAbstractButton* button)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void IOWindow::OnDetectButtonPressed()
|
|
||||||
{
|
|
||||||
const auto expression =
|
|
||||||
MappingCommon::DetectExpression(m_detect_button, g_controller_interface, {m_devq.ToString()},
|
|
||||||
m_devq, ciface::MappingCommon::Quote::Off);
|
|
||||||
|
|
||||||
if (expression.isEmpty())
|
|
||||||
return;
|
|
||||||
|
|
||||||
const auto list = m_option_list->findItems(expression, Qt::MatchFixedString);
|
|
||||||
|
|
||||||
// Try to select the first. If this fails, the last selected item would still appear as such
|
|
||||||
if (!list.empty())
|
|
||||||
m_option_list->setCurrentItem(list[0]);
|
|
||||||
}
|
|
||||||
|
|
||||||
void IOWindow::OnTestButtonPressed()
|
|
||||||
{
|
|
||||||
MappingCommon::TestOutput(m_test_button, static_cast<OutputReference*>(m_reference));
|
|
||||||
}
|
|
||||||
|
|
||||||
void IOWindow::OnRangeChanged(int value)
|
void IOWindow::OnRangeChanged(int value)
|
||||||
{
|
{
|
||||||
m_reference->range = value / 100.0;
|
m_reference->range = value / 100.0;
|
||||||
|
emit TestOutputComplete();
|
||||||
}
|
}
|
||||||
|
|
||||||
void IOWindow::ReleaseDevices()
|
void IOWindow::ReleaseDevices()
|
||||||
|
@ -670,6 +737,8 @@ void IOWindow::UpdateDeviceList()
|
||||||
|
|
||||||
void IOWindow::UpdateExpression(std::string new_expression, UpdateMode mode)
|
void IOWindow::UpdateExpression(std::string new_expression, UpdateMode mode)
|
||||||
{
|
{
|
||||||
|
emit TestOutputComplete();
|
||||||
|
|
||||||
const auto lock = m_controller->GetStateLock();
|
const auto lock = m_controller->GetStateLock();
|
||||||
if (mode != UpdateMode::Force && new_expression == m_reference->GetExpression())
|
if (mode != UpdateMode::Force && new_expression == m_reference->GetExpression())
|
||||||
return;
|
return;
|
||||||
|
@ -719,6 +788,7 @@ InputStateDelegate::InputStateDelegate(IOWindow* parent, int column,
|
||||||
InputStateLineEdit::InputStateLineEdit(std::function<ControlState()> state_evaluator)
|
InputStateLineEdit::InputStateLineEdit(std::function<ControlState()> state_evaluator)
|
||||||
: m_state_evaluator(std::move(state_evaluator))
|
: m_state_evaluator(std::move(state_evaluator))
|
||||||
{
|
{
|
||||||
|
setReadOnly(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void PaintStateIndicator(QPainter& painter, const QRect& region, ControlState state)
|
static void PaintStateIndicator(QPainter& painter, const QRect& region, ControlState state)
|
||||||
|
|
|
@ -12,11 +12,10 @@
|
||||||
#include <QString>
|
#include <QString>
|
||||||
#include <QSyntaxHighlighter>
|
#include <QSyntaxHighlighter>
|
||||||
|
|
||||||
#include "Common/Flag.h"
|
|
||||||
#include "InputCommon/ControllerInterface/CoreDevice.h"
|
#include "InputCommon/ControllerInterface/CoreDevice.h"
|
||||||
|
|
||||||
class ControlReference;
|
class ControlReference;
|
||||||
class MappingWidget;
|
class MappingWindow;
|
||||||
class QAbstractButton;
|
class QAbstractButton;
|
||||||
class QDialogButtonBox;
|
class QDialogButtonBox;
|
||||||
class QLineEdit;
|
class QLineEdit;
|
||||||
|
@ -66,9 +65,13 @@ public:
|
||||||
Output
|
Output
|
||||||
};
|
};
|
||||||
|
|
||||||
explicit IOWindow(MappingWidget* parent, ControllerEmu::EmulatedController* m_controller,
|
explicit IOWindow(MappingWindow* window, ControllerEmu::EmulatedController* m_controller,
|
||||||
ControlReference* ref, Type type);
|
ControlReference* ref, Type type);
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void DetectInputComplete();
|
||||||
|
void TestOutputComplete();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::shared_ptr<ciface::Core::Device> GetSelectedDevice() const;
|
std::shared_ptr<ciface::Core::Device> GetSelectedDevice() const;
|
||||||
|
|
||||||
|
@ -79,8 +82,6 @@ private:
|
||||||
|
|
||||||
void OnDialogButtonPressed(QAbstractButton* button);
|
void OnDialogButtonPressed(QAbstractButton* button);
|
||||||
void OnDeviceChanged();
|
void OnDeviceChanged();
|
||||||
void OnDetectButtonPressed();
|
|
||||||
void OnTestButtonPressed();
|
|
||||||
void OnRangeChanged(int range);
|
void OnRangeChanged(int range);
|
||||||
|
|
||||||
void AppendSelectedOption();
|
void AppendSelectedOption();
|
||||||
|
@ -115,10 +116,12 @@ private:
|
||||||
|
|
||||||
// Input actions
|
// Input actions
|
||||||
QPushButton* m_detect_button;
|
QPushButton* m_detect_button;
|
||||||
|
std::unique_ptr<ciface::Core::InputDetector> m_input_detector;
|
||||||
QComboBox* m_functions_combo;
|
QComboBox* m_functions_combo;
|
||||||
|
|
||||||
// Output actions
|
// Output actions
|
||||||
QPushButton* m_test_button;
|
QPushButton* m_test_button;
|
||||||
|
QTimer* m_output_test_timer;
|
||||||
|
|
||||||
// Textarea
|
// Textarea
|
||||||
QPlainTextEdit* m_expression_text;
|
QPlainTextEdit* m_expression_text;
|
||||||
|
|
|
@ -9,13 +9,12 @@
|
||||||
#include <QString>
|
#include <QString>
|
||||||
|
|
||||||
#include "DolphinQt/Config/Mapping/IOWindow.h"
|
#include "DolphinQt/Config/Mapping/IOWindow.h"
|
||||||
#include "DolphinQt/Config/Mapping/MappingCommon.h"
|
|
||||||
#include "DolphinQt/Config/Mapping/MappingWidget.h"
|
#include "DolphinQt/Config/Mapping/MappingWidget.h"
|
||||||
#include "DolphinQt/Config/Mapping/MappingWindow.h"
|
#include "DolphinQt/Config/Mapping/MappingWindow.h"
|
||||||
|
#include "DolphinQt/QtUtils/BlockUserInputFilter.h"
|
||||||
#include "DolphinQt/QtUtils/SetWindowDecorations.h"
|
#include "DolphinQt/QtUtils/SetWindowDecorations.h"
|
||||||
|
|
||||||
#include "InputCommon/ControlReference/ControlReference.h"
|
#include "InputCommon/ControlReference/ControlReference.h"
|
||||||
#include "InputCommon/ControllerEmu/ControlGroup/Buttons.h"
|
|
||||||
#include "InputCommon/ControllerEmu/ControllerEmu.h"
|
#include "InputCommon/ControllerEmu/ControllerEmu.h"
|
||||||
#include "InputCommon/ControllerInterface/ControllerInterface.h"
|
#include "InputCommon/ControllerInterface/ControllerInterface.h"
|
||||||
|
|
||||||
|
@ -74,7 +73,7 @@ bool MappingButton::IsInput() const
|
||||||
}
|
}
|
||||||
|
|
||||||
MappingButton::MappingButton(MappingWidget* parent, ControlReference* ref, bool indicator)
|
MappingButton::MappingButton(MappingWidget* parent, ControlReference* ref, bool indicator)
|
||||||
: ElidedButton(RefToDisplayString(ref)), m_parent(parent), m_reference(ref)
|
: ElidedButton(RefToDisplayString(ref)), m_mapping_window(parent->GetParent()), m_reference(ref)
|
||||||
{
|
{
|
||||||
if (IsInput())
|
if (IsInput())
|
||||||
{
|
{
|
||||||
|
@ -92,17 +91,22 @@ MappingButton::MappingButton(MappingWidget* parent, ControlReference* ref, bool
|
||||||
connect(parent, &MappingWidget::Update, this, &MappingButton::UpdateIndicator);
|
connect(parent, &MappingWidget::Update, this, &MappingButton::UpdateIndicator);
|
||||||
|
|
||||||
connect(parent, &MappingWidget::ConfigChanged, this, &MappingButton::ConfigChanged);
|
connect(parent, &MappingWidget::ConfigChanged, this, &MappingButton::ConfigChanged);
|
||||||
|
connect(this, &MappingButton::ConfigChanged, [this] {
|
||||||
|
setText(RefToDisplayString(m_reference));
|
||||||
|
m_is_mapping = false;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void MappingButton::AdvancedPressed()
|
void MappingButton::AdvancedPressed()
|
||||||
{
|
{
|
||||||
IOWindow io(m_parent, m_parent->GetController(), m_reference,
|
m_mapping_window->CancelMapping();
|
||||||
|
|
||||||
|
IOWindow io(m_mapping_window, m_mapping_window->GetController(), m_reference,
|
||||||
m_reference->IsInput() ? IOWindow::Type::Input : IOWindow::Type::Output);
|
m_reference->IsInput() ? IOWindow::Type::Input : IOWindow::Type::Output);
|
||||||
SetQWidgetWindowDecorations(&io);
|
|
||||||
io.exec();
|
io.exec();
|
||||||
|
|
||||||
ConfigChanged();
|
ConfigChanged();
|
||||||
m_parent->SaveSettings();
|
m_mapping_window->Save();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MappingButton::Clicked()
|
void MappingButton::Clicked()
|
||||||
|
@ -113,31 +117,8 @@ void MappingButton::Clicked()
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const auto default_device_qualifier = m_parent->GetController()->GetDefaultDevice();
|
m_is_mapping = true;
|
||||||
|
m_mapping_window->QueueInputDetection(this);
|
||||||
QString expression;
|
|
||||||
|
|
||||||
if (m_parent->GetParent()->IsMappingAllDevices())
|
|
||||||
{
|
|
||||||
expression = MappingCommon::DetectExpression(this, g_controller_interface,
|
|
||||||
g_controller_interface.GetAllDeviceStrings(),
|
|
||||||
default_device_qualifier);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
expression = MappingCommon::DetectExpression(this, g_controller_interface,
|
|
||||||
{default_device_qualifier.ToString()},
|
|
||||||
default_device_qualifier);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (expression.isEmpty())
|
|
||||||
return;
|
|
||||||
|
|
||||||
m_reference->SetExpression(expression.toStdString());
|
|
||||||
m_parent->GetController()->UpdateSingleControlReference(g_controller_interface, m_reference);
|
|
||||||
|
|
||||||
ConfigChanged();
|
|
||||||
m_parent->SaveSettings();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MappingButton::Clear()
|
void MappingButton::Clear()
|
||||||
|
@ -145,22 +126,21 @@ void MappingButton::Clear()
|
||||||
m_reference->range = 100.0 / SLIDER_TICK_COUNT;
|
m_reference->range = 100.0 / SLIDER_TICK_COUNT;
|
||||||
|
|
||||||
m_reference->SetExpression("");
|
m_reference->SetExpression("");
|
||||||
m_parent->GetController()->UpdateSingleControlReference(g_controller_interface, m_reference);
|
m_mapping_window->GetController()->UpdateSingleControlReference(g_controller_interface,
|
||||||
|
m_reference);
|
||||||
|
|
||||||
m_parent->SaveSettings();
|
m_mapping_window->Save();
|
||||||
ConfigChanged();
|
|
||||||
|
m_mapping_window->UnQueueInputDetection(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MappingButton::UpdateIndicator()
|
void MappingButton::UpdateIndicator()
|
||||||
{
|
{
|
||||||
if (!isActiveWindow())
|
QFont f = m_mapping_window->font();
|
||||||
return;
|
|
||||||
|
|
||||||
QFont f = m_parent->font();
|
if (isActiveWindow() && m_reference->IsInput() && m_reference->GetState<bool>() && !m_is_mapping)
|
||||||
|
|
||||||
// If the input state is "true" (we can't know the state of outputs), show it in bold.
|
|
||||||
if (m_reference->IsInput() && m_reference->GetState<bool>())
|
|
||||||
f.setBold(true);
|
f.setBold(true);
|
||||||
|
|
||||||
// If the expression has failed to parse, show it in italic.
|
// If the expression has failed to parse, show it in italic.
|
||||||
// Some expressions still work even the failed to parse so don't prevent the GetState() above.
|
// Some expressions still work even the failed to parse so don't prevent the GetState() above.
|
||||||
if (m_reference->GetParseStatus() == ciface::ExpressionParser::ParseStatus::SyntaxError)
|
if (m_reference->GetParseStatus() == ciface::ExpressionParser::ParseStatus::SyntaxError)
|
||||||
|
@ -169,9 +149,12 @@ void MappingButton::UpdateIndicator()
|
||||||
setFont(f);
|
setFont(f);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MappingButton::ConfigChanged()
|
void MappingButton::StartMapping()
|
||||||
{
|
{
|
||||||
setText(RefToDisplayString(m_reference));
|
// Focus just makes it more clear which button is currently being mapped.
|
||||||
|
setFocus();
|
||||||
|
setText(tr("[ Press Now ]"));
|
||||||
|
QtUtils::InstallKeyboardBlocker(this, this, &MappingButton::ConfigChanged);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MappingButton::mouseReleaseEvent(QMouseEvent* event)
|
void MappingButton::mouseReleaseEvent(QMouseEvent* event)
|
||||||
|
@ -189,3 +172,8 @@ void MappingButton::mouseReleaseEvent(QMouseEvent* event)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ControlReference* MappingButton::GetControlReference()
|
||||||
|
{
|
||||||
|
return m_reference;
|
||||||
|
}
|
||||||
|
|
|
@ -3,11 +3,11 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "Common/Flag.h"
|
|
||||||
#include "DolphinQt/QtUtils/ElidedButton.h"
|
#include "DolphinQt/QtUtils/ElidedButton.h"
|
||||||
|
|
||||||
class ControlReference;
|
class ControlReference;
|
||||||
class MappingWidget;
|
class MappingWidget;
|
||||||
|
class MappingWindow;
|
||||||
class QEvent;
|
class QEvent;
|
||||||
class QMouseEvent;
|
class QMouseEvent;
|
||||||
|
|
||||||
|
@ -18,16 +18,21 @@ public:
|
||||||
MappingButton(MappingWidget* widget, ControlReference* ref, bool indicator);
|
MappingButton(MappingWidget* widget, ControlReference* ref, bool indicator);
|
||||||
|
|
||||||
bool IsInput() const;
|
bool IsInput() const;
|
||||||
|
ControlReference* GetControlReference();
|
||||||
|
void StartMapping();
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void ConfigChanged();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void Clear();
|
void Clear();
|
||||||
void UpdateIndicator();
|
void UpdateIndicator();
|
||||||
void ConfigChanged();
|
|
||||||
void AdvancedPressed();
|
void AdvancedPressed();
|
||||||
|
|
||||||
void Clicked();
|
void Clicked();
|
||||||
void mouseReleaseEvent(QMouseEvent* event) override;
|
void mouseReleaseEvent(QMouseEvent* event) override;
|
||||||
|
|
||||||
MappingWidget* m_parent;
|
MappingWindow* const m_mapping_window;
|
||||||
ControlReference* m_reference;
|
ControlReference* const m_reference;
|
||||||
|
bool m_is_mapping = false;
|
||||||
};
|
};
|
||||||
|
|
|
@ -3,19 +3,18 @@
|
||||||
|
|
||||||
#include "DolphinQt/Config/Mapping/MappingCommon.h"
|
#include "DolphinQt/Config/Mapping/MappingCommon.h"
|
||||||
|
|
||||||
#include <chrono>
|
#include <deque>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
#include <QApplication>
|
|
||||||
#include <QPushButton>
|
|
||||||
#include <QRegularExpression>
|
|
||||||
#include <QString>
|
|
||||||
#include <QTimer>
|
#include <QTimer>
|
||||||
|
|
||||||
#include "DolphinQt/QtUtils/BlockUserInputFilter.h"
|
#include "DolphinQt/Config/Mapping/MappingButton.h"
|
||||||
#include "InputCommon/ControlReference/ControlReference.h"
|
#include "DolphinQt/Config/Mapping/MappingWindow.h"
|
||||||
#include "InputCommon/ControllerInterface/MappingCommon.h"
|
|
||||||
|
|
||||||
#include "Common/Thread.h"
|
#include "InputCommon/ControlReference/ControlReference.h"
|
||||||
|
#include "InputCommon/ControllerEmu/ControllerEmu.h"
|
||||||
|
#include "InputCommon/ControllerInterface/ControllerInterface.h"
|
||||||
|
#include "InputCommon/ControllerInterface/MappingCommon.h"
|
||||||
|
|
||||||
namespace MappingCommon
|
namespace MappingCommon
|
||||||
{
|
{
|
||||||
|
@ -23,65 +22,128 @@ constexpr auto INPUT_DETECT_INITIAL_TIME = std::chrono::seconds(3);
|
||||||
constexpr auto INPUT_DETECT_CONFIRMATION_TIME = std::chrono::milliseconds(0);
|
constexpr auto INPUT_DETECT_CONFIRMATION_TIME = std::chrono::milliseconds(0);
|
||||||
constexpr auto INPUT_DETECT_MAXIMUM_TIME = std::chrono::seconds(5);
|
constexpr auto INPUT_DETECT_MAXIMUM_TIME = std::chrono::seconds(5);
|
||||||
|
|
||||||
constexpr auto OUTPUT_TEST_TIME = std::chrono::seconds(2);
|
class MappingProcessor : public QWidget
|
||||||
|
|
||||||
QString DetectExpression(QPushButton* button, ciface::Core::DeviceContainer& device_container,
|
|
||||||
const std::vector<std::string>& device_strings,
|
|
||||||
const ciface::Core::DeviceQualifier& default_device,
|
|
||||||
ciface::MappingCommon::Quote quote)
|
|
||||||
{
|
{
|
||||||
const auto filter = new BlockUserInputFilter(button);
|
public:
|
||||||
|
MappingProcessor(MappingWindow* parent) : QWidget{parent}, m_parent{parent}
|
||||||
|
{
|
||||||
|
using MW = MappingWindow;
|
||||||
|
using MP = MappingProcessor;
|
||||||
|
|
||||||
button->installEventFilter(filter);
|
connect(parent, &MW::Update, this, &MP::ProcessMappingButtons);
|
||||||
button->grabKeyboard();
|
connect(parent, &MW::ConfigChanged, this, &MP::CancelMapping);
|
||||||
button->grabMouse();
|
|
||||||
|
|
||||||
const auto old_text = button->text();
|
connect(parent, &MW::UnQueueInputDetection, this, &MP::UnQueueInputDetection);
|
||||||
button->setText(QStringLiteral("..."));
|
connect(parent, &MW::QueueInputDetection, this, &MP::QueueInputDetection);
|
||||||
|
connect(parent, &MW::CancelMapping, this, &MP::CancelMapping);
|
||||||
|
|
||||||
// The button text won't be updated if we don't process events here
|
m_input_detection_start_timer = new QTimer(this);
|
||||||
QApplication::processEvents();
|
m_input_detection_start_timer->setSingleShot(true);
|
||||||
|
connect(m_input_detection_start_timer, &QTimer::timeout, this, &MP::StartInputDetection);
|
||||||
// Avoid that the button press itself is registered as an event
|
|
||||||
Common::SleepCurrentThread(50);
|
|
||||||
|
|
||||||
auto detections =
|
|
||||||
device_container.DetectInput(device_strings, INPUT_DETECT_INITIAL_TIME,
|
|
||||||
INPUT_DETECT_CONFIRMATION_TIME, INPUT_DETECT_MAXIMUM_TIME);
|
|
||||||
|
|
||||||
ciface::MappingCommon::RemoveSpuriousTriggerCombinations(&detections);
|
|
||||||
|
|
||||||
const auto timer = new QTimer(button);
|
|
||||||
|
|
||||||
timer->setSingleShot(true);
|
|
||||||
|
|
||||||
button->connect(timer, &QTimer::timeout, [button, filter] {
|
|
||||||
button->releaseMouse();
|
|
||||||
button->releaseKeyboard();
|
|
||||||
button->removeEventFilter(filter);
|
|
||||||
});
|
|
||||||
|
|
||||||
// Prevent mappings of "space", "return", or mouse clicks from re-activating detection.
|
|
||||||
timer->start(500);
|
|
||||||
|
|
||||||
button->setText(old_text);
|
|
||||||
|
|
||||||
return QString::fromStdString(BuildExpression(detections, default_device, quote));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void TestOutput(QPushButton* button, OutputReference* reference)
|
void StartInputDetection()
|
||||||
{
|
{
|
||||||
const auto old_text = button->text();
|
const auto& default_device = m_parent->GetController()->GetDefaultDevice();
|
||||||
button->setText(QStringLiteral("..."));
|
auto& button = m_clicked_mapping_buttons.front();
|
||||||
|
|
||||||
// The button text won't be updated if we don't process events here
|
button->StartMapping();
|
||||||
QApplication::processEvents();
|
|
||||||
|
|
||||||
reference->State(1.0);
|
std::vector device_strings{default_device.ToString()};
|
||||||
std::this_thread::sleep_for(OUTPUT_TEST_TIME);
|
if (m_parent->IsMappingAllDevices())
|
||||||
reference->State(0.0);
|
device_strings = g_controller_interface.GetAllDeviceStrings();
|
||||||
|
|
||||||
button->setText(old_text);
|
m_input_detector = std::make_unique<ciface::Core::InputDetector>();
|
||||||
|
const auto lock = m_parent->GetController()->GetStateLock();
|
||||||
|
m_input_detector->Start(g_controller_interface, device_strings);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ProcessMappingButtons()
|
||||||
|
{
|
||||||
|
if (!m_input_detector)
|
||||||
|
return;
|
||||||
|
|
||||||
|
m_input_detector->Update(INPUT_DETECT_INITIAL_TIME, INPUT_DETECT_CONFIRMATION_TIME,
|
||||||
|
INPUT_DETECT_MAXIMUM_TIME);
|
||||||
|
|
||||||
|
if (m_input_detector->IsComplete())
|
||||||
|
{
|
||||||
|
auto detections = m_input_detector->TakeResults();
|
||||||
|
ciface::MappingCommon::RemoveSpuriousTriggerCombinations(&detections);
|
||||||
|
|
||||||
|
// No inputs detected. Cancel this and any other queued mappings.
|
||||||
|
if (detections.empty())
|
||||||
|
{
|
||||||
|
CancelMapping();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto& default_device = m_parent->GetController()->GetDefaultDevice();
|
||||||
|
auto& button = m_clicked_mapping_buttons.front();
|
||||||
|
auto* const control_reference = button->GetControlReference();
|
||||||
|
|
||||||
|
control_reference->SetExpression(
|
||||||
|
BuildExpression(detections, default_device, ciface::MappingCommon::Quote::On));
|
||||||
|
m_parent->Save();
|
||||||
|
|
||||||
|
m_parent->GetController()->UpdateSingleControlReference(g_controller_interface,
|
||||||
|
control_reference);
|
||||||
|
UnQueueInputDetection(button);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void UpdateInputDetectionStartTimer()
|
||||||
|
{
|
||||||
|
m_input_detector.reset();
|
||||||
|
|
||||||
|
if (m_clicked_mapping_buttons.empty())
|
||||||
|
m_input_detection_start_timer->stop();
|
||||||
|
else
|
||||||
|
m_input_detection_start_timer->start(INPUT_DETECT_INITIAL_DELAY);
|
||||||
|
}
|
||||||
|
|
||||||
|
void UnQueueInputDetection(MappingButton* button)
|
||||||
|
{
|
||||||
|
std::erase(m_clicked_mapping_buttons, button);
|
||||||
|
button->ConfigChanged();
|
||||||
|
UpdateInputDetectionStartTimer();
|
||||||
|
}
|
||||||
|
|
||||||
|
void QueueInputDetection(MappingButton* button)
|
||||||
|
{
|
||||||
|
// UnQueue if already queued.
|
||||||
|
if (std::erase(m_clicked_mapping_buttons, button))
|
||||||
|
{
|
||||||
|
button->ConfigChanged();
|
||||||
|
UpdateInputDetectionStartTimer();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
button->setText(QStringLiteral("[ ... ]"));
|
||||||
|
m_clicked_mapping_buttons.push_back(button);
|
||||||
|
UpdateInputDetectionStartTimer();
|
||||||
|
}
|
||||||
|
|
||||||
|
void CancelMapping()
|
||||||
|
{
|
||||||
|
// Signal buttons to take on their proper input expression text.
|
||||||
|
for (auto* button : m_clicked_mapping_buttons)
|
||||||
|
button->ConfigChanged();
|
||||||
|
|
||||||
|
m_clicked_mapping_buttons = {};
|
||||||
|
UpdateInputDetectionStartTimer();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::deque<MappingButton*> m_clicked_mapping_buttons;
|
||||||
|
std::unique_ptr<ciface::Core::InputDetector> m_input_detector;
|
||||||
|
QTimer* m_input_detection_start_timer;
|
||||||
|
MappingWindow* const m_parent;
|
||||||
|
};
|
||||||
|
|
||||||
|
void CreateMappingProcessor(MappingWindow* window)
|
||||||
|
{
|
||||||
|
new MappingProcessor{window};
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace MappingCommon
|
} // namespace MappingCommon
|
||||||
|
|
|
@ -3,23 +3,14 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <string>
|
#include <chrono>
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
#include "InputCommon/ControllerInterface/CoreDevice.h"
|
class MappingWindow;
|
||||||
#include "InputCommon/ControllerInterface/MappingCommon.h"
|
|
||||||
|
|
||||||
class QString;
|
|
||||||
class OutputReference;
|
|
||||||
class QPushButton;
|
|
||||||
|
|
||||||
namespace MappingCommon
|
namespace MappingCommon
|
||||||
{
|
{
|
||||||
QString DetectExpression(QPushButton* button, ciface::Core::DeviceContainer& device_container,
|
// A slight delay improves behavior when "clicking" the detect button via key-press.
|
||||||
const std::vector<std::string>& device_strings,
|
static constexpr auto INPUT_DETECT_INITIAL_DELAY = std::chrono::milliseconds{100};
|
||||||
const ciface::Core::DeviceQualifier& default_device,
|
|
||||||
ciface::MappingCommon::Quote quote = ciface::MappingCommon::Quote::On);
|
|
||||||
|
|
||||||
void TestOutput(QPushButton* button, OutputReference* reference);
|
|
||||||
|
|
||||||
|
void CreateMappingProcessor(MappingWindow*);
|
||||||
} // namespace MappingCommon
|
} // namespace MappingCommon
|
||||||
|
|
|
@ -20,7 +20,6 @@
|
||||||
#include "DolphinQt/Config/Mapping/MappingWindow.h"
|
#include "DolphinQt/Config/Mapping/MappingWindow.h"
|
||||||
#include "DolphinQt/QtUtils/SetWindowDecorations.h"
|
#include "DolphinQt/QtUtils/SetWindowDecorations.h"
|
||||||
|
|
||||||
#include "InputCommon/ControlReference/ControlReference.h"
|
|
||||||
#include "InputCommon/ControllerEmu/Control/Control.h"
|
#include "InputCommon/ControllerEmu/Control/Control.h"
|
||||||
#include "InputCommon/ControllerEmu/ControlGroup/ControlGroup.h"
|
#include "InputCommon/ControllerEmu/ControlGroup/ControlGroup.h"
|
||||||
#include "InputCommon/ControllerEmu/ControlGroup/MixedTriggers.h"
|
#include "InputCommon/ControllerEmu/ControlGroup/MixedTriggers.h"
|
||||||
|
@ -340,10 +339,10 @@ MappingWidget::CreateSettingAdvancedMappingButton(ControllerEmu::NumericSettingB
|
||||||
setting.SetExpressionFromValue();
|
setting.SetExpressionFromValue();
|
||||||
|
|
||||||
// Ensure the UI has the game-controller indicator while editing the expression.
|
// Ensure the UI has the game-controller indicator while editing the expression.
|
||||||
|
// And cancel in-progress mappings.
|
||||||
ConfigChanged();
|
ConfigChanged();
|
||||||
|
|
||||||
IOWindow io(this, GetController(), &setting.GetInputReference(), IOWindow::Type::Input);
|
IOWindow io(GetParent(), GetController(), &setting.GetInputReference(), IOWindow::Type::Input);
|
||||||
SetQWidgetWindowDecorations(&io);
|
|
||||||
io.exec();
|
io.exec();
|
||||||
|
|
||||||
setting.SimplifyIfPossible();
|
setting.SimplifyIfPossible();
|
||||||
|
|
|
@ -3,15 +3,10 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <memory>
|
|
||||||
#include <vector>
|
|
||||||
|
|
||||||
#include <QString>
|
#include <QString>
|
||||||
#include <QWidget>
|
#include <QWidget>
|
||||||
|
|
||||||
class ControlGroupBox;
|
|
||||||
class InputConfig;
|
class InputConfig;
|
||||||
class MappingButton;
|
|
||||||
class MappingNumeric;
|
class MappingNumeric;
|
||||||
class MappingWindow;
|
class MappingWindow;
|
||||||
class QFormLayout;
|
class QFormLayout;
|
||||||
|
|
|
@ -41,6 +41,7 @@
|
||||||
#include "DolphinQt/Config/Mapping/HotkeyTAS.h"
|
#include "DolphinQt/Config/Mapping/HotkeyTAS.h"
|
||||||
#include "DolphinQt/Config/Mapping/HotkeyUSBEmu.h"
|
#include "DolphinQt/Config/Mapping/HotkeyUSBEmu.h"
|
||||||
#include "DolphinQt/Config/Mapping/HotkeyWii.h"
|
#include "DolphinQt/Config/Mapping/HotkeyWii.h"
|
||||||
|
#include "DolphinQt/Config/Mapping/MappingCommon.h"
|
||||||
#include "DolphinQt/Config/Mapping/WiimoteEmuExtension.h"
|
#include "DolphinQt/Config/Mapping/WiimoteEmuExtension.h"
|
||||||
#include "DolphinQt/Config/Mapping/WiimoteEmuExtensionMotionInput.h"
|
#include "DolphinQt/Config/Mapping/WiimoteEmuExtensionMotionInput.h"
|
||||||
#include "DolphinQt/Config/Mapping/WiimoteEmuExtensionMotionSimulation.h"
|
#include "DolphinQt/Config/Mapping/WiimoteEmuExtensionMotionSimulation.h"
|
||||||
|
@ -93,6 +94,8 @@ MappingWindow::MappingWindow(QWidget* parent, Type type, int port_num)
|
||||||
[] { HotkeyManagerEmu::Enable(true); });
|
[] { HotkeyManagerEmu::Enable(true); });
|
||||||
filter->connect(filter, &WindowActivationEventFilter::windowActivated,
|
filter->connect(filter, &WindowActivationEventFilter::windowActivated,
|
||||||
[] { HotkeyManagerEmu::Enable(false); });
|
[] { HotkeyManagerEmu::Enable(false); });
|
||||||
|
|
||||||
|
MappingCommon::CreateMappingProcessor(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MappingWindow::CreateDevicesLayout()
|
void MappingWindow::CreateDevicesLayout()
|
||||||
|
@ -185,9 +188,8 @@ void MappingWindow::CreateMainLayout()
|
||||||
|
|
||||||
void MappingWindow::ConnectWidgets()
|
void MappingWindow::ConnectWidgets()
|
||||||
{
|
{
|
||||||
connect(&Settings::Instance(), &Settings::DevicesChanged, this,
|
connect(&Settings::Instance(), &Settings::DevicesChanged, this, &MappingWindow::ConfigChanged);
|
||||||
&MappingWindow::OnGlobalDevicesChanged);
|
connect(this, &MappingWindow::ConfigChanged, this, &MappingWindow::UpdateDeviceList);
|
||||||
connect(this, &MappingWindow::ConfigChanged, this, &MappingWindow::OnGlobalDevicesChanged);
|
|
||||||
connect(m_devices_combo, &QComboBox::currentIndexChanged, this, &MappingWindow::OnSelectDevice);
|
connect(m_devices_combo, &QComboBox::currentIndexChanged, this, &MappingWindow::OnSelectDevice);
|
||||||
|
|
||||||
connect(m_reset_clear, &QPushButton::clicked, this, &MappingWindow::OnClearFieldsPressed);
|
connect(m_reset_clear, &QPushButton::clicked, this, &MappingWindow::OnClearFieldsPressed);
|
||||||
|
@ -203,6 +205,8 @@ void MappingWindow::ConnectWidgets()
|
||||||
// We currently use the "Close" button as an "Accept" button so we must save on reject.
|
// We currently use the "Close" button as an "Accept" button so we must save on reject.
|
||||||
connect(this, &QDialog::rejected, [this] { emit Save(); });
|
connect(this, &QDialog::rejected, [this] { emit Save(); });
|
||||||
connect(m_button_box, &QDialogButtonBox::rejected, this, &QDialog::reject);
|
connect(m_button_box, &QDialogButtonBox::rejected, this, &QDialog::reject);
|
||||||
|
|
||||||
|
connect(m_tab_widget, &QTabWidget::currentChanged, this, &MappingWindow::CancelMapping);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MappingWindow::UpdateProfileIndex()
|
void MappingWindow::UpdateProfileIndex()
|
||||||
|
@ -345,6 +349,8 @@ void MappingWindow::OnSelectDevice(int)
|
||||||
const auto device = m_devices_combo->currentData().toString().toStdString();
|
const auto device = m_devices_combo->currentData().toString().toStdString();
|
||||||
|
|
||||||
m_controller->SetDefaultDevice(device);
|
m_controller->SetDefaultDevice(device);
|
||||||
|
|
||||||
|
emit ConfigChanged();
|
||||||
m_controller->UpdateReferences(g_controller_interface);
|
m_controller->UpdateReferences(g_controller_interface);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -358,7 +364,7 @@ void MappingWindow::RefreshDevices()
|
||||||
g_controller_interface.RefreshDevices();
|
g_controller_interface.RefreshDevices();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MappingWindow::OnGlobalDevicesChanged()
|
void MappingWindow::UpdateDeviceList()
|
||||||
{
|
{
|
||||||
const QSignalBlocker blocker(m_devices_combo);
|
const QSignalBlocker blocker(m_devices_combo);
|
||||||
|
|
||||||
|
|
|
@ -5,9 +5,6 @@
|
||||||
|
|
||||||
#include <QDialog>
|
#include <QDialog>
|
||||||
#include <QString>
|
#include <QString>
|
||||||
#include <memory>
|
|
||||||
|
|
||||||
#include "InputCommon/ControllerInterface/CoreDevice.h"
|
|
||||||
|
|
||||||
namespace ControllerEmu
|
namespace ControllerEmu
|
||||||
{
|
{
|
||||||
|
@ -15,6 +12,8 @@ class EmulatedController;
|
||||||
}
|
}
|
||||||
|
|
||||||
class InputConfig;
|
class InputConfig;
|
||||||
|
class MappingButton;
|
||||||
|
|
||||||
class QComboBox;
|
class QComboBox;
|
||||||
class QDialogButtonBox;
|
class QDialogButtonBox;
|
||||||
class QEvent;
|
class QEvent;
|
||||||
|
@ -58,10 +57,14 @@ public:
|
||||||
signals:
|
signals:
|
||||||
// Emitted when config has changed so widgets can update to reflect the change.
|
// Emitted when config has changed so widgets can update to reflect the change.
|
||||||
void ConfigChanged();
|
void ConfigChanged();
|
||||||
// Emitted at 30hz for real-time indicators to be updated.
|
// Emitted at INDICATOR_UPDATE_FREQ Hz for real-time indicators to be updated.
|
||||||
void Update();
|
void Update();
|
||||||
void Save();
|
void Save();
|
||||||
|
|
||||||
|
void UnQueueInputDetection(MappingButton*);
|
||||||
|
void QueueInputDetection(MappingButton*);
|
||||||
|
void CancelMapping();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void SetMappingType(Type type);
|
void SetMappingType(Type type);
|
||||||
void CreateDevicesLayout();
|
void CreateDevicesLayout();
|
||||||
|
@ -82,11 +85,11 @@ private:
|
||||||
void UpdateProfileIndex();
|
void UpdateProfileIndex();
|
||||||
void UpdateProfileButtonState();
|
void UpdateProfileButtonState();
|
||||||
void PopulateProfileSelection();
|
void PopulateProfileSelection();
|
||||||
|
void UpdateDeviceList();
|
||||||
|
|
||||||
void OnDefaultFieldsPressed();
|
void OnDefaultFieldsPressed();
|
||||||
void OnClearFieldsPressed();
|
void OnClearFieldsPressed();
|
||||||
void OnSelectDevice(int index);
|
void OnSelectDevice(int index);
|
||||||
void OnGlobalDevicesChanged();
|
|
||||||
|
|
||||||
ControllerEmu::EmulatedController* m_controller = nullptr;
|
ControllerEmu::EmulatedController* m_controller = nullptr;
|
||||||
|
|
||||||
|
|
|
@ -39,12 +39,6 @@
|
||||||
<string>English</string>
|
<string>English</string>
|
||||||
<key>CFBundlePackageType</key>
|
<key>CFBundlePackageType</key>
|
||||||
<string>APPL</string>
|
<string>APPL</string>
|
||||||
<key>CFBundleShortVersionString</key>
|
|
||||||
<string>${DOLPHIN_WC_DESCRIBE}</string>
|
|
||||||
<key>CFBundleLongVersionString</key>
|
|
||||||
<string>${DOLPHIN_WC_REVISION}</string>
|
|
||||||
<key>CFBundleVersion</key>
|
|
||||||
<string>${DOLPHIN_VERSION_MAJOR}.${DOLPHIN_VERSION_MINOR}</string>
|
|
||||||
<key>NSHumanReadableCopyright</key>
|
<key>NSHumanReadableCopyright</key>
|
||||||
<string>Licensed under GPL version 2 or later (GPLv2+)</string>
|
<string>Licensed under GPL version 2 or later (GPLv2+)</string>
|
||||||
<key>LSApplicationCategoryType</key>
|
<key>LSApplicationCategoryType</key>
|
||||||
|
|
|
@ -3,12 +3,34 @@
|
||||||
|
|
||||||
#include "DolphinQt/QtUtils/BlockUserInputFilter.h"
|
#include "DolphinQt/QtUtils/BlockUserInputFilter.h"
|
||||||
|
|
||||||
#include <QEvent>
|
#include <chrono>
|
||||||
|
|
||||||
bool BlockUserInputFilter::eventFilter(QObject* object, QEvent* event)
|
#include <QEvent>
|
||||||
|
#include <QTimer>
|
||||||
|
|
||||||
|
namespace QtUtils
|
||||||
{
|
{
|
||||||
const QEvent::Type event_type = event->type();
|
|
||||||
return event_type == QEvent::KeyPress || event_type == QEvent::KeyRelease ||
|
// Leave filter active for a bit to prevent Return/Space detection from reactivating the button.
|
||||||
event_type == QEvent::MouseButtonPress || event_type == QEvent::MouseButtonRelease ||
|
constexpr auto REMOVAL_DELAY = std::chrono::milliseconds{100};
|
||||||
event_type == QEvent::MouseButtonDblClick;
|
|
||||||
|
BlockKeyboardInputFilter::BlockKeyboardInputFilter(QObject* parent) : QObject{parent}
|
||||||
|
{
|
||||||
|
parent->installEventFilter(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void BlockKeyboardInputFilter::ScheduleRemoval()
|
||||||
|
{
|
||||||
|
auto* const timer = new QTimer(this);
|
||||||
|
timer->setSingleShot(true);
|
||||||
|
connect(timer, &QTimer::timeout, [this] { delete this; });
|
||||||
|
timer->start(REMOVAL_DELAY);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool BlockKeyboardInputFilter::eventFilter(QObject* object, QEvent* event)
|
||||||
|
{
|
||||||
|
const auto event_type = event->type();
|
||||||
|
return event_type == QEvent::KeyPress || event_type == QEvent::KeyRelease;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace QtUtils
|
||||||
|
|
|
@ -5,14 +5,26 @@
|
||||||
|
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
|
|
||||||
class QEvent;
|
namespace QtUtils
|
||||||
|
{
|
||||||
|
|
||||||
class BlockUserInputFilter : public QObject
|
class BlockKeyboardInputFilter : public QObject
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
using QObject::QObject;
|
BlockKeyboardInputFilter(QObject* parent);
|
||||||
|
void ScheduleRemoval();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool eventFilter(QObject* object, QEvent* event) override;
|
bool eventFilter(QObject* object, QEvent* event) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void InstallKeyboardBlocker(QObject* obj, T* removal_signal_object, void (T::*removal_signal)())
|
||||||
|
{
|
||||||
|
removal_signal_object->connect(removal_signal_object, removal_signal,
|
||||||
|
new QtUtils::BlockKeyboardInputFilter{obj},
|
||||||
|
&QtUtils::BlockKeyboardInputFilter::ScheduleRemoval);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace QtUtils
|
||||||
|
|
|
@ -345,6 +345,20 @@ auto DeviceContainer::DetectInput(const std::vector<std::string>& device_strings
|
||||||
std::chrono::milliseconds confirmation_wait,
|
std::chrono::milliseconds confirmation_wait,
|
||||||
std::chrono::milliseconds maximum_wait) const
|
std::chrono::milliseconds maximum_wait) const
|
||||||
-> std::vector<InputDetection>
|
-> std::vector<InputDetection>
|
||||||
|
{
|
||||||
|
InputDetector input_detector;
|
||||||
|
input_detector.Start(*this, device_strings);
|
||||||
|
|
||||||
|
while (!input_detector.IsComplete())
|
||||||
|
{
|
||||||
|
Common::SleepCurrentThread(10);
|
||||||
|
input_detector.Update(initial_wait, confirmation_wait, maximum_wait);
|
||||||
|
}
|
||||||
|
|
||||||
|
return input_detector.TakeResults();
|
||||||
|
}
|
||||||
|
|
||||||
|
struct InputDetector::Impl
|
||||||
{
|
{
|
||||||
struct InputState
|
struct InputState
|
||||||
{
|
{
|
||||||
|
@ -355,7 +369,7 @@ auto DeviceContainer::DetectInput(const std::vector<std::string>& device_strings
|
||||||
ControlState last_state = initial_state;
|
ControlState last_state = initial_state;
|
||||||
MathUtil::RunningVariance<ControlState> stats;
|
MathUtil::RunningVariance<ControlState> stats;
|
||||||
|
|
||||||
// Prevent multiiple detections until after release.
|
// Prevent multiple detections until after release.
|
||||||
bool is_ready = true;
|
bool is_ready = true;
|
||||||
|
|
||||||
void Update()
|
void Update()
|
||||||
|
@ -392,18 +406,32 @@ auto DeviceContainer::DetectInput(const std::vector<std::string>& device_strings
|
||||||
std::vector<InputState> input_states;
|
std::vector<InputState> input_states;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Acquire devices and initial input states.
|
|
||||||
std::vector<DeviceState> device_states;
|
std::vector<DeviceState> device_states;
|
||||||
|
};
|
||||||
|
|
||||||
|
InputDetector::InputDetector() : m_start_time{}, m_state{}
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void InputDetector::Start(const DeviceContainer& container,
|
||||||
|
const std::vector<std::string>& device_strings)
|
||||||
|
|
||||||
|
{
|
||||||
|
m_start_time = Clock::now();
|
||||||
|
m_detections = {};
|
||||||
|
m_state = std::make_unique<Impl>();
|
||||||
|
|
||||||
|
// Acquire devices and initial input states.
|
||||||
for (const auto& device_string : device_strings)
|
for (const auto& device_string : device_strings)
|
||||||
{
|
{
|
||||||
DeviceQualifier dq;
|
DeviceQualifier dq;
|
||||||
dq.FromString(device_string);
|
dq.FromString(device_string);
|
||||||
auto device = FindDevice(dq);
|
auto device = container.FindDevice(dq);
|
||||||
|
|
||||||
if (!device)
|
if (!device)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
std::vector<InputState> input_states;
|
std::vector<Impl::InputState> input_states;
|
||||||
|
|
||||||
for (auto* input : device->Inputs())
|
for (auto* input : device->Inputs())
|
||||||
{
|
{
|
||||||
|
@ -413,38 +441,42 @@ auto DeviceContainer::DetectInput(const std::vector<std::string>& device_strings
|
||||||
|
|
||||||
// Undesirable axes will have negative values here when trying to map a
|
// Undesirable axes will have negative values here when trying to map a
|
||||||
// "FullAnalogSurface".
|
// "FullAnalogSurface".
|
||||||
input_states.push_back(InputState{input});
|
input_states.push_back(Impl::InputState{input});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!input_states.empty())
|
if (!input_states.empty())
|
||||||
device_states.emplace_back(DeviceState{std::move(device), std::move(input_states)});
|
{
|
||||||
|
m_state->device_states.emplace_back(
|
||||||
|
Impl::DeviceState{std::move(device), std::move(input_states)});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (device_states.empty())
|
// If no inputs were found via the supplied device strings, immediately complete.
|
||||||
return {};
|
if (m_state->device_states.empty())
|
||||||
|
m_state.reset();
|
||||||
|
}
|
||||||
|
|
||||||
std::vector<InputDetection> detections;
|
void InputDetector::Update(std::chrono::milliseconds initial_wait,
|
||||||
|
std::chrono::milliseconds confirmation_wait,
|
||||||
const auto start_time = Clock::now();
|
std::chrono::milliseconds maximum_wait)
|
||||||
while (true)
|
{
|
||||||
|
if (m_state)
|
||||||
{
|
{
|
||||||
const auto now = Clock::now();
|
const auto now = Clock::now();
|
||||||
const auto elapsed_time = now - start_time;
|
const auto elapsed_time = now - m_start_time;
|
||||||
|
|
||||||
if (elapsed_time >= maximum_wait || (detections.empty() && elapsed_time >= initial_wait) ||
|
if (elapsed_time >= maximum_wait || (m_detections.empty() && elapsed_time >= initial_wait) ||
|
||||||
(!detections.empty() && detections.back().release_time.has_value() &&
|
(!m_detections.empty() && m_detections.back().release_time.has_value() &&
|
||||||
now >= *detections.back().release_time + confirmation_wait))
|
now >= *m_detections.back().release_time + confirmation_wait))
|
||||||
{
|
{
|
||||||
break;
|
m_state.reset();
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Common::SleepCurrentThread(10);
|
for (auto& device_state : m_state->device_states)
|
||||||
|
|
||||||
for (auto& device_state : device_states)
|
|
||||||
{
|
{
|
||||||
for (std::size_t i = 0; i != device_state.input_states.size(); ++i)
|
for (auto& input_state : device_state.input_states)
|
||||||
{
|
{
|
||||||
auto& input_state = device_state.input_states[i];
|
|
||||||
input_state.Update();
|
input_state.Update();
|
||||||
|
|
||||||
if (input_state.IsPressed())
|
if (input_state.IsPressed())
|
||||||
|
@ -456,26 +488,42 @@ auto DeviceContainer::DetectInput(const std::vector<std::string>& device_strings
|
||||||
const auto smoothness =
|
const auto smoothness =
|
||||||
1 / std::sqrt(input_state.stats.Variance() / input_state.stats.Mean());
|
1 / std::sqrt(input_state.stats.Variance() / input_state.stats.Mean());
|
||||||
|
|
||||||
InputDetection new_detection;
|
Detection new_detection;
|
||||||
new_detection.device = device_state.device;
|
new_detection.device = device_state.device;
|
||||||
new_detection.input = input_state.input;
|
new_detection.input = input_state.input;
|
||||||
new_detection.press_time = Clock::now();
|
new_detection.press_time = Clock::now();
|
||||||
new_detection.smoothness = smoothness;
|
new_detection.smoothness = smoothness;
|
||||||
|
|
||||||
// We found an input. Add it to our detections.
|
// We found an input. Add it to our detections.
|
||||||
detections.emplace_back(std::move(new_detection));
|
m_detections.emplace_back(std::move(new_detection));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check for any releases of our detected inputs.
|
// Check for any releases of our detected inputs.
|
||||||
for (auto& d : detections)
|
for (auto& d : m_detections)
|
||||||
{
|
{
|
||||||
if (!d.release_time.has_value() && d.input->GetState() < (1 - INPUT_DETECT_THRESHOLD))
|
if (!d.release_time.has_value() && d.input->GetState() < (1 - INPUT_DETECT_THRESHOLD))
|
||||||
d.release_time = Clock::now();
|
d.release_time = Clock::now();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return detections;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
InputDetector::~InputDetector() = default;
|
||||||
|
|
||||||
|
bool InputDetector::IsComplete() const
|
||||||
|
{
|
||||||
|
return !m_state;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto InputDetector::GetResults() const -> const std::vector<Detection>&
|
||||||
|
{
|
||||||
|
return m_detections;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto InputDetector::TakeResults() -> std::vector<Detection>
|
||||||
|
{
|
||||||
|
return std::move(m_detections);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace ciface::Core
|
} // namespace ciface::Core
|
||||||
|
|
|
@ -245,5 +245,32 @@ protected:
|
||||||
mutable std::recursive_mutex m_devices_mutex;
|
mutable std::recursive_mutex m_devices_mutex;
|
||||||
std::vector<std::shared_ptr<Device>> m_devices;
|
std::vector<std::shared_ptr<Device>> m_devices;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class InputDetector
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using Detection = DeviceContainer::InputDetection;
|
||||||
|
|
||||||
|
InputDetector();
|
||||||
|
~InputDetector();
|
||||||
|
|
||||||
|
void Start(const DeviceContainer& container, const std::vector<std::string>& device_strings);
|
||||||
|
void Update(std::chrono::milliseconds initial_wait, std::chrono::milliseconds confirmation_wait,
|
||||||
|
std::chrono::milliseconds maximum_wait);
|
||||||
|
bool IsComplete() const;
|
||||||
|
|
||||||
|
const std::vector<Detection>& GetResults() const;
|
||||||
|
|
||||||
|
// move-return'd to prevent copying.
|
||||||
|
std::vector<Detection> TakeResults();
|
||||||
|
|
||||||
|
private:
|
||||||
|
struct Impl;
|
||||||
|
|
||||||
|
Clock::time_point m_start_time;
|
||||||
|
std::vector<Detection> m_detections;
|
||||||
|
std::unique_ptr<Impl> m_state;
|
||||||
|
};
|
||||||
|
|
||||||
} // namespace Core
|
} // namespace Core
|
||||||
} // namespace ciface
|
} // namespace ciface
|
||||||
|
|
|
@ -16,7 +16,7 @@ add_dependencies(MacUpdater dolphin_scmrev)
|
||||||
|
|
||||||
set_target_properties(MacUpdater PROPERTIES
|
set_target_properties(MacUpdater PROPERTIES
|
||||||
MACOSX_BUNDLE true
|
MACOSX_BUNDLE true
|
||||||
MACOSX_BUNDLE_INFO_PLIST "${CMAKE_CURRENT_BINARY_DIR}/Info.plist"
|
MACOSX_BUNDLE_INFO_PLIST "${CMAKE_CURRENT_SOURCE_DIR}/Info.plist.in"
|
||||||
OUTPUT_NAME "Dolphin Updater")
|
OUTPUT_NAME "Dolphin Updater")
|
||||||
|
|
||||||
target_compile_options(MacUpdater PRIVATE -x objective-c++)
|
target_compile_options(MacUpdater PRIVATE -x objective-c++)
|
||||||
|
@ -53,6 +53,9 @@ foreach(sb ${STORYBOARDS})
|
||||||
COMMENT "Compiling Storyboard ${sb}...")
|
COMMENT "Compiling Storyboard ${sb}...")
|
||||||
endforeach()
|
endforeach()
|
||||||
|
|
||||||
|
include(DolphinInjectVersionInfo)
|
||||||
|
dolphin_inject_version_info(MacUpdater)
|
||||||
|
|
||||||
if(NOT SKIP_POSTPROCESS_BUNDLE)
|
if(NOT SKIP_POSTPROCESS_BUNDLE)
|
||||||
# Update library references to make the bundle portable
|
# Update library references to make the bundle portable
|
||||||
include(DolphinPostprocessBundle)
|
include(DolphinPostprocessBundle)
|
||||||
|
|
|
@ -16,10 +16,6 @@
|
||||||
<string>Dolphin Updater</string>
|
<string>Dolphin Updater</string>
|
||||||
<key>CFBundlePackageType</key>
|
<key>CFBundlePackageType</key>
|
||||||
<string>APPL</string>
|
<string>APPL</string>
|
||||||
<key>CFBundleShortVersionString</key>
|
|
||||||
<string>${DOLPHIN_WC_DESCRIBE}</string>
|
|
||||||
<key>CFBundleVersion</key>
|
|
||||||
<string>${DOLPHIN_VERSION_MAJOR}.${DOLPHIN_VERSION_MINOR}</string>
|
|
||||||
<key>LSMinimumSystemVersion</key>
|
<key>LSMinimumSystemVersion</key>
|
||||||
<string>${CMAKE_OSX_DEPLOYMENT_TARGET}</string>
|
<string>${CMAKE_OSX_DEPLOYMENT_TARGET}</string>
|
||||||
<key>NSHumanReadableCopyright</key>
|
<key>NSHumanReadableCopyright</key>
|
||||||
|
|
|
@ -0,0 +1,13 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
|
<plist version="1.0">
|
||||||
|
<dict>
|
||||||
|
<!-- This plist file is merged with the application's Info.plist to set its version info. -->
|
||||||
|
<key>CFBundleShortVersionString</key>
|
||||||
|
<string>${DOLPHIN_WC_DESCRIBE}</string>
|
||||||
|
<key>CFBundleLongVersionString</key>
|
||||||
|
<string>${DOLPHIN_WC_REVISION}</string>
|
||||||
|
<key>CFBundleVersion</key>
|
||||||
|
<string>${DOLPHIN_VERSION_MAJOR}.${DOLPHIN_VERSION_MINOR}</string>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
|
@ -259,6 +259,10 @@ void VideoBackend::Shutdown()
|
||||||
void VideoBackend::PrepareWindow(WindowSystemInfo& wsi)
|
void VideoBackend::PrepareWindow(WindowSystemInfo& wsi)
|
||||||
{
|
{
|
||||||
#if defined(VK_USE_PLATFORM_METAL_EXT)
|
#if defined(VK_USE_PLATFORM_METAL_EXT)
|
||||||
|
// We only need to manually create the CAMetalLayer on macOS.
|
||||||
|
if (wsi.type != WindowSystemType::MacOS)
|
||||||
|
return;
|
||||||
|
|
||||||
// This is kinda messy, but it avoids having to write Objective C++ just to create a metal layer.
|
// This is kinda messy, but it avoids having to write Objective C++ just to create a metal layer.
|
||||||
id view = reinterpret_cast<id>(wsi.render_surface);
|
id view = reinterpret_cast<id>(wsi.render_surface);
|
||||||
Class clsCAMetalLayer = objc_getClass("CAMetalLayer");
|
Class clsCAMetalLayer = objc_getClass("CAMetalLayer");
|
||||||
|
|
|
@ -77,11 +77,6 @@ std::pair<std::string, bool> GetNameArbPair(const TextureInfo& texture_info)
|
||||||
}
|
}
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
void HiresTexture::Init()
|
|
||||||
{
|
|
||||||
Update();
|
|
||||||
}
|
|
||||||
|
|
||||||
void HiresTexture::Shutdown()
|
void HiresTexture::Shutdown()
|
||||||
{
|
{
|
||||||
Clear();
|
Clear();
|
||||||
|
|
|
@ -22,7 +22,6 @@ std::set<std::string> GetTextureDirectoriesWithGameId(const std::string& root_di
|
||||||
class HiresTexture
|
class HiresTexture
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
static void Init();
|
|
||||||
static void Update();
|
static void Update();
|
||||||
static void Clear();
|
static void Clear();
|
||||||
static void Shutdown();
|
static void Shutdown();
|
||||||
|
|
|
@ -137,10 +137,8 @@ void PostProcessingConfiguration::LoadOptions(const std::string& code)
|
||||||
|
|
||||||
std::vector<GLSLStringOption> option_strings;
|
std::vector<GLSLStringOption> option_strings;
|
||||||
GLSLStringOption* current_strings = nullptr;
|
GLSLStringOption* current_strings = nullptr;
|
||||||
while (!in.eof())
|
|
||||||
{
|
|
||||||
std::string line_str;
|
std::string line_str;
|
||||||
if (std::getline(in, line_str))
|
while (std::getline(in, line_str))
|
||||||
{
|
{
|
||||||
std::string_view line = line_str;
|
std::string_view line = line_str;
|
||||||
|
|
||||||
|
@ -177,7 +175,6 @@ void PostProcessingConfiguration::LoadOptions(const std::string& code)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
for (const auto& it : option_strings)
|
for (const auto& it : option_strings)
|
||||||
{
|
{
|
||||||
|
|
|
@ -99,8 +99,6 @@ TextureCacheBase::TextureCacheBase()
|
||||||
TexDecoder_SetTexFmtOverlayOptions(m_backup_config.texfmt_overlay,
|
TexDecoder_SetTexFmtOverlayOptions(m_backup_config.texfmt_overlay,
|
||||||
m_backup_config.texfmt_overlay_center);
|
m_backup_config.texfmt_overlay_center);
|
||||||
|
|
||||||
HiresTexture::Init();
|
|
||||||
|
|
||||||
TMEM::InvalidateAll();
|
TMEM::InvalidateAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -24,7 +24,7 @@ protected:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetUp()
|
void SetUp() override
|
||||||
{
|
{
|
||||||
if (m_parent_directory.empty())
|
if (m_parent_directory.empty())
|
||||||
{
|
{
|
||||||
|
|
|
@ -44,7 +44,7 @@ TEST(TMDReader, Validity)
|
||||||
class TMDReaderTest : public ::testing::Test
|
class TMDReaderTest : public ::testing::Test
|
||||||
{
|
{
|
||||||
protected:
|
protected:
|
||||||
virtual void SetUp() = 0;
|
void SetUp() override = 0;
|
||||||
|
|
||||||
// Common tests.
|
// Common tests.
|
||||||
void TestGeneralInfo();
|
void TestGeneralInfo();
|
||||||
|
|
|
@ -41,7 +41,7 @@ protected:
|
||||||
m_fs.reset();
|
m_fs.reset();
|
||||||
File::DeleteDirRecursively(m_profile_path);
|
File::DeleteDirRecursively(m_profile_path);
|
||||||
}
|
}
|
||||||
void SetUp()
|
void SetUp() override
|
||||||
{
|
{
|
||||||
if (UserDirectoryCreationFailed())
|
if (UserDirectoryCreationFailed())
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in New Issue