diff options
39 files changed, 1385 insertions, 42 deletions
diff --git a/.gitmodules b/.gitmodules index 9ba8fe207..79028bbb5 100644 --- a/.gitmodules +++ b/.gitmodules | |||
| @@ -34,3 +34,9 @@ | |||
| 34 | [submodule "xbyak"] | 34 | [submodule "xbyak"] |
| 35 | path = externals/xbyak | 35 | path = externals/xbyak |
| 36 | url = https://github.com/herumi/xbyak.git | 36 | url = https://github.com/herumi/xbyak.git |
| 37 | [submodule "externals/libusb"] | ||
| 38 | path = externals/libusb | ||
| 39 | url = https://github.com/ameerj/libusb | ||
| 40 | [submodule "opus"] | ||
| 41 | path = externals/opus/opus | ||
| 42 | url = https://github.com/xiph/opus.git | ||
diff --git a/CMakeLists.txt b/CMakeLists.txt index 73405ce4b..27383bce8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt | |||
| @@ -156,8 +156,6 @@ macro(yuzu_find_packages) | |||
| 156 | #"libzip 1.5 libzip/1.5.2@bincrafters/stable" | 156 | #"libzip 1.5 libzip/1.5.2@bincrafters/stable" |
| 157 | "lz4 1.8 lz4/1.9.2" | 157 | "lz4 1.8 lz4/1.9.2" |
| 158 | "nlohmann_json 3.7 nlohmann_json/3.7.3" | 158 | "nlohmann_json 3.7 nlohmann_json/3.7.3" |
| 159 | # we need to be careful as the version check might be broken https://github.com/xiph/opus/issues/110 | ||
| 160 | "opus 1.3 opus/1.3.1" | ||
| 161 | "ZLIB 1.2 zlib/1.2.11" | 159 | "ZLIB 1.2 zlib/1.2.11" |
| 162 | "zstd 1.4 zstd/1.4.4" | 160 | "zstd 1.4 zstd/1.4.4" |
| 163 | ) | 161 | ) |
| @@ -331,6 +329,12 @@ elseif(SDL2_FOUND) | |||
| 331 | target_link_libraries(SDL2 INTERFACE "${SDL2_LIBRARIES}") | 329 | target_link_libraries(SDL2 INTERFACE "${SDL2_LIBRARIES}") |
| 332 | endif() | 330 | endif() |
| 333 | 331 | ||
| 332 | # Ensure libusb is properly configured (based on dolphin libusb include) | ||
| 333 | find_package(LibUSB) | ||
| 334 | add_subdirectory(externals/libusb) | ||
| 335 | set(LIBUSB_LIBRARIES usb) | ||
| 336 | |||
| 337 | |||
| 334 | # Prefer the -pthread flag on Linux. | 338 | # Prefer the -pthread flag on Linux. |
| 335 | set(THREADS_PREFER_PTHREAD_FLAG ON) | 339 | set(THREADS_PREFER_PTHREAD_FLAG ON) |
| 336 | find_package(Threads REQUIRED) | 340 | find_package(Threads REQUIRED) |
diff --git a/externals/CMakeLists.txt b/externals/CMakeLists.txt index b80b27605..d1dcc403b 100644 --- a/externals/CMakeLists.txt +++ b/externals/CMakeLists.txt | |||
| @@ -91,3 +91,6 @@ if (ENABLE_WEB_SERVICE) | |||
| 91 | target_compile_definitions(httplib INTERFACE -DCPPHTTPLIB_OPENSSL_SUPPORT) | 91 | target_compile_definitions(httplib INTERFACE -DCPPHTTPLIB_OPENSSL_SUPPORT) |
| 92 | target_link_libraries(httplib INTERFACE ${OPENSSL_LIBRARIES}) | 92 | target_link_libraries(httplib INTERFACE ${OPENSSL_LIBRARIES}) |
| 93 | endif() | 93 | endif() |
| 94 | |||
| 95 | # Opus | ||
| 96 | add_subdirectory(opus) | ||
diff --git a/externals/libusb b/externals/libusb new file mode 160000 | |||
| Subproject 3406d72cda879f8792a88bf5f6bd0b7a65636f7 | |||
diff --git a/externals/opus/CMakeLists.txt b/externals/opus/CMakeLists.txt new file mode 100644 index 000000000..94a86551f --- /dev/null +++ b/externals/opus/CMakeLists.txt | |||
| @@ -0,0 +1,254 @@ | |||
| 1 | cmake_minimum_required(VERSION 3.8) | ||
| 2 | |||
| 3 | project(opus) | ||
| 4 | |||
| 5 | option(OPUS_STACK_PROTECTOR "Use stack protection" OFF) | ||
| 6 | option(OPUS_USE_ALLOCA "Use alloca for stack arrays (on non-C99 compilers)" OFF) | ||
| 7 | option(OPUS_CUSTOM_MODES "Enable non-Opus modes, e.g. 44.1 kHz & 2^n frames" OFF) | ||
| 8 | option(OPUS_FIXED_POINT "Compile as fixed-point (for machines without a fast enough FPU)" OFF) | ||
| 9 | option(OPUS_ENABLE_FLOAT_API "Compile with the floating point API (for machines with float library" ON) | ||
| 10 | |||
| 11 | include(opus/opus_functions.cmake) | ||
| 12 | |||
| 13 | if(OPUS_STACK_PROTECTOR) | ||
| 14 | if(NOT MSVC) # GC on by default on MSVC | ||
| 15 | check_and_set_flag(STACK_PROTECTION_STRONG -fstack-protector-strong) | ||
| 16 | endif() | ||
| 17 | else() | ||
| 18 | if(MSVC) | ||
| 19 | check_and_set_flag(BUFFER_SECURITY_CHECK /GS-) | ||
| 20 | endif() | ||
| 21 | endif() | ||
| 22 | |||
| 23 | add_library(opus STATIC | ||
| 24 | # CELT sources | ||
| 25 | opus/celt/bands.c | ||
| 26 | opus/celt/celt.c | ||
| 27 | opus/celt/celt_decoder.c | ||
| 28 | opus/celt/celt_encoder.c | ||
| 29 | opus/celt/celt_lpc.c | ||
| 30 | opus/celt/cwrs.c | ||
| 31 | opus/celt/entcode.c | ||
| 32 | opus/celt/entdec.c | ||
| 33 | opus/celt/entenc.c | ||
| 34 | opus/celt/kiss_fft.c | ||
| 35 | opus/celt/laplace.c | ||
| 36 | opus/celt/mathops.c | ||
| 37 | opus/celt/mdct.c | ||
| 38 | opus/celt/modes.c | ||
| 39 | opus/celt/pitch.c | ||
| 40 | opus/celt/quant_bands.c | ||
| 41 | opus/celt/rate.c | ||
| 42 | opus/celt/vq.c | ||
| 43 | |||
| 44 | # SILK sources | ||
| 45 | opus/silk/A2NLSF.c | ||
| 46 | opus/silk/CNG.c | ||
| 47 | opus/silk/HP_variable_cutoff.c | ||
| 48 | opus/silk/LPC_analysis_filter.c | ||
| 49 | opus/silk/LPC_fit.c | ||
| 50 | opus/silk/LPC_inv_pred_gain.c | ||
| 51 | opus/silk/LP_variable_cutoff.c | ||
| 52 | opus/silk/NLSF2A.c | ||
| 53 | opus/silk/NLSF_VQ.c | ||
| 54 | opus/silk/NLSF_VQ_weights_laroia.c | ||
| 55 | opus/silk/NLSF_decode.c | ||
| 56 | opus/silk/NLSF_del_dec_quant.c | ||
| 57 | opus/silk/NLSF_encode.c | ||
| 58 | opus/silk/NLSF_stabilize.c | ||
| 59 | opus/silk/NLSF_unpack.c | ||
| 60 | opus/silk/NSQ.c | ||
| 61 | opus/silk/NSQ_del_dec.c | ||
| 62 | opus/silk/PLC.c | ||
| 63 | opus/silk/VAD.c | ||
| 64 | opus/silk/VQ_WMat_EC.c | ||
| 65 | opus/silk/ana_filt_bank_1.c | ||
| 66 | opus/silk/biquad_alt.c | ||
| 67 | opus/silk/bwexpander.c | ||
| 68 | opus/silk/bwexpander_32.c | ||
| 69 | opus/silk/check_control_input.c | ||
| 70 | opus/silk/code_signs.c | ||
| 71 | opus/silk/control_SNR.c | ||
| 72 | opus/silk/control_audio_bandwidth.c | ||
| 73 | opus/silk/control_codec.c | ||
| 74 | opus/silk/dec_API.c | ||
| 75 | opus/silk/decode_core.c | ||
| 76 | opus/silk/decode_frame.c | ||
| 77 | opus/silk/decode_indices.c | ||
| 78 | opus/silk/decode_parameters.c | ||
| 79 | opus/silk/decode_pitch.c | ||
| 80 | opus/silk/decode_pulses.c | ||
| 81 | opus/silk/decoder_set_fs.c | ||
| 82 | opus/silk/enc_API.c | ||
| 83 | opus/silk/encode_indices.c | ||
| 84 | opus/silk/encode_pulses.c | ||
| 85 | opus/silk/gain_quant.c | ||
| 86 | opus/silk/init_decoder.c | ||
| 87 | opus/silk/init_encoder.c | ||
| 88 | opus/silk/inner_prod_aligned.c | ||
| 89 | opus/silk/interpolate.c | ||
| 90 | opus/silk/lin2log.c | ||
| 91 | opus/silk/log2lin.c | ||
| 92 | opus/silk/pitch_est_tables.c | ||
| 93 | opus/silk/process_NLSFs.c | ||
| 94 | opus/silk/quant_LTP_gains.c | ||
| 95 | opus/silk/resampler.c | ||
| 96 | opus/silk/resampler_down2.c | ||
| 97 | opus/silk/resampler_down2_3.c | ||
| 98 | opus/silk/resampler_private_AR2.c | ||
| 99 | opus/silk/resampler_private_IIR_FIR.c | ||
| 100 | opus/silk/resampler_private_down_FIR.c | ||
| 101 | opus/silk/resampler_private_up2_HQ.c | ||
| 102 | opus/silk/resampler_rom.c | ||
| 103 | opus/silk/shell_coder.c | ||
| 104 | opus/silk/sigm_Q15.c | ||
| 105 | opus/silk/sort.c | ||
| 106 | opus/silk/stereo_LR_to_MS.c | ||
| 107 | opus/silk/stereo_MS_to_LR.c | ||
| 108 | opus/silk/stereo_decode_pred.c | ||
| 109 | opus/silk/stereo_encode_pred.c | ||
| 110 | opus/silk/stereo_find_predictor.c | ||
| 111 | opus/silk/stereo_quant_pred.c | ||
| 112 | opus/silk/sum_sqr_shift.c | ||
| 113 | opus/silk/table_LSF_cos.c | ||
| 114 | opus/silk/tables_LTP.c | ||
| 115 | opus/silk/tables_NLSF_CB_NB_MB.c | ||
| 116 | opus/silk/tables_NLSF_CB_WB.c | ||
| 117 | opus/silk/tables_gain.c | ||
| 118 | opus/silk/tables_other.c | ||
| 119 | opus/silk/tables_pitch_lag.c | ||
| 120 | opus/silk/tables_pulses_per_block.c | ||
| 121 | |||
| 122 | # Opus sources | ||
| 123 | opus/src/analysis.c | ||
| 124 | opus/src/mapping_matrix.c | ||
| 125 | opus/src/mlp.c | ||
| 126 | opus/src/mlp_data.c | ||
| 127 | opus/src/opus.c | ||
| 128 | opus/src/opus_decoder.c | ||
| 129 | opus/src/opus_encoder.c | ||
| 130 | opus/src/opus_multistream.c | ||
| 131 | opus/src/opus_multistream_decoder.c | ||
| 132 | opus/src/opus_multistream_encoder.c | ||
| 133 | opus/src/opus_projection_decoder.c | ||
| 134 | opus/src/opus_projection_encoder.c | ||
| 135 | opus/src/repacketizer.c | ||
| 136 | ) | ||
| 137 | |||
| 138 | if (DEBUG) | ||
| 139 | target_sources(opus PRIVATE opus/silk/debug.c) | ||
| 140 | endif() | ||
| 141 | |||
| 142 | if (OPUS_FIXED_POINT) | ||
| 143 | target_sources(opus PRIVATE | ||
| 144 | opus/silk/fixed/LTP_analysis_filter_FIX.c | ||
| 145 | opus/silk/fixed/LTP_scale_ctrl_FIX.c | ||
| 146 | opus/silk/fixed/apply_sine_window_FIX.c | ||
| 147 | opus/silk/fixed/autocorr_FIX.c | ||
| 148 | opus/silk/fixed/burg_modified_FIX.c | ||
| 149 | opus/silk/fixed/corrMatrix_FIX.c | ||
| 150 | opus/silk/fixed/encode_frame_FIX.c | ||
| 151 | opus/silk/fixed/find_LPC_FIX.c | ||
| 152 | opus/silk/fixed/find_LTP_FIX.c | ||
| 153 | opus/silk/fixed/find_pitch_lags_FIX.c | ||
| 154 | opus/silk/fixed/find_pred_coefs_FIX.c | ||
| 155 | opus/silk/fixed/k2a_FIX.c | ||
| 156 | opus/silk/fixed/k2a_Q16_FIX.c | ||
| 157 | opus/silk/fixed/noise_shape_analysis_FIX.c | ||
| 158 | opus/silk/fixed/pitch_analysis_core_FIX.c | ||
| 159 | opus/silk/fixed/prefilter_FIX.c | ||
| 160 | opus/silk/fixed/process_gains_FIX.c | ||
| 161 | opus/silk/fixed/regularize_correlations_FIX.c | ||
| 162 | opus/silk/fixed/residual_energy16_FIX.c | ||
| 163 | opus/silk/fixed/residual_energy_FIX.c | ||
| 164 | opus/silk/fixed/schur64_FIX.c | ||
| 165 | opus/silk/fixed/schur_FIX.c | ||
| 166 | opus/silk/fixed/solve_LS_FIX.c | ||
| 167 | opus/silk/fixed/vector_ops_FIX.c | ||
| 168 | opus/silk/fixed/warped_autocorrelation_FIX.c | ||
| 169 | ) | ||
| 170 | else() | ||
| 171 | target_sources(opus PRIVATE | ||
| 172 | opus/silk/float/LPC_analysis_filter_FLP.c | ||
| 173 | opus/silk/float/LPC_inv_pred_gain_FLP.c | ||
| 174 | opus/silk/float/LTP_analysis_filter_FLP.c | ||
| 175 | opus/silk/float/LTP_scale_ctrl_FLP.c | ||
| 176 | opus/silk/float/apply_sine_window_FLP.c | ||
| 177 | opus/silk/float/autocorrelation_FLP.c | ||
| 178 | opus/silk/float/burg_modified_FLP.c | ||
| 179 | opus/silk/float/bwexpander_FLP.c | ||
| 180 | opus/silk/float/corrMatrix_FLP.c | ||
| 181 | opus/silk/float/encode_frame_FLP.c | ||
| 182 | opus/silk/float/energy_FLP.c | ||
| 183 | opus/silk/float/find_LPC_FLP.c | ||
| 184 | opus/silk/float/find_LTP_FLP.c | ||
| 185 | opus/silk/float/find_pitch_lags_FLP.c | ||
| 186 | opus/silk/float/find_pred_coefs_FLP.c | ||
| 187 | opus/silk/float/inner_product_FLP.c | ||
| 188 | opus/silk/float/k2a_FLP.c | ||
| 189 | opus/silk/float/noise_shape_analysis_FLP.c | ||
| 190 | opus/silk/float/pitch_analysis_core_FLP.c | ||
| 191 | opus/silk/float/process_gains_FLP.c | ||
| 192 | opus/silk/float/regularize_correlations_FLP.c | ||
| 193 | opus/silk/float/residual_energy_FLP.c | ||
| 194 | opus/silk/float/scale_copy_vector_FLP.c | ||
| 195 | opus/silk/float/scale_vector_FLP.c | ||
| 196 | opus/silk/float/schur_FLP.c | ||
| 197 | opus/silk/float/sort_FLP.c | ||
| 198 | opus/silk/float/warped_autocorrelation_FLP.c | ||
| 199 | opus/silk/float/wrappers_FLP.c | ||
| 200 | ) | ||
| 201 | endif() | ||
| 202 | |||
| 203 | target_compile_definitions(opus PRIVATE OPUS_BUILD ENABLE_HARDENING) | ||
| 204 | |||
| 205 | if(NOT MSVC) | ||
| 206 | if(MINGW) | ||
| 207 | target_compile_definitions(opus PRIVATE _FORTIFY_SOURCE=0) | ||
| 208 | else() | ||
| 209 | target_compile_definitions(opus PRIVATE _FORTIFY_SOURCE=2) | ||
| 210 | endif() | ||
| 211 | endif() | ||
| 212 | |||
| 213 | # It is strongly recommended to uncomment one of these VAR_ARRAYS: Use C99 | ||
| 214 | # variable-length arrays for stack allocation USE_ALLOCA: Use alloca() for stack | ||
| 215 | # allocation If none is defined, then the fallback is a non-threadsafe global | ||
| 216 | # array | ||
| 217 | if(OPUS_USE_ALLOCA OR MSVC) | ||
| 218 | target_compile_definitions(opus PRIVATE USE_ALLOCA) | ||
| 219 | else() | ||
| 220 | target_compile_definitions(opus PRIVATE VAR_ARRAYS) | ||
| 221 | endif() | ||
| 222 | |||
| 223 | if(OPUS_CUSTOM_MODES) | ||
| 224 | target_compile_definitions(opus PRIVATE CUSTOM_MODES) | ||
| 225 | endif() | ||
| 226 | |||
| 227 | if(NOT OPUS_ENABLE_FLOAT_API) | ||
| 228 | target_compile_definitions(opus PRIVATE DISABLE_FLOAT_API) | ||
| 229 | endif() | ||
| 230 | |||
| 231 | target_compile_definitions(opus | ||
| 232 | PUBLIC | ||
| 233 | -DOPUS_VERSION="\\"1.3.1\\"" | ||
| 234 | |||
| 235 | PRIVATE | ||
| 236 | # Use C99 intrinsics to speed up float-to-int conversion | ||
| 237 | HAVE_LRINTF | ||
| 238 | ) | ||
| 239 | |||
| 240 | if (FIXED_POINT) | ||
| 241 | target_compile_definitions(opus PRIVATE -DFIXED_POINT=1 -DDISABLE_FLOAT_API) | ||
| 242 | endif() | ||
| 243 | |||
| 244 | target_include_directories(opus | ||
| 245 | PUBLIC | ||
| 246 | opus/include | ||
| 247 | |||
| 248 | PRIVATE | ||
| 249 | opus/celt | ||
| 250 | opus/silk | ||
| 251 | opus/silk/fixed | ||
| 252 | opus/silk/float | ||
| 253 | opus/src | ||
| 254 | ) | ||
diff --git a/externals/opus/opus b/externals/opus/opus new file mode 160000 | |||
| Subproject ad8fe90db79b7d2a135e3dfd2ed6631b0c5662a | |||
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index f87d67db5..d1f173f42 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt | |||
| @@ -614,7 +614,7 @@ endif() | |||
| 614 | create_target_directory_groups(core) | 614 | create_target_directory_groups(core) |
| 615 | 615 | ||
| 616 | target_link_libraries(core PUBLIC common PRIVATE audio_core video_core) | 616 | target_link_libraries(core PUBLIC common PRIVATE audio_core video_core) |
| 617 | target_link_libraries(core PUBLIC Boost::boost PRIVATE fmt::fmt nlohmann_json::nlohmann_json mbedtls Opus::Opus unicorn zip) | 617 | target_link_libraries(core PUBLIC Boost::boost PRIVATE fmt::fmt nlohmann_json::nlohmann_json mbedtls opus unicorn zip) |
| 618 | 618 | ||
| 619 | if (YUZU_ENABLE_BOXCAT) | 619 | if (YUZU_ENABLE_BOXCAT) |
| 620 | target_compile_definitions(core PRIVATE -DYUZU_ENABLE_BOXCAT) | 620 | target_compile_definitions(core PRIVATE -DYUZU_ENABLE_BOXCAT) |
diff --git a/src/core/crypto/key_manager.h b/src/core/crypto/key_manager.h index bf3434e1c..9269a73f2 100644 --- a/src/core/crypto/key_manager.h +++ b/src/core/crypto/key_manager.h | |||
| @@ -223,13 +223,16 @@ bool operator<(const KeyIndex<KeyType>& lhs, const KeyIndex<KeyType>& rhs) { | |||
| 223 | 223 | ||
| 224 | class KeyManager { | 224 | class KeyManager { |
| 225 | public: | 225 | public: |
| 226 | static KeyManager& instance() { | 226 | static KeyManager& Instance() { |
| 227 | static KeyManager instance; | 227 | static KeyManager instance; |
| 228 | return instance; | 228 | return instance; |
| 229 | } | 229 | } |
| 230 | 230 | ||
| 231 | KeyManager(KeyManager const&) = delete; | 231 | KeyManager(const KeyManager&) = delete; |
| 232 | void operator=(KeyManager const&) = delete; | 232 | KeyManager& operator=(const KeyManager&) = delete; |
| 233 | |||
| 234 | KeyManager(KeyManager&&) = delete; | ||
| 235 | KeyManager& operator=(KeyManager&&) = delete; | ||
| 233 | 236 | ||
| 234 | bool HasKey(S128KeyType id, u64 field1 = 0, u64 field2 = 0) const; | 237 | bool HasKey(S128KeyType id, u64 field1 = 0, u64 field2 = 0) const; |
| 235 | bool HasKey(S256KeyType id, u64 field1 = 0, u64 field2 = 0) const; | 238 | bool HasKey(S256KeyType id, u64 field1 = 0, u64 field2 = 0) const; |
diff --git a/src/core/file_sys/bis_factory.cpp b/src/core/file_sys/bis_factory.cpp index 464ca6503..8935a62c3 100644 --- a/src/core/file_sys/bis_factory.cpp +++ b/src/core/file_sys/bis_factory.cpp | |||
| @@ -79,7 +79,7 @@ VirtualDir BISFactory::OpenPartition(BisPartitionId id) const { | |||
| 79 | } | 79 | } |
| 80 | 80 | ||
| 81 | VirtualFile BISFactory::OpenPartitionStorage(BisPartitionId id) const { | 81 | VirtualFile BISFactory::OpenPartitionStorage(BisPartitionId id) const { |
| 82 | Core::Crypto::KeyManager& keys = Core::Crypto::KeyManager::instance(); | 82 | auto& keys = Core::Crypto::KeyManager::Instance(); |
| 83 | Core::Crypto::PartitionDataManager pdm{ | 83 | Core::Crypto::PartitionDataManager pdm{ |
| 84 | Core::System::GetInstance().GetFilesystem()->OpenDirectory( | 84 | Core::System::GetInstance().GetFilesystem()->OpenDirectory( |
| 85 | FileUtil::GetUserPath(FileUtil::UserPath::SysDataDir), Mode::Read)}; | 85 | FileUtil::GetUserPath(FileUtil::UserPath::SysDataDir), Mode::Read)}; |
diff --git a/src/core/file_sys/card_image.h b/src/core/file_sys/card_image.h index a09d504ae..e1b136426 100644 --- a/src/core/file_sys/card_image.h +++ b/src/core/file_sys/card_image.h | |||
| @@ -140,6 +140,6 @@ private: | |||
| 140 | 140 | ||
| 141 | u64 update_normal_partition_end; | 141 | u64 update_normal_partition_end; |
| 142 | 142 | ||
| 143 | Core::Crypto::KeyManager& keys = Core::Crypto::KeyManager::instance(); | 143 | Core::Crypto::KeyManager& keys = Core::Crypto::KeyManager::Instance(); |
| 144 | }; | 144 | }; |
| 145 | } // namespace FileSys | 145 | } // namespace FileSys |
diff --git a/src/core/file_sys/content_archive.h b/src/core/file_sys/content_archive.h index e6c887b32..d25cbcf91 100644 --- a/src/core/file_sys/content_archive.h +++ b/src/core/file_sys/content_archive.h | |||
| @@ -158,7 +158,7 @@ private: | |||
| 158 | bool encrypted = false; | 158 | bool encrypted = false; |
| 159 | bool is_update = false; | 159 | bool is_update = false; |
| 160 | 160 | ||
| 161 | Core::Crypto::KeyManager& keys = Core::Crypto::KeyManager::instance(); | 161 | Core::Crypto::KeyManager& keys = Core::Crypto::KeyManager::Instance(); |
| 162 | }; | 162 | }; |
| 163 | 163 | ||
| 164 | } // namespace FileSys | 164 | } // namespace FileSys |
diff --git a/src/core/file_sys/registered_cache.h b/src/core/file_sys/registered_cache.h index 4b2fb08cb..f339cd17b 100644 --- a/src/core/file_sys/registered_cache.h +++ b/src/core/file_sys/registered_cache.h | |||
| @@ -88,7 +88,7 @@ public: | |||
| 88 | 88 | ||
| 89 | protected: | 89 | protected: |
| 90 | // A single instance of KeyManager to be used by GetEntry() | 90 | // A single instance of KeyManager to be used by GetEntry() |
| 91 | Core::Crypto::KeyManager& keys = Core::Crypto::KeyManager::instance(); | 91 | Core::Crypto::KeyManager& keys = Core::Crypto::KeyManager::Instance(); |
| 92 | }; | 92 | }; |
| 93 | 93 | ||
| 94 | class PlaceholderCache { | 94 | class PlaceholderCache { |
diff --git a/src/core/file_sys/submission_package.cpp b/src/core/file_sys/submission_package.cpp index c35a0d10b..175a8266a 100644 --- a/src/core/file_sys/submission_package.cpp +++ b/src/core/file_sys/submission_package.cpp | |||
| @@ -21,7 +21,7 @@ | |||
| 21 | namespace FileSys { | 21 | namespace FileSys { |
| 22 | namespace { | 22 | namespace { |
| 23 | void SetTicketKeys(const std::vector<VirtualFile>& files) { | 23 | void SetTicketKeys(const std::vector<VirtualFile>& files) { |
| 24 | Core::Crypto::KeyManager& keys = Core::Crypto::KeyManager::instance(); | 24 | auto& keys = Core::Crypto::KeyManager::Instance(); |
| 25 | 25 | ||
| 26 | for (const auto& ticket_file : files) { | 26 | for (const auto& ticket_file : files) { |
| 27 | if (ticket_file == nullptr) { | 27 | if (ticket_file == nullptr) { |
diff --git a/src/core/file_sys/submission_package.h b/src/core/file_sys/submission_package.h index bd577f6e5..cf89de6a9 100644 --- a/src/core/file_sys/submission_package.h +++ b/src/core/file_sys/submission_package.h | |||
| @@ -73,7 +73,7 @@ private: | |||
| 73 | std::map<u64, std::map<std::pair<TitleType, ContentRecordType>, std::shared_ptr<NCA>>> ncas; | 73 | std::map<u64, std::map<std::pair<TitleType, ContentRecordType>, std::shared_ptr<NCA>>> ncas; |
| 74 | std::vector<VirtualFile> ticket_files; | 74 | std::vector<VirtualFile> ticket_files; |
| 75 | 75 | ||
| 76 | Core::Crypto::KeyManager& keys = Core::Crypto::KeyManager::instance(); | 76 | Core::Crypto::KeyManager& keys = Core::Crypto::KeyManager::Instance(); |
| 77 | 77 | ||
| 78 | VirtualFile romfs; | 78 | VirtualFile romfs; |
| 79 | VirtualDir exefs; | 79 | VirtualDir exefs; |
diff --git a/src/core/file_sys/xts_archive.h b/src/core/file_sys/xts_archive.h index 95da907bc..563531bb6 100644 --- a/src/core/file_sys/xts_archive.h +++ b/src/core/file_sys/xts_archive.h | |||
| @@ -62,6 +62,6 @@ private: | |||
| 62 | 62 | ||
| 63 | VirtualFile dec_file; | 63 | VirtualFile dec_file; |
| 64 | 64 | ||
| 65 | Core::Crypto::KeyManager& keys = Core::Crypto::KeyManager::instance(); | 65 | Core::Crypto::KeyManager& keys = Core::Crypto::KeyManager::Instance(); |
| 66 | }; | 66 | }; |
| 67 | } // namespace FileSys | 67 | } // namespace FileSys |
diff --git a/src/core/hle/service/acc/acc.cpp b/src/core/hle/service/acc/acc.cpp index 94d8c1fc6..8ac856ec3 100644 --- a/src/core/hle/service/acc/acc.cpp +++ b/src/core/hle/service/acc/acc.cpp | |||
| @@ -776,6 +776,15 @@ void Module::Interface::ListQualifiedUsers(Kernel::HLERequestContext& ctx) { | |||
| 776 | rb.Push(RESULT_SUCCESS); | 776 | rb.Push(RESULT_SUCCESS); |
| 777 | } | 777 | } |
| 778 | 778 | ||
| 779 | void Module::Interface::ListOpenContextStoredUsers(Kernel::HLERequestContext& ctx) { | ||
| 780 | LOG_WARNING(Service_ACC, "(STUBBED) called"); | ||
| 781 | |||
| 782 | // TODO(ogniK): Handle open contexts | ||
| 783 | ctx.WriteBuffer(profile_manager->GetOpenUsers()); | ||
| 784 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 785 | rb.Push(RESULT_SUCCESS); | ||
| 786 | } | ||
| 787 | |||
| 779 | void Module::Interface::TrySelectUserWithoutInteraction(Kernel::HLERequestContext& ctx) { | 788 | void Module::Interface::TrySelectUserWithoutInteraction(Kernel::HLERequestContext& ctx) { |
| 780 | LOG_DEBUG(Service_ACC, "called"); | 789 | LOG_DEBUG(Service_ACC, "called"); |
| 781 | // A u8 is passed into this function which we can safely ignore. It's to determine if we have | 790 | // A u8 is passed into this function which we can safely ignore. It's to determine if we have |
diff --git a/src/core/hle/service/acc/acc.h b/src/core/hle/service/acc/acc.h index 74ca39d6e..d4c6395c6 100644 --- a/src/core/hle/service/acc/acc.h +++ b/src/core/hle/service/acc/acc.h | |||
| @@ -34,6 +34,7 @@ public: | |||
| 34 | void IsUserAccountSwitchLocked(Kernel::HLERequestContext& ctx); | 34 | void IsUserAccountSwitchLocked(Kernel::HLERequestContext& ctx); |
| 35 | void GetProfileEditor(Kernel::HLERequestContext& ctx); | 35 | void GetProfileEditor(Kernel::HLERequestContext& ctx); |
| 36 | void ListQualifiedUsers(Kernel::HLERequestContext& ctx); | 36 | void ListQualifiedUsers(Kernel::HLERequestContext& ctx); |
| 37 | void ListOpenContextStoredUsers(Kernel::HLERequestContext& ctx); | ||
| 37 | 38 | ||
| 38 | private: | 39 | private: |
| 39 | ResultCode InitializeApplicationInfoBase(); | 40 | ResultCode InitializeApplicationInfoBase(); |
diff --git a/src/core/hle/service/acc/acc_su.cpp b/src/core/hle/service/acc/acc_su.cpp index 85620bde3..d2bb8c2c8 100644 --- a/src/core/hle/service/acc/acc_su.cpp +++ b/src/core/hle/service/acc/acc_su.cpp | |||
| @@ -20,7 +20,7 @@ ACC_SU::ACC_SU(std::shared_ptr<Module> module, std::shared_ptr<ProfileManager> p | |||
| 20 | {6, nullptr, "GetProfileDigest"}, // 3.0.0+ | 20 | {6, nullptr, "GetProfileDigest"}, // 3.0.0+ |
| 21 | {50, &ACC_SU::IsUserRegistrationRequestPermitted, "IsUserRegistrationRequestPermitted"}, | 21 | {50, &ACC_SU::IsUserRegistrationRequestPermitted, "IsUserRegistrationRequestPermitted"}, |
| 22 | {51, &ACC_SU::TrySelectUserWithoutInteraction, "TrySelectUserWithoutInteraction"}, | 22 | {51, &ACC_SU::TrySelectUserWithoutInteraction, "TrySelectUserWithoutInteraction"}, |
| 23 | {60, nullptr, "ListOpenContextStoredUsers"}, // 5.0.0 - 5.1.0 | 23 | {60, &ACC_SU::ListOpenContextStoredUsers, "ListOpenContextStoredUsers"}, // 5.0.0 - 5.1.0 |
| 24 | {99, nullptr, "DebugActivateOpenContextRetention"}, // 6.0.0+ | 24 | {99, nullptr, "DebugActivateOpenContextRetention"}, // 6.0.0+ |
| 25 | {100, nullptr, "GetUserRegistrationNotifier"}, | 25 | {100, nullptr, "GetUserRegistrationNotifier"}, |
| 26 | {101, nullptr, "GetUserStateChangeNotifier"}, | 26 | {101, nullptr, "GetUserStateChangeNotifier"}, |
diff --git a/src/core/hle/service/acc/acc_u0.cpp b/src/core/hle/service/acc/acc_u0.cpp index 49f6e20f1..cb44e06b7 100644 --- a/src/core/hle/service/acc/acc_u0.cpp +++ b/src/core/hle/service/acc/acc_u0.cpp | |||
| @@ -20,7 +20,7 @@ ACC_U0::ACC_U0(std::shared_ptr<Module> module, std::shared_ptr<ProfileManager> p | |||
| 20 | {6, nullptr, "GetProfileDigest"}, // 3.0.0+ | 20 | {6, nullptr, "GetProfileDigest"}, // 3.0.0+ |
| 21 | {50, &ACC_U0::IsUserRegistrationRequestPermitted, "IsUserRegistrationRequestPermitted"}, | 21 | {50, &ACC_U0::IsUserRegistrationRequestPermitted, "IsUserRegistrationRequestPermitted"}, |
| 22 | {51, &ACC_U0::TrySelectUserWithoutInteraction, "TrySelectUserWithoutInteraction"}, | 22 | {51, &ACC_U0::TrySelectUserWithoutInteraction, "TrySelectUserWithoutInteraction"}, |
| 23 | {60, nullptr, "ListOpenContextStoredUsers"}, // 5.0.0 - 5.1.0 | 23 | {60, &ACC_U0::ListOpenContextStoredUsers, "ListOpenContextStoredUsers"}, // 5.0.0 - 5.1.0 |
| 24 | {99, nullptr, "DebugActivateOpenContextRetention"}, // 6.0.0+ | 24 | {99, nullptr, "DebugActivateOpenContextRetention"}, // 6.0.0+ |
| 25 | {100, &ACC_U0::InitializeApplicationInfo, "InitializeApplicationInfo"}, | 25 | {100, &ACC_U0::InitializeApplicationInfo, "InitializeApplicationInfo"}, |
| 26 | {101, &ACC_U0::GetBaasAccountManagerForApplication, "GetBaasAccountManagerForApplication"}, | 26 | {101, &ACC_U0::GetBaasAccountManagerForApplication, "GetBaasAccountManagerForApplication"}, |
| @@ -30,7 +30,7 @@ ACC_U0::ACC_U0(std::shared_ptr<Module> module, std::shared_ptr<ProfileManager> p | |||
| 30 | {111, nullptr, "ClearSaveDataThumbnail"}, | 30 | {111, nullptr, "ClearSaveDataThumbnail"}, |
| 31 | {120, nullptr, "CreateGuestLoginRequest"}, | 31 | {120, nullptr, "CreateGuestLoginRequest"}, |
| 32 | {130, nullptr, "LoadOpenContext"}, // 5.0.0+ | 32 | {130, nullptr, "LoadOpenContext"}, // 5.0.0+ |
| 33 | {131, nullptr, "ListOpenContextStoredUsers"}, // 6.0.0+ | 33 | {131, &ACC_U0::ListOpenContextStoredUsers, "ListOpenContextStoredUsers"}, // 6.0.0+ |
| 34 | {140, &ACC_U0::InitializeApplicationInfoRestricted, "InitializeApplicationInfoRestricted"}, // 6.0.0+ | 34 | {140, &ACC_U0::InitializeApplicationInfoRestricted, "InitializeApplicationInfoRestricted"}, // 6.0.0+ |
| 35 | {141, &ACC_U0::ListQualifiedUsers, "ListQualifiedUsers"}, // 6.0.0+ | 35 | {141, &ACC_U0::ListQualifiedUsers, "ListQualifiedUsers"}, // 6.0.0+ |
| 36 | {150, &ACC_U0::IsUserAccountSwitchLocked, "IsUserAccountSwitchLocked"}, // 6.0.0+ | 36 | {150, &ACC_U0::IsUserAccountSwitchLocked, "IsUserAccountSwitchLocked"}, // 6.0.0+ |
diff --git a/src/core/hle/service/acc/acc_u1.cpp b/src/core/hle/service/acc/acc_u1.cpp index f47004f84..a4aa5316a 100644 --- a/src/core/hle/service/acc/acc_u1.cpp +++ b/src/core/hle/service/acc/acc_u1.cpp | |||
| @@ -20,7 +20,7 @@ ACC_U1::ACC_U1(std::shared_ptr<Module> module, std::shared_ptr<ProfileManager> p | |||
| 20 | {6, nullptr, "GetProfileDigest"}, // 3.0.0+ | 20 | {6, nullptr, "GetProfileDigest"}, // 3.0.0+ |
| 21 | {50, &ACC_U1::IsUserRegistrationRequestPermitted, "IsUserRegistrationRequestPermitted"}, | 21 | {50, &ACC_U1::IsUserRegistrationRequestPermitted, "IsUserRegistrationRequestPermitted"}, |
| 22 | {51, &ACC_U1::TrySelectUserWithoutInteraction, "TrySelectUserWithoutInteraction"}, | 22 | {51, &ACC_U1::TrySelectUserWithoutInteraction, "TrySelectUserWithoutInteraction"}, |
| 23 | {60, nullptr, "ListOpenContextStoredUsers"}, // 5.0.0 - 5.1.0 | 23 | {60, &ACC_U1::ListOpenContextStoredUsers, "ListOpenContextStoredUsers"}, // 5.0.0 - 5.1.0 |
| 24 | {99, nullptr, "DebugActivateOpenContextRetention"}, // 6.0.0+ | 24 | {99, nullptr, "DebugActivateOpenContextRetention"}, // 6.0.0+ |
| 25 | {100, nullptr, "GetUserRegistrationNotifier"}, | 25 | {100, nullptr, "GetUserRegistrationNotifier"}, |
| 26 | {101, nullptr, "GetUserStateChangeNotifier"}, | 26 | {101, nullptr, "GetUserStateChangeNotifier"}, |
diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp index 20f366635..1bb544dd8 100644 --- a/src/core/hle/service/am/am.cpp +++ b/src/core/hle/service/am/am.cpp | |||
| @@ -841,7 +841,7 @@ public: | |||
| 841 | {110, nullptr, "NeedsToExitProcess"}, | 841 | {110, nullptr, "NeedsToExitProcess"}, |
| 842 | {120, nullptr, "GetLibraryAppletInfo"}, | 842 | {120, nullptr, "GetLibraryAppletInfo"}, |
| 843 | {150, nullptr, "RequestForAppletToGetForeground"}, | 843 | {150, nullptr, "RequestForAppletToGetForeground"}, |
| 844 | {160, nullptr, "GetIndirectLayerConsumerHandle"}, | 844 | {160, &ILibraryAppletAccessor::GetIndirectLayerConsumerHandle, "GetIndirectLayerConsumerHandle"}, |
| 845 | }; | 845 | }; |
| 846 | // clang-format on | 846 | // clang-format on |
| 847 | 847 | ||
| @@ -960,6 +960,18 @@ private: | |||
| 960 | rb.PushCopyObjects(applet->GetBroker().GetInteractiveDataEvent()); | 960 | rb.PushCopyObjects(applet->GetBroker().GetInteractiveDataEvent()); |
| 961 | } | 961 | } |
| 962 | 962 | ||
| 963 | void GetIndirectLayerConsumerHandle(Kernel::HLERequestContext& ctx) { | ||
| 964 | LOG_WARNING(Service_AM, "(STUBBED) called"); | ||
| 965 | |||
| 966 | // We require a non-zero handle to be valid. Using 0xdeadbeef allows us to trace if this is | ||
| 967 | // actually used anywhere | ||
| 968 | constexpr u64 handle = 0xdeadbeef; | ||
| 969 | |||
| 970 | IPC::ResponseBuilder rb{ctx, 4}; | ||
| 971 | rb.Push(RESULT_SUCCESS); | ||
| 972 | rb.Push(handle); | ||
| 973 | } | ||
| 974 | |||
| 963 | std::shared_ptr<Applets::Applet> applet; | 975 | std::shared_ptr<Applets::Applet> applet; |
| 964 | }; | 976 | }; |
| 965 | 977 | ||
diff --git a/src/core/hle/service/es/es.cpp b/src/core/hle/service/es/es.cpp index da6b74a22..a41c73c48 100644 --- a/src/core/hle/service/es/es.cpp +++ b/src/core/hle/service/es/es.cpp | |||
| @@ -302,7 +302,7 @@ private: | |||
| 302 | rb.Push<u64>(write_size); | 302 | rb.Push<u64>(write_size); |
| 303 | } | 303 | } |
| 304 | 304 | ||
| 305 | Core::Crypto::KeyManager& keys = Core::Crypto::KeyManager::instance(); | 305 | Core::Crypto::KeyManager& keys = Core::Crypto::KeyManager::Instance(); |
| 306 | }; | 306 | }; |
| 307 | 307 | ||
| 308 | void InstallInterfaces(SM::ServiceManager& service_manager) { | 308 | void InstallInterfaces(SM::ServiceManager& service_manager) { |
diff --git a/src/core/hle/service/set/set.cpp b/src/core/hle/service/set/set.cpp index f3b4b286c..e5cfd2101 100644 --- a/src/core/hle/service/set/set.cpp +++ b/src/core/hle/service/set/set.cpp | |||
| @@ -3,6 +3,7 @@ | |||
| 3 | // Refer to the license.txt file included. | 3 | // Refer to the license.txt file included. |
| 4 | 4 | ||
| 5 | #include <algorithm> | 5 | #include <algorithm> |
| 6 | #include <array> | ||
| 6 | #include <chrono> | 7 | #include <chrono> |
| 7 | #include "common/logging/log.h" | 8 | #include "common/logging/log.h" |
| 8 | #include "core/hle/ipc_helpers.h" | 9 | #include "core/hle/ipc_helpers.h" |
| @@ -31,6 +32,44 @@ constexpr std::array<LanguageCode, 17> available_language_codes = {{ | |||
| 31 | LanguageCode::ZH_HANT, | 32 | LanguageCode::ZH_HANT, |
| 32 | }}; | 33 | }}; |
| 33 | 34 | ||
| 35 | enum class KeyboardLayout : u64 { | ||
| 36 | Japanese = 0, | ||
| 37 | EnglishUs = 1, | ||
| 38 | EnglishUsInternational = 2, | ||
| 39 | EnglishUk = 3, | ||
| 40 | French = 4, | ||
| 41 | FrenchCa = 5, | ||
| 42 | Spanish = 6, | ||
| 43 | SpanishLatin = 7, | ||
| 44 | German = 8, | ||
| 45 | Italian = 9, | ||
| 46 | Portuguese = 10, | ||
| 47 | Russian = 11, | ||
| 48 | Korean = 12, | ||
| 49 | ChineseSimplified = 13, | ||
| 50 | ChineseTraditional = 14, | ||
| 51 | }; | ||
| 52 | |||
| 53 | constexpr std::array<std::pair<LanguageCode, KeyboardLayout>, 17> language_to_layout{{ | ||
| 54 | {LanguageCode::JA, KeyboardLayout::Japanese}, | ||
| 55 | {LanguageCode::EN_US, KeyboardLayout::EnglishUs}, | ||
| 56 | {LanguageCode::FR, KeyboardLayout::French}, | ||
| 57 | {LanguageCode::DE, KeyboardLayout::German}, | ||
| 58 | {LanguageCode::IT, KeyboardLayout::Italian}, | ||
| 59 | {LanguageCode::ES, KeyboardLayout::Spanish}, | ||
| 60 | {LanguageCode::ZH_CN, KeyboardLayout::ChineseSimplified}, | ||
| 61 | {LanguageCode::KO, KeyboardLayout::Korean}, | ||
| 62 | {LanguageCode::NL, KeyboardLayout::EnglishUsInternational}, | ||
| 63 | {LanguageCode::PT, KeyboardLayout::Portuguese}, | ||
| 64 | {LanguageCode::RU, KeyboardLayout::Russian}, | ||
| 65 | {LanguageCode::ZH_TW, KeyboardLayout::ChineseTraditional}, | ||
| 66 | {LanguageCode::EN_GB, KeyboardLayout::EnglishUk}, | ||
| 67 | {LanguageCode::FR_CA, KeyboardLayout::FrenchCa}, | ||
| 68 | {LanguageCode::ES_419, KeyboardLayout::SpanishLatin}, | ||
| 69 | {LanguageCode::ZH_HANS, KeyboardLayout::ChineseSimplified}, | ||
| 70 | {LanguageCode::ZH_HANT, KeyboardLayout::ChineseTraditional}, | ||
| 71 | }}; | ||
| 72 | |||
| 34 | constexpr std::size_t pre4_0_0_max_entries = 15; | 73 | constexpr std::size_t pre4_0_0_max_entries = 15; |
| 35 | constexpr std::size_t post4_0_0_max_entries = 17; | 74 | constexpr std::size_t post4_0_0_max_entries = 17; |
| 36 | 75 | ||
| @@ -50,6 +89,25 @@ void GetAvailableLanguageCodesImpl(Kernel::HLERequestContext& ctx, std::size_t m | |||
| 50 | ctx.WriteBuffer(available_language_codes.data(), copy_size); | 89 | ctx.WriteBuffer(available_language_codes.data(), copy_size); |
| 51 | PushResponseLanguageCode(ctx, copy_amount); | 90 | PushResponseLanguageCode(ctx, copy_amount); |
| 52 | } | 91 | } |
| 92 | |||
| 93 | void GetKeyCodeMapImpl(Kernel::HLERequestContext& ctx) { | ||
| 94 | const auto language_code = available_language_codes[Settings::values.language_index]; | ||
| 95 | const auto key_code = | ||
| 96 | std::find_if(language_to_layout.cbegin(), language_to_layout.cend(), | ||
| 97 | [=](const auto& element) { return element.first == language_code; }); | ||
| 98 | KeyboardLayout layout = KeyboardLayout::EnglishUs; | ||
| 99 | if (key_code == language_to_layout.cend()) { | ||
| 100 | LOG_ERROR(Service_SET, | ||
| 101 | "Could not find keyboard layout for language index {}, defaulting to English us", | ||
| 102 | Settings::values.language_index); | ||
| 103 | } else { | ||
| 104 | layout = key_code->second; | ||
| 105 | } | ||
| 106 | |||
| 107 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 108 | rb.Push(RESULT_SUCCESS); | ||
| 109 | ctx.WriteBuffer(&layout, sizeof(KeyboardLayout)); | ||
| 110 | } | ||
| 53 | } // Anonymous namespace | 111 | } // Anonymous namespace |
| 54 | 112 | ||
| 55 | LanguageCode GetLanguageCodeFromIndex(std::size_t index) { | 113 | LanguageCode GetLanguageCodeFromIndex(std::size_t index) { |
| @@ -120,6 +178,16 @@ void SET::GetRegionCode(Kernel::HLERequestContext& ctx) { | |||
| 120 | rb.Push(Settings::values.region_index); | 178 | rb.Push(Settings::values.region_index); |
| 121 | } | 179 | } |
| 122 | 180 | ||
| 181 | void SET::GetKeyCodeMap(Kernel::HLERequestContext& ctx) { | ||
| 182 | LOG_DEBUG(Service_SET, "Called {}", ctx.Description()); | ||
| 183 | GetKeyCodeMapImpl(ctx); | ||
| 184 | } | ||
| 185 | |||
| 186 | void SET::GetKeyCodeMap2(Kernel::HLERequestContext& ctx) { | ||
| 187 | LOG_DEBUG(Service_SET, "Called {}", ctx.Description()); | ||
| 188 | GetKeyCodeMapImpl(ctx); | ||
| 189 | } | ||
| 190 | |||
| 123 | SET::SET() : ServiceFramework("set") { | 191 | SET::SET() : ServiceFramework("set") { |
| 124 | // clang-format off | 192 | // clang-format off |
| 125 | static const FunctionInfo functions[] = { | 193 | static const FunctionInfo functions[] = { |
| @@ -130,9 +198,9 @@ SET::SET() : ServiceFramework("set") { | |||
| 130 | {4, &SET::GetRegionCode, "GetRegionCode"}, | 198 | {4, &SET::GetRegionCode, "GetRegionCode"}, |
| 131 | {5, &SET::GetAvailableLanguageCodes2, "GetAvailableLanguageCodes2"}, | 199 | {5, &SET::GetAvailableLanguageCodes2, "GetAvailableLanguageCodes2"}, |
| 132 | {6, &SET::GetAvailableLanguageCodeCount2, "GetAvailableLanguageCodeCount2"}, | 200 | {6, &SET::GetAvailableLanguageCodeCount2, "GetAvailableLanguageCodeCount2"}, |
| 133 | {7, nullptr, "GetKeyCodeMap"}, | 201 | {7, &SET::GetKeyCodeMap, "GetKeyCodeMap"}, |
| 134 | {8, &SET::GetQuestFlag, "GetQuestFlag"}, | 202 | {8, &SET::GetQuestFlag, "GetQuestFlag"}, |
| 135 | {9, nullptr, "GetKeyCodeMap2"}, | 203 | {9, &SET::GetKeyCodeMap2, "GetKeyCodeMap2"}, |
| 136 | {10, nullptr, "GetFirmwareVersionForDebug"}, | 204 | {10, nullptr, "GetFirmwareVersionForDebug"}, |
| 137 | }; | 205 | }; |
| 138 | // clang-format on | 206 | // clang-format on |
diff --git a/src/core/hle/service/set/set.h b/src/core/hle/service/set/set.h index 6084b345d..8ac9c169d 100644 --- a/src/core/hle/service/set/set.h +++ b/src/core/hle/service/set/set.h | |||
| @@ -44,6 +44,8 @@ private: | |||
| 44 | void GetAvailableLanguageCodeCount2(Kernel::HLERequestContext& ctx); | 44 | void GetAvailableLanguageCodeCount2(Kernel::HLERequestContext& ctx); |
| 45 | void GetQuestFlag(Kernel::HLERequestContext& ctx); | 45 | void GetQuestFlag(Kernel::HLERequestContext& ctx); |
| 46 | void GetRegionCode(Kernel::HLERequestContext& ctx); | 46 | void GetRegionCode(Kernel::HLERequestContext& ctx); |
| 47 | void GetKeyCodeMap(Kernel::HLERequestContext& ctx); | ||
| 48 | void GetKeyCodeMap2(Kernel::HLERequestContext& ctx); | ||
| 47 | }; | 49 | }; |
| 48 | 50 | ||
| 49 | } // namespace Service::Set | 51 | } // namespace Service::Set |
diff --git a/src/input_common/CMakeLists.txt b/src/input_common/CMakeLists.txt index a9c2392b1..3bd76dd23 100644 --- a/src/input_common/CMakeLists.txt +++ b/src/input_common/CMakeLists.txt | |||
| @@ -7,6 +7,10 @@ add_library(input_common STATIC | |||
| 7 | main.h | 7 | main.h |
| 8 | motion_emu.cpp | 8 | motion_emu.cpp |
| 9 | motion_emu.h | 9 | motion_emu.h |
| 10 | gcadapter/gc_adapter.cpp | ||
| 11 | gcadapter/gc_adapter.h | ||
| 12 | gcadapter/gc_poller.cpp | ||
| 13 | gcadapter/gc_poller.h | ||
| 10 | sdl/sdl.cpp | 14 | sdl/sdl.cpp |
| 11 | sdl/sdl.h | 15 | sdl/sdl.h |
| 12 | udp/client.cpp | 16 | udp/client.cpp |
| @@ -26,5 +30,7 @@ if(SDL2_FOUND) | |||
| 26 | target_compile_definitions(input_common PRIVATE HAVE_SDL2) | 30 | target_compile_definitions(input_common PRIVATE HAVE_SDL2) |
| 27 | endif() | 31 | endif() |
| 28 | 32 | ||
| 33 | target_link_libraries(input_common PUBLIC ${LIBUSB_LIBRARIES}) | ||
| 34 | |||
| 29 | create_target_directory_groups(input_common) | 35 | create_target_directory_groups(input_common) |
| 30 | target_link_libraries(input_common PUBLIC core PRIVATE common Boost::boost) | 36 | target_link_libraries(input_common PUBLIC core PRIVATE common Boost::boost) |
diff --git a/src/input_common/gcadapter/gc_adapter.cpp b/src/input_common/gcadapter/gc_adapter.cpp new file mode 100644 index 000000000..b39d2a3fb --- /dev/null +++ b/src/input_common/gcadapter/gc_adapter.cpp | |||
| @@ -0,0 +1,379 @@ | |||
| 1 | // Copyright 2014 Dolphin Emulator Project | ||
| 2 | // Licensed under GPLv2+ | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include <chrono> | ||
| 6 | #include <thread> | ||
| 7 | #include "common/logging/log.h" | ||
| 8 | #include "input_common/gcadapter/gc_adapter.h" | ||
| 9 | |||
| 10 | namespace GCAdapter { | ||
| 11 | |||
| 12 | /// Used to loop through and assign button in poller | ||
| 13 | constexpr std::array<PadButton, 12> PadButtonArray{ | ||
| 14 | PadButton::PAD_BUTTON_LEFT, PadButton::PAD_BUTTON_RIGHT, PadButton::PAD_BUTTON_DOWN, | ||
| 15 | PadButton::PAD_BUTTON_UP, PadButton::PAD_TRIGGER_Z, PadButton::PAD_TRIGGER_R, | ||
| 16 | PadButton::PAD_TRIGGER_L, PadButton::PAD_BUTTON_A, PadButton::PAD_BUTTON_B, | ||
| 17 | PadButton::PAD_BUTTON_X, PadButton::PAD_BUTTON_Y, PadButton::PAD_BUTTON_START, | ||
| 18 | }; | ||
| 19 | |||
| 20 | Adapter::Adapter() { | ||
| 21 | if (usb_adapter_handle != nullptr) { | ||
| 22 | return; | ||
| 23 | } | ||
| 24 | LOG_INFO(Input, "GC Adapter Initialization started"); | ||
| 25 | |||
| 26 | current_status = NO_ADAPTER_DETECTED; | ||
| 27 | libusb_init(&libusb_ctx); | ||
| 28 | |||
| 29 | StartScanThread(); | ||
| 30 | } | ||
| 31 | |||
| 32 | GCPadStatus Adapter::GetPadStatus(int port, const std::array<u8, 37>& adapter_payload) { | ||
| 33 | GCPadStatus pad = {}; | ||
| 34 | bool get_origin = false; | ||
| 35 | |||
| 36 | ControllerTypes type = ControllerTypes(adapter_payload[1 + (9 * port)] >> 4); | ||
| 37 | if (type != ControllerTypes::None) { | ||
| 38 | get_origin = true; | ||
| 39 | } | ||
| 40 | |||
| 41 | adapter_controllers_status[port] = type; | ||
| 42 | |||
| 43 | static constexpr std::array<PadButton, 8> b1_buttons{ | ||
| 44 | PadButton::PAD_BUTTON_A, PadButton::PAD_BUTTON_B, PadButton::PAD_BUTTON_X, | ||
| 45 | PadButton::PAD_BUTTON_Y, PadButton::PAD_BUTTON_LEFT, PadButton::PAD_BUTTON_RIGHT, | ||
| 46 | PadButton::PAD_BUTTON_DOWN, PadButton::PAD_BUTTON_UP, | ||
| 47 | }; | ||
| 48 | |||
| 49 | static constexpr std::array<PadButton, 4> b2_buttons{ | ||
| 50 | PadButton::PAD_BUTTON_START, | ||
| 51 | PadButton::PAD_TRIGGER_Z, | ||
| 52 | PadButton::PAD_TRIGGER_R, | ||
| 53 | PadButton::PAD_TRIGGER_L, | ||
| 54 | }; | ||
| 55 | |||
| 56 | if (adapter_controllers_status[port] != ControllerTypes::None) { | ||
| 57 | const u8 b1 = adapter_payload[1 + (9 * port) + 1]; | ||
| 58 | const u8 b2 = adapter_payload[1 + (9 * port) + 2]; | ||
| 59 | |||
| 60 | for (std::size_t i = 0; i < b1_buttons.size(); ++i) { | ||
| 61 | if ((b1 & (1U << i)) != 0) { | ||
| 62 | pad.button |= static_cast<u16>(b1_buttons[i]); | ||
| 63 | } | ||
| 64 | } | ||
| 65 | |||
| 66 | for (std::size_t j = 0; j < b2_buttons.size(); ++j) { | ||
| 67 | if ((b2 & (1U << j)) != 0) { | ||
| 68 | pad.button |= static_cast<u16>(b2_buttons[j]); | ||
| 69 | } | ||
| 70 | } | ||
| 71 | |||
| 72 | if (get_origin) { | ||
| 73 | pad.button |= PAD_GET_ORIGIN; | ||
| 74 | } | ||
| 75 | |||
| 76 | pad.stick_x = adapter_payload[1 + (9 * port) + 3]; | ||
| 77 | pad.stick_y = adapter_payload[1 + (9 * port) + 4]; | ||
| 78 | pad.substick_x = adapter_payload[1 + (9 * port) + 5]; | ||
| 79 | pad.substick_y = adapter_payload[1 + (9 * port) + 6]; | ||
| 80 | pad.trigger_left = adapter_payload[1 + (9 * port) + 7]; | ||
| 81 | pad.trigger_right = adapter_payload[1 + (9 * port) + 8]; | ||
| 82 | } | ||
| 83 | return pad; | ||
| 84 | } | ||
| 85 | |||
| 86 | void Adapter::PadToState(const GCPadStatus& pad, GCState& state) { | ||
| 87 | for (const auto& button : PadButtonArray) { | ||
| 88 | const u16 button_value = static_cast<u16>(button); | ||
| 89 | state.buttons.insert_or_assign(button_value, pad.button & button_value); | ||
| 90 | } | ||
| 91 | |||
| 92 | state.axes.insert_or_assign(static_cast<u8>(PadAxes::StickX), pad.stick_x); | ||
| 93 | state.axes.insert_or_assign(static_cast<u8>(PadAxes::StickY), pad.stick_y); | ||
| 94 | state.axes.insert_or_assign(static_cast<u8>(PadAxes::SubstickX), pad.substick_x); | ||
| 95 | state.axes.insert_or_assign(static_cast<u8>(PadAxes::SubstickY), pad.substick_y); | ||
| 96 | state.axes.insert_or_assign(static_cast<u8>(PadAxes::TriggerLeft), pad.trigger_left); | ||
| 97 | state.axes.insert_or_assign(static_cast<u8>(PadAxes::TriggerRight), pad.trigger_right); | ||
| 98 | } | ||
| 99 | |||
| 100 | void Adapter::Read() { | ||
| 101 | LOG_DEBUG(Input, "GC Adapter Read() thread started"); | ||
| 102 | |||
| 103 | int payload_size_in, payload_size_copy; | ||
| 104 | std::array<u8, 37> adapter_payload; | ||
| 105 | std::array<u8, 37> adapter_payload_copy; | ||
| 106 | std::array<GCPadStatus, 4> pads; | ||
| 107 | |||
| 108 | while (adapter_thread_running) { | ||
| 109 | libusb_interrupt_transfer(usb_adapter_handle, input_endpoint, adapter_payload.data(), | ||
| 110 | sizeof(adapter_payload), &payload_size_in, 16); | ||
| 111 | payload_size_copy = 0; | ||
| 112 | // this mutex might be redundant? | ||
| 113 | { | ||
| 114 | std::lock_guard<std::mutex> lk(s_mutex); | ||
| 115 | std::copy(std::begin(adapter_payload), std::end(adapter_payload), | ||
| 116 | std::begin(adapter_payload_copy)); | ||
| 117 | payload_size_copy = payload_size_in; | ||
| 118 | } | ||
| 119 | |||
| 120 | if (payload_size_copy != sizeof(adapter_payload_copy) || | ||
| 121 | adapter_payload_copy[0] != LIBUSB_DT_HID) { | ||
| 122 | LOG_ERROR(Input, "error reading payload (size: {}, type: {:02x})", payload_size_copy, | ||
| 123 | adapter_payload_copy[0]); | ||
| 124 | adapter_thread_running = false; // error reading from adapter, stop reading. | ||
| 125 | break; | ||
| 126 | } | ||
| 127 | for (std::size_t port = 0; port < pads.size(); ++port) { | ||
| 128 | pads[port] = GetPadStatus(port, adapter_payload_copy); | ||
| 129 | if (DeviceConnected(port) && configuring) { | ||
| 130 | if (pads[port].button != PAD_GET_ORIGIN) { | ||
| 131 | pad_queue[port].Push(pads[port]); | ||
| 132 | } | ||
| 133 | |||
| 134 | // Accounting for a threshold here because of some controller variance | ||
| 135 | if (pads[port].stick_x > pads[port].MAIN_STICK_CENTER_X + pads[port].THRESHOLD || | ||
| 136 | pads[port].stick_x < pads[port].MAIN_STICK_CENTER_X - pads[port].THRESHOLD) { | ||
| 137 | pads[port].axis = GCAdapter::PadAxes::StickX; | ||
| 138 | pads[port].axis_value = pads[port].stick_x; | ||
| 139 | pad_queue[port].Push(pads[port]); | ||
| 140 | } | ||
| 141 | if (pads[port].stick_y > pads[port].MAIN_STICK_CENTER_Y + pads[port].THRESHOLD || | ||
| 142 | pads[port].stick_y < pads[port].MAIN_STICK_CENTER_Y - pads[port].THRESHOLD) { | ||
| 143 | pads[port].axis = GCAdapter::PadAxes::StickY; | ||
| 144 | pads[port].axis_value = pads[port].stick_y; | ||
| 145 | pad_queue[port].Push(pads[port]); | ||
| 146 | } | ||
| 147 | if (pads[port].substick_x > pads[port].C_STICK_CENTER_X + pads[port].THRESHOLD || | ||
| 148 | pads[port].substick_x < pads[port].C_STICK_CENTER_X - pads[port].THRESHOLD) { | ||
| 149 | pads[port].axis = GCAdapter::PadAxes::SubstickX; | ||
| 150 | pads[port].axis_value = pads[port].substick_x; | ||
| 151 | pad_queue[port].Push(pads[port]); | ||
| 152 | } | ||
| 153 | if (pads[port].substick_y > pads[port].C_STICK_CENTER_Y + pads[port].THRESHOLD || | ||
| 154 | pads[port].substick_y < pads[port].C_STICK_CENTER_Y - pads[port].THRESHOLD) { | ||
| 155 | pads[port].axis = GCAdapter::PadAxes::SubstickY; | ||
| 156 | pads[port].axis_value = pads[port].substick_y; | ||
| 157 | pad_queue[port].Push(pads[port]); | ||
| 158 | } | ||
| 159 | if (pads[port].trigger_left > pads[port].TRIGGER_THRESHOLD) { | ||
| 160 | pads[port].axis = GCAdapter::PadAxes::TriggerLeft; | ||
| 161 | pads[port].axis_value = pads[port].trigger_left; | ||
| 162 | pad_queue[port].Push(pads[port]); | ||
| 163 | } | ||
| 164 | if (pads[port].trigger_right > pads[port].TRIGGER_THRESHOLD) { | ||
| 165 | pads[port].axis = GCAdapter::PadAxes::TriggerRight; | ||
| 166 | pads[port].axis_value = pads[port].trigger_right; | ||
| 167 | pad_queue[port].Push(pads[port]); | ||
| 168 | } | ||
| 169 | } | ||
| 170 | PadToState(pads[port], state[port]); | ||
| 171 | } | ||
| 172 | std::this_thread::yield(); | ||
| 173 | } | ||
| 174 | } | ||
| 175 | |||
| 176 | void Adapter::ScanThreadFunc() { | ||
| 177 | LOG_INFO(Input, "GC Adapter scanning thread started"); | ||
| 178 | |||
| 179 | while (detect_thread_running) { | ||
| 180 | if (usb_adapter_handle == nullptr) { | ||
| 181 | std::lock_guard<std::mutex> lk(initialization_mutex); | ||
| 182 | Setup(); | ||
| 183 | } | ||
| 184 | std::this_thread::sleep_for(std::chrono::milliseconds(500)); | ||
| 185 | } | ||
| 186 | } | ||
| 187 | |||
| 188 | void Adapter::StartScanThread() { | ||
| 189 | if (detect_thread_running) { | ||
| 190 | return; | ||
| 191 | } | ||
| 192 | if (!libusb_ctx) { | ||
| 193 | return; | ||
| 194 | } | ||
| 195 | |||
| 196 | detect_thread_running = true; | ||
| 197 | detect_thread = std::thread([=] { ScanThreadFunc(); }); | ||
| 198 | } | ||
| 199 | |||
| 200 | void Adapter::StopScanThread() { | ||
| 201 | detect_thread_running = false; | ||
| 202 | detect_thread.join(); | ||
| 203 | } | ||
| 204 | |||
| 205 | void Adapter::Setup() { | ||
| 206 | // Reset the error status in case the adapter gets unplugged | ||
| 207 | if (current_status < 0) { | ||
| 208 | current_status = NO_ADAPTER_DETECTED; | ||
| 209 | } | ||
| 210 | |||
| 211 | adapter_controllers_status.fill(ControllerTypes::None); | ||
| 212 | |||
| 213 | // pointer to list of connected usb devices | ||
| 214 | libusb_device** devices; | ||
| 215 | |||
| 216 | // populate the list of devices, get the count | ||
| 217 | const std::size_t device_count = libusb_get_device_list(libusb_ctx, &devices); | ||
| 218 | |||
| 219 | for (std::size_t index = 0; index < device_count; ++index) { | ||
| 220 | if (CheckDeviceAccess(devices[index])) { | ||
| 221 | // GC Adapter found and accessible, registering it | ||
| 222 | GetGCEndpoint(devices[index]); | ||
| 223 | break; | ||
| 224 | } | ||
| 225 | } | ||
| 226 | } | ||
| 227 | |||
| 228 | bool Adapter::CheckDeviceAccess(libusb_device* device) { | ||
| 229 | libusb_device_descriptor desc; | ||
| 230 | const int get_descriptor_error = libusb_get_device_descriptor(device, &desc); | ||
| 231 | if (get_descriptor_error) { | ||
| 232 | // could not acquire the descriptor, no point in trying to use it. | ||
| 233 | LOG_ERROR(Input, "libusb_get_device_descriptor failed with error: {}", | ||
| 234 | get_descriptor_error); | ||
| 235 | return false; | ||
| 236 | } | ||
| 237 | |||
| 238 | if (desc.idVendor != 0x057e || desc.idProduct != 0x0337) { | ||
| 239 | // This isn't the device we are looking for. | ||
| 240 | return false; | ||
| 241 | } | ||
| 242 | const int open_error = libusb_open(device, &usb_adapter_handle); | ||
| 243 | |||
| 244 | if (open_error == LIBUSB_ERROR_ACCESS) { | ||
| 245 | LOG_ERROR(Input, "Yuzu can not gain access to this device: ID {:04X}:{:04X}.", | ||
| 246 | desc.idVendor, desc.idProduct); | ||
| 247 | return false; | ||
| 248 | } | ||
| 249 | if (open_error) { | ||
| 250 | LOG_ERROR(Input, "libusb_open failed to open device with error = {}", open_error); | ||
| 251 | return false; | ||
| 252 | } | ||
| 253 | |||
| 254 | int kernel_driver_error = libusb_kernel_driver_active(usb_adapter_handle, 0); | ||
| 255 | if (kernel_driver_error == 1) { | ||
| 256 | kernel_driver_error = libusb_detach_kernel_driver(usb_adapter_handle, 0); | ||
| 257 | if (kernel_driver_error != 0 && kernel_driver_error != LIBUSB_ERROR_NOT_SUPPORTED) { | ||
| 258 | LOG_ERROR(Input, "libusb_detach_kernel_driver failed with error = {}", | ||
| 259 | kernel_driver_error); | ||
| 260 | } | ||
| 261 | } | ||
| 262 | |||
| 263 | if (kernel_driver_error && kernel_driver_error != LIBUSB_ERROR_NOT_SUPPORTED) { | ||
| 264 | libusb_close(usb_adapter_handle); | ||
| 265 | usb_adapter_handle = nullptr; | ||
| 266 | return false; | ||
| 267 | } | ||
| 268 | |||
| 269 | const int interface_claim_error = libusb_claim_interface(usb_adapter_handle, 0); | ||
| 270 | if (interface_claim_error) { | ||
| 271 | LOG_ERROR(Input, "libusb_claim_interface failed with error = {}", interface_claim_error); | ||
| 272 | libusb_close(usb_adapter_handle); | ||
| 273 | usb_adapter_handle = nullptr; | ||
| 274 | return false; | ||
| 275 | } | ||
| 276 | |||
| 277 | return true; | ||
| 278 | } | ||
| 279 | |||
| 280 | void Adapter::GetGCEndpoint(libusb_device* device) { | ||
| 281 | libusb_config_descriptor* config = nullptr; | ||
| 282 | libusb_get_config_descriptor(device, 0, &config); | ||
| 283 | for (u8 ic = 0; ic < config->bNumInterfaces; ic++) { | ||
| 284 | const libusb_interface* interfaceContainer = &config->interface[ic]; | ||
| 285 | for (int i = 0; i < interfaceContainer->num_altsetting; i++) { | ||
| 286 | const libusb_interface_descriptor* interface = &interfaceContainer->altsetting[i]; | ||
| 287 | for (u8 e = 0; e < interface->bNumEndpoints; e++) { | ||
| 288 | const libusb_endpoint_descriptor* endpoint = &interface->endpoint[e]; | ||
| 289 | if (endpoint->bEndpointAddress & LIBUSB_ENDPOINT_IN) { | ||
| 290 | input_endpoint = endpoint->bEndpointAddress; | ||
| 291 | } else { | ||
| 292 | output_endpoint = endpoint->bEndpointAddress; | ||
| 293 | } | ||
| 294 | } | ||
| 295 | } | ||
| 296 | } | ||
| 297 | // This transfer seems to be responsible for clearing the state of the adapter | ||
| 298 | // Used to clear the "busy" state of when the device is unexpectedly unplugged | ||
| 299 | unsigned char clear_payload = 0x13; | ||
| 300 | libusb_interrupt_transfer(usb_adapter_handle, output_endpoint, &clear_payload, | ||
| 301 | sizeof(clear_payload), nullptr, 16); | ||
| 302 | |||
| 303 | adapter_thread_running = true; | ||
| 304 | current_status = ADAPTER_DETECTED; | ||
| 305 | adapter_input_thread = std::thread([=] { Read(); }); // Read input | ||
| 306 | } | ||
| 307 | |||
| 308 | Adapter::~Adapter() { | ||
| 309 | StopScanThread(); | ||
| 310 | Reset(); | ||
| 311 | } | ||
| 312 | |||
| 313 | void Adapter::Reset() { | ||
| 314 | std::unique_lock<std::mutex> lock(initialization_mutex, std::defer_lock); | ||
| 315 | if (!lock.try_lock()) { | ||
| 316 | return; | ||
| 317 | } | ||
| 318 | if (current_status != ADAPTER_DETECTED) { | ||
| 319 | return; | ||
| 320 | } | ||
| 321 | |||
| 322 | if (adapter_thread_running) { | ||
| 323 | adapter_thread_running = false; | ||
| 324 | } | ||
| 325 | adapter_input_thread.join(); | ||
| 326 | |||
| 327 | adapter_controllers_status.fill(ControllerTypes::None); | ||
| 328 | current_status = NO_ADAPTER_DETECTED; | ||
| 329 | |||
| 330 | if (usb_adapter_handle) { | ||
| 331 | libusb_release_interface(usb_adapter_handle, 1); | ||
| 332 | libusb_close(usb_adapter_handle); | ||
| 333 | usb_adapter_handle = nullptr; | ||
| 334 | } | ||
| 335 | |||
| 336 | if (libusb_ctx) { | ||
| 337 | libusb_exit(libusb_ctx); | ||
| 338 | } | ||
| 339 | } | ||
| 340 | |||
| 341 | bool Adapter::DeviceConnected(int port) { | ||
| 342 | return adapter_controllers_status[port] != ControllerTypes::None; | ||
| 343 | } | ||
| 344 | |||
| 345 | void Adapter::ResetDeviceType(int port) { | ||
| 346 | adapter_controllers_status[port] = ControllerTypes::None; | ||
| 347 | } | ||
| 348 | |||
| 349 | void Adapter::BeginConfiguration() { | ||
| 350 | for (auto& pq : pad_queue) { | ||
| 351 | pq.Clear(); | ||
| 352 | } | ||
| 353 | configuring = true; | ||
| 354 | } | ||
| 355 | |||
| 356 | void Adapter::EndConfiguration() { | ||
| 357 | for (auto& pq : pad_queue) { | ||
| 358 | pq.Clear(); | ||
| 359 | } | ||
| 360 | configuring = false; | ||
| 361 | } | ||
| 362 | |||
| 363 | std::array<Common::SPSCQueue<GCPadStatus>, 4>& Adapter::GetPadQueue() { | ||
| 364 | return pad_queue; | ||
| 365 | } | ||
| 366 | |||
| 367 | const std::array<Common::SPSCQueue<GCPadStatus>, 4>& Adapter::GetPadQueue() const { | ||
| 368 | return pad_queue; | ||
| 369 | } | ||
| 370 | |||
| 371 | std::array<GCState, 4>& Adapter::GetPadState() { | ||
| 372 | return state; | ||
| 373 | } | ||
| 374 | |||
| 375 | const std::array<GCState, 4>& Adapter::GetPadState() const { | ||
| 376 | return state; | ||
| 377 | } | ||
| 378 | |||
| 379 | } // namespace GCAdapter | ||
diff --git a/src/input_common/gcadapter/gc_adapter.h b/src/input_common/gcadapter/gc_adapter.h new file mode 100644 index 000000000..0ea6263eb --- /dev/null +++ b/src/input_common/gcadapter/gc_adapter.h | |||
| @@ -0,0 +1,160 @@ | |||
| 1 | // Copyright 2014 Dolphin Emulator Project | ||
| 2 | // Licensed under GPLv2+ | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | #include <algorithm> | ||
| 7 | #include <functional> | ||
| 8 | #include <mutex> | ||
| 9 | #include <thread> | ||
| 10 | #include <libusb.h> | ||
| 11 | #include "common/common_types.h" | ||
| 12 | #include "common/threadsafe_queue.h" | ||
| 13 | |||
| 14 | namespace GCAdapter { | ||
| 15 | |||
| 16 | enum { | ||
| 17 | PAD_USE_ORIGIN = 0x0080, | ||
| 18 | PAD_GET_ORIGIN = 0x2000, | ||
| 19 | PAD_ERR_STATUS = 0x8000, | ||
| 20 | }; | ||
| 21 | |||
| 22 | enum class PadButton { | ||
| 23 | PAD_BUTTON_LEFT = 0x0001, | ||
| 24 | PAD_BUTTON_RIGHT = 0x0002, | ||
| 25 | PAD_BUTTON_DOWN = 0x0004, | ||
| 26 | PAD_BUTTON_UP = 0x0008, | ||
| 27 | PAD_TRIGGER_Z = 0x0010, | ||
| 28 | PAD_TRIGGER_R = 0x0020, | ||
| 29 | PAD_TRIGGER_L = 0x0040, | ||
| 30 | PAD_BUTTON_A = 0x0100, | ||
| 31 | PAD_BUTTON_B = 0x0200, | ||
| 32 | PAD_BUTTON_X = 0x0400, | ||
| 33 | PAD_BUTTON_Y = 0x0800, | ||
| 34 | PAD_BUTTON_START = 0x1000, | ||
| 35 | // Below is for compatibility with "AxisButton" type | ||
| 36 | PAD_STICK = 0x2000, | ||
| 37 | }; | ||
| 38 | |||
| 39 | extern const std::array<PadButton, 12> PadButtonArray; | ||
| 40 | |||
| 41 | enum class PadAxes : u8 { | ||
| 42 | StickX, | ||
| 43 | StickY, | ||
| 44 | SubstickX, | ||
| 45 | SubstickY, | ||
| 46 | TriggerLeft, | ||
| 47 | TriggerRight, | ||
| 48 | Undefined, | ||
| 49 | }; | ||
| 50 | |||
| 51 | struct GCPadStatus { | ||
| 52 | u16 button{}; // Or-ed PAD_BUTTON_* and PAD_TRIGGER_* bits | ||
| 53 | u8 stick_x{}; // 0 <= stick_x <= 255 | ||
| 54 | u8 stick_y{}; // 0 <= stick_y <= 255 | ||
| 55 | u8 substick_x{}; // 0 <= substick_x <= 255 | ||
| 56 | u8 substick_y{}; // 0 <= substick_y <= 255 | ||
| 57 | u8 trigger_left{}; // 0 <= trigger_left <= 255 | ||
| 58 | u8 trigger_right{}; // 0 <= trigger_right <= 255 | ||
| 59 | |||
| 60 | static constexpr u8 MAIN_STICK_CENTER_X = 0x80; | ||
| 61 | static constexpr u8 MAIN_STICK_CENTER_Y = 0x80; | ||
| 62 | static constexpr u8 MAIN_STICK_RADIUS = 0x7f; | ||
| 63 | static constexpr u8 C_STICK_CENTER_X = 0x80; | ||
| 64 | static constexpr u8 C_STICK_CENTER_Y = 0x80; | ||
| 65 | static constexpr u8 C_STICK_RADIUS = 0x7f; | ||
| 66 | static constexpr u8 THRESHOLD = 10; | ||
| 67 | |||
| 68 | // 256/4, at least a quarter press to count as a press. For polling mostly | ||
| 69 | static constexpr u8 TRIGGER_THRESHOLD = 64; | ||
| 70 | |||
| 71 | u8 port{}; | ||
| 72 | PadAxes axis{PadAxes::Undefined}; | ||
| 73 | u8 axis_value{255}; | ||
| 74 | }; | ||
| 75 | |||
| 76 | struct GCState { | ||
| 77 | std::unordered_map<int, bool> buttons; | ||
| 78 | std::unordered_map<int, u16> axes; | ||
| 79 | }; | ||
| 80 | |||
| 81 | enum class ControllerTypes { None, Wired, Wireless }; | ||
| 82 | |||
| 83 | enum { | ||
| 84 | NO_ADAPTER_DETECTED = 0, | ||
| 85 | ADAPTER_DETECTED = 1, | ||
| 86 | }; | ||
| 87 | |||
| 88 | class Adapter { | ||
| 89 | public: | ||
| 90 | /// Initialize the GC Adapter capture and read sequence | ||
| 91 | Adapter(); | ||
| 92 | |||
| 93 | /// Close the adapter read thread and release the adapter | ||
| 94 | ~Adapter(); | ||
| 95 | /// Used for polling | ||
| 96 | void BeginConfiguration(); | ||
| 97 | void EndConfiguration(); | ||
| 98 | |||
| 99 | std::array<Common::SPSCQueue<GCPadStatus>, 4>& GetPadQueue(); | ||
| 100 | const std::array<Common::SPSCQueue<GCPadStatus>, 4>& GetPadQueue() const; | ||
| 101 | |||
| 102 | std::array<GCState, 4>& GetPadState(); | ||
| 103 | const std::array<GCState, 4>& GetPadState() const; | ||
| 104 | |||
| 105 | private: | ||
| 106 | GCPadStatus GetPadStatus(int port, const std::array<u8, 37>& adapter_payload); | ||
| 107 | |||
| 108 | void PadToState(const GCPadStatus& pad, GCState& state); | ||
| 109 | |||
| 110 | void Read(); | ||
| 111 | void ScanThreadFunc(); | ||
| 112 | /// Begin scanning for the GC Adapter. | ||
| 113 | void StartScanThread(); | ||
| 114 | |||
| 115 | /// Stop scanning for the adapter | ||
| 116 | void StopScanThread(); | ||
| 117 | |||
| 118 | /// Returns true if there is a device connected to port | ||
| 119 | bool DeviceConnected(int port); | ||
| 120 | |||
| 121 | /// Resets status of device connected to port | ||
| 122 | void ResetDeviceType(int port); | ||
| 123 | |||
| 124 | /// Returns true if we successfully gain access to GC Adapter | ||
| 125 | bool CheckDeviceAccess(libusb_device* device); | ||
| 126 | |||
| 127 | /// Captures GC Adapter endpoint address, | ||
| 128 | void GetGCEndpoint(libusb_device* device); | ||
| 129 | |||
| 130 | /// For shutting down, clear all data, join all threads, release usb | ||
| 131 | void Reset(); | ||
| 132 | |||
| 133 | /// For use in initialization, querying devices to find the adapter | ||
| 134 | void Setup(); | ||
| 135 | |||
| 136 | int current_status = NO_ADAPTER_DETECTED; | ||
| 137 | libusb_device_handle* usb_adapter_handle = nullptr; | ||
| 138 | std::array<ControllerTypes, 4> adapter_controllers_status{}; | ||
| 139 | |||
| 140 | std::mutex s_mutex; | ||
| 141 | |||
| 142 | std::thread adapter_input_thread; | ||
| 143 | bool adapter_thread_running; | ||
| 144 | |||
| 145 | std::mutex initialization_mutex; | ||
| 146 | std::thread detect_thread; | ||
| 147 | bool detect_thread_running = false; | ||
| 148 | |||
| 149 | libusb_context* libusb_ctx; | ||
| 150 | |||
| 151 | u8 input_endpoint = 0; | ||
| 152 | u8 output_endpoint = 0; | ||
| 153 | |||
| 154 | bool configuring = false; | ||
| 155 | |||
| 156 | std::array<Common::SPSCQueue<GCPadStatus>, 4> pad_queue; | ||
| 157 | std::array<GCState, 4> state; | ||
| 158 | }; | ||
| 159 | |||
| 160 | } // namespace GCAdapter | ||
diff --git a/src/input_common/gcadapter/gc_poller.cpp b/src/input_common/gcadapter/gc_poller.cpp new file mode 100644 index 000000000..385ce8430 --- /dev/null +++ b/src/input_common/gcadapter/gc_poller.cpp | |||
| @@ -0,0 +1,272 @@ | |||
| 1 | // Copyright 2020 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include <atomic> | ||
| 6 | #include <list> | ||
| 7 | #include <mutex> | ||
| 8 | #include <utility> | ||
| 9 | #include "common/threadsafe_queue.h" | ||
| 10 | #include "input_common/gcadapter/gc_adapter.h" | ||
| 11 | #include "input_common/gcadapter/gc_poller.h" | ||
| 12 | |||
| 13 | namespace InputCommon { | ||
| 14 | |||
| 15 | class GCButton final : public Input::ButtonDevice { | ||
| 16 | public: | ||
| 17 | explicit GCButton(int port_, int button_, GCAdapter::Adapter* adapter) | ||
| 18 | : port(port_), button(button_), gcadapter(adapter) {} | ||
| 19 | |||
| 20 | ~GCButton() override; | ||
| 21 | |||
| 22 | bool GetStatus() const override { | ||
| 23 | return gcadapter->GetPadState()[port].buttons.at(button); | ||
| 24 | } | ||
| 25 | |||
| 26 | private: | ||
| 27 | const int port; | ||
| 28 | const int button; | ||
| 29 | GCAdapter::Adapter* gcadapter; | ||
| 30 | }; | ||
| 31 | |||
| 32 | class GCAxisButton final : public Input::ButtonDevice { | ||
| 33 | public: | ||
| 34 | explicit GCAxisButton(int port_, int axis_, float threshold_, bool trigger_if_greater_, | ||
| 35 | GCAdapter::Adapter* adapter) | ||
| 36 | : port(port_), axis(axis_), threshold(threshold_), trigger_if_greater(trigger_if_greater_), | ||
| 37 | gcadapter(adapter) { | ||
| 38 | // L/R triggers range is only in positive direction beginning near 0 | ||
| 39 | // 0.0 threshold equates to near half trigger press, but threshold accounts for variability. | ||
| 40 | if (axis > 3) { | ||
| 41 | threshold *= -0.5; | ||
| 42 | } | ||
| 43 | } | ||
| 44 | |||
| 45 | bool GetStatus() const override { | ||
| 46 | const float axis_value = (gcadapter->GetPadState()[port].axes.at(axis) - 128.0f) / 128.0f; | ||
| 47 | if (trigger_if_greater) { | ||
| 48 | // TODO: Might be worthwile to set a slider for the trigger threshold. It is currently | ||
| 49 | // always set to 0.5 in configure_input_player.cpp ZL/ZR HandleClick | ||
| 50 | return axis_value > threshold; | ||
| 51 | } | ||
| 52 | return axis_value < -threshold; | ||
| 53 | } | ||
| 54 | |||
| 55 | private: | ||
| 56 | const int port; | ||
| 57 | const int axis; | ||
| 58 | float threshold; | ||
| 59 | bool trigger_if_greater; | ||
| 60 | GCAdapter::Adapter* gcadapter; | ||
| 61 | }; | ||
| 62 | |||
| 63 | GCButtonFactory::GCButtonFactory(std::shared_ptr<GCAdapter::Adapter> adapter_) | ||
| 64 | : adapter(std::move(adapter_)) {} | ||
| 65 | |||
| 66 | GCButton::~GCButton() = default; | ||
| 67 | |||
| 68 | std::unique_ptr<Input::ButtonDevice> GCButtonFactory::Create(const Common::ParamPackage& params) { | ||
| 69 | const int button_id = params.Get("button", 0); | ||
| 70 | const int port = params.Get("port", 0); | ||
| 71 | |||
| 72 | constexpr int PAD_STICK_ID = static_cast<u16>(GCAdapter::PadButton::PAD_STICK); | ||
| 73 | |||
| 74 | // button is not an axis/stick button | ||
| 75 | if (button_id != PAD_STICK_ID) { | ||
| 76 | auto button = std::make_unique<GCButton>(port, button_id, adapter.get()); | ||
| 77 | return std::move(button); | ||
| 78 | } | ||
| 79 | |||
| 80 | // For Axis buttons, used by the binary sticks. | ||
| 81 | if (button_id == PAD_STICK_ID) { | ||
| 82 | const int axis = params.Get("axis", 0); | ||
| 83 | const float threshold = params.Get("threshold", 0.25f); | ||
| 84 | const std::string direction_name = params.Get("direction", ""); | ||
| 85 | bool trigger_if_greater; | ||
| 86 | if (direction_name == "+") { | ||
| 87 | trigger_if_greater = true; | ||
| 88 | } else if (direction_name == "-") { | ||
| 89 | trigger_if_greater = false; | ||
| 90 | } else { | ||
| 91 | trigger_if_greater = true; | ||
| 92 | LOG_ERROR(Input, "Unknown direction {}", direction_name); | ||
| 93 | } | ||
| 94 | return std::make_unique<GCAxisButton>(port, axis, threshold, trigger_if_greater, | ||
| 95 | adapter.get()); | ||
| 96 | } | ||
| 97 | } | ||
| 98 | |||
| 99 | Common::ParamPackage GCButtonFactory::GetNextInput() { | ||
| 100 | Common::ParamPackage params; | ||
| 101 | GCAdapter::GCPadStatus pad; | ||
| 102 | auto& queue = adapter->GetPadQueue(); | ||
| 103 | for (std::size_t port = 0; port < queue.size(); ++port) { | ||
| 104 | while (queue[port].Pop(pad)) { | ||
| 105 | // This while loop will break on the earliest detected button | ||
| 106 | params.Set("engine", "gcpad"); | ||
| 107 | params.Set("port", static_cast<int>(port)); | ||
| 108 | for (const auto& button : GCAdapter::PadButtonArray) { | ||
| 109 | const u16 button_value = static_cast<u16>(button); | ||
| 110 | if (pad.button & button_value) { | ||
| 111 | params.Set("button", button_value); | ||
| 112 | break; | ||
| 113 | } | ||
| 114 | } | ||
| 115 | |||
| 116 | // For Axis button implementation | ||
| 117 | if (pad.axis != GCAdapter::PadAxes::Undefined) { | ||
| 118 | params.Set("axis", static_cast<u8>(pad.axis)); | ||
| 119 | params.Set("button", static_cast<u16>(GCAdapter::PadButton::PAD_STICK)); | ||
| 120 | if (pad.axis_value > 128) { | ||
| 121 | params.Set("direction", "+"); | ||
| 122 | params.Set("threshold", "0.25"); | ||
| 123 | } else { | ||
| 124 | params.Set("direction", "-"); | ||
| 125 | params.Set("threshold", "-0.25"); | ||
| 126 | } | ||
| 127 | break; | ||
| 128 | } | ||
| 129 | } | ||
| 130 | } | ||
| 131 | return params; | ||
| 132 | } | ||
| 133 | |||
| 134 | void GCButtonFactory::BeginConfiguration() { | ||
| 135 | polling = true; | ||
| 136 | adapter->BeginConfiguration(); | ||
| 137 | } | ||
| 138 | |||
| 139 | void GCButtonFactory::EndConfiguration() { | ||
| 140 | polling = false; | ||
| 141 | adapter->EndConfiguration(); | ||
| 142 | } | ||
| 143 | |||
| 144 | class GCAnalog final : public Input::AnalogDevice { | ||
| 145 | public: | ||
| 146 | GCAnalog(int port_, int axis_x_, int axis_y_, float deadzone_, GCAdapter::Adapter* adapter) | ||
| 147 | : port(port_), axis_x(axis_x_), axis_y(axis_y_), deadzone(deadzone_), gcadapter(adapter) {} | ||
| 148 | |||
| 149 | float GetAxis(int axis) const { | ||
| 150 | std::lock_guard lock{mutex}; | ||
| 151 | // division is not by a perfect 128 to account for some variance in center location | ||
| 152 | // e.g. my device idled at 131 in X, 120 in Y, and full range of motion was in range | ||
| 153 | // [20-230] | ||
| 154 | return (gcadapter->GetPadState()[port].axes.at(axis) - 128.0f) / 95.0f; | ||
| 155 | } | ||
| 156 | |||
| 157 | std::pair<float, float> GetAnalog(int axis_x, int axis_y) const { | ||
| 158 | float x = GetAxis(axis_x); | ||
| 159 | float y = GetAxis(axis_y); | ||
| 160 | |||
| 161 | // Make sure the coordinates are in the unit circle, | ||
| 162 | // otherwise normalize it. | ||
| 163 | float r = x * x + y * y; | ||
| 164 | if (r > 1.0f) { | ||
| 165 | r = std::sqrt(r); | ||
| 166 | x /= r; | ||
| 167 | y /= r; | ||
| 168 | } | ||
| 169 | |||
| 170 | return {x, y}; | ||
| 171 | } | ||
| 172 | |||
| 173 | std::tuple<float, float> GetStatus() const override { | ||
| 174 | const auto [x, y] = GetAnalog(axis_x, axis_y); | ||
| 175 | const float r = std::sqrt((x * x) + (y * y)); | ||
| 176 | if (r > deadzone) { | ||
| 177 | return {x / r * (r - deadzone) / (1 - deadzone), | ||
| 178 | y / r * (r - deadzone) / (1 - deadzone)}; | ||
| 179 | } | ||
| 180 | return {0.0f, 0.0f}; | ||
| 181 | } | ||
| 182 | |||
| 183 | bool GetAnalogDirectionStatus(Input::AnalogDirection direction) const override { | ||
| 184 | const auto [x, y] = GetStatus(); | ||
| 185 | const float directional_deadzone = 0.4f; | ||
| 186 | switch (direction) { | ||
| 187 | case Input::AnalogDirection::RIGHT: | ||
| 188 | return x > directional_deadzone; | ||
| 189 | case Input::AnalogDirection::LEFT: | ||
| 190 | return x < -directional_deadzone; | ||
| 191 | case Input::AnalogDirection::UP: | ||
| 192 | return y > directional_deadzone; | ||
| 193 | case Input::AnalogDirection::DOWN: | ||
| 194 | return y < -directional_deadzone; | ||
| 195 | } | ||
| 196 | return false; | ||
| 197 | } | ||
| 198 | |||
| 199 | private: | ||
| 200 | const int port; | ||
| 201 | const int axis_x; | ||
| 202 | const int axis_y; | ||
| 203 | const float deadzone; | ||
| 204 | mutable std::mutex mutex; | ||
| 205 | GCAdapter::Adapter* gcadapter; | ||
| 206 | }; | ||
| 207 | |||
| 208 | /// An analog device factory that creates analog devices from GC Adapter | ||
| 209 | GCAnalogFactory::GCAnalogFactory(std::shared_ptr<GCAdapter::Adapter> adapter_) | ||
| 210 | : adapter(std::move(adapter_)) {} | ||
| 211 | |||
| 212 | /** | ||
| 213 | * Creates analog device from joystick axes | ||
| 214 | * @param params contains parameters for creating the device: | ||
| 215 | * - "port": the nth gcpad on the adapter | ||
| 216 | * - "axis_x": the index of the axis to be bind as x-axis | ||
| 217 | * - "axis_y": the index of the axis to be bind as y-axis | ||
| 218 | */ | ||
| 219 | std::unique_ptr<Input::AnalogDevice> GCAnalogFactory::Create(const Common::ParamPackage& params) { | ||
| 220 | const int port = params.Get("port", 0); | ||
| 221 | const int axis_x = params.Get("axis_x", 0); | ||
| 222 | const int axis_y = params.Get("axis_y", 1); | ||
| 223 | const float deadzone = std::clamp(params.Get("deadzone", 0.0f), 0.0f, .99f); | ||
| 224 | |||
| 225 | return std::make_unique<GCAnalog>(port, axis_x, axis_y, deadzone, adapter.get()); | ||
| 226 | } | ||
| 227 | |||
| 228 | void GCAnalogFactory::BeginConfiguration() { | ||
| 229 | polling = true; | ||
| 230 | adapter->BeginConfiguration(); | ||
| 231 | } | ||
| 232 | |||
| 233 | void GCAnalogFactory::EndConfiguration() { | ||
| 234 | polling = false; | ||
| 235 | adapter->EndConfiguration(); | ||
| 236 | } | ||
| 237 | |||
| 238 | Common::ParamPackage GCAnalogFactory::GetNextInput() { | ||
| 239 | GCAdapter::GCPadStatus pad; | ||
| 240 | auto& queue = adapter->GetPadQueue(); | ||
| 241 | for (std::size_t port = 0; port < queue.size(); ++port) { | ||
| 242 | while (queue[port].Pop(pad)) { | ||
| 243 | if (pad.axis == GCAdapter::PadAxes::Undefined || | ||
| 244 | std::abs((pad.axis_value - 128.0f) / 128.0f) < 0.1) { | ||
| 245 | continue; | ||
| 246 | } | ||
| 247 | // An analog device needs two axes, so we need to store the axis for later and wait for | ||
| 248 | // a second input event. The axes also must be from the same joystick. | ||
| 249 | const u8 axis = static_cast<u8>(pad.axis); | ||
| 250 | if (analog_x_axis == -1) { | ||
| 251 | analog_x_axis = axis; | ||
| 252 | controller_number = port; | ||
| 253 | } else if (analog_y_axis == -1 && analog_x_axis != axis && controller_number == port) { | ||
| 254 | analog_y_axis = axis; | ||
| 255 | } | ||
| 256 | } | ||
| 257 | } | ||
| 258 | Common::ParamPackage params; | ||
| 259 | if (analog_x_axis != -1 && analog_y_axis != -1) { | ||
| 260 | params.Set("engine", "gcpad"); | ||
| 261 | params.Set("port", controller_number); | ||
| 262 | params.Set("axis_x", analog_x_axis); | ||
| 263 | params.Set("axis_y", analog_y_axis); | ||
| 264 | analog_x_axis = -1; | ||
| 265 | analog_y_axis = -1; | ||
| 266 | controller_number = -1; | ||
| 267 | return params; | ||
| 268 | } | ||
| 269 | return params; | ||
| 270 | } | ||
| 271 | |||
| 272 | } // namespace InputCommon | ||
diff --git a/src/input_common/gcadapter/gc_poller.h b/src/input_common/gcadapter/gc_poller.h new file mode 100644 index 000000000..e96af7d51 --- /dev/null +++ b/src/input_common/gcadapter/gc_poller.h | |||
| @@ -0,0 +1,67 @@ | |||
| 1 | // Copyright 2020 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include <memory> | ||
| 8 | #include "core/frontend/input.h" | ||
| 9 | #include "input_common/gcadapter/gc_adapter.h" | ||
| 10 | |||
| 11 | namespace InputCommon { | ||
| 12 | |||
| 13 | /** | ||
| 14 | * A button device factory representing a gcpad. It receives gcpad events and forward them | ||
| 15 | * to all button devices it created. | ||
| 16 | */ | ||
| 17 | class GCButtonFactory final : public Input::Factory<Input::ButtonDevice> { | ||
| 18 | public: | ||
| 19 | explicit GCButtonFactory(std::shared_ptr<GCAdapter::Adapter> adapter_); | ||
| 20 | |||
| 21 | /** | ||
| 22 | * Creates a button device from a button press | ||
| 23 | * @param params contains parameters for creating the device: | ||
| 24 | * - "code": the code of the key to bind with the button | ||
| 25 | */ | ||
| 26 | std::unique_ptr<Input::ButtonDevice> Create(const Common::ParamPackage& params) override; | ||
| 27 | |||
| 28 | Common::ParamPackage GetNextInput(); | ||
| 29 | |||
| 30 | /// For device input configuration/polling | ||
| 31 | void BeginConfiguration(); | ||
| 32 | void EndConfiguration(); | ||
| 33 | |||
| 34 | bool IsPolling() const { | ||
| 35 | return polling; | ||
| 36 | } | ||
| 37 | |||
| 38 | private: | ||
| 39 | std::shared_ptr<GCAdapter::Adapter> adapter; | ||
| 40 | bool polling = false; | ||
| 41 | }; | ||
| 42 | |||
| 43 | /// An analog device factory that creates analog devices from GC Adapter | ||
| 44 | class GCAnalogFactory final : public Input::Factory<Input::AnalogDevice> { | ||
| 45 | public: | ||
| 46 | explicit GCAnalogFactory(std::shared_ptr<GCAdapter::Adapter> adapter_); | ||
| 47 | |||
| 48 | std::unique_ptr<Input::AnalogDevice> Create(const Common::ParamPackage& params) override; | ||
| 49 | Common::ParamPackage GetNextInput(); | ||
| 50 | |||
| 51 | /// For device input configuration/polling | ||
| 52 | void BeginConfiguration(); | ||
| 53 | void EndConfiguration(); | ||
| 54 | |||
| 55 | bool IsPolling() const { | ||
| 56 | return polling; | ||
| 57 | } | ||
| 58 | |||
| 59 | private: | ||
| 60 | std::shared_ptr<GCAdapter::Adapter> adapter; | ||
| 61 | int analog_x_axis = -1; | ||
| 62 | int analog_y_axis = -1; | ||
| 63 | int controller_number = -1; | ||
| 64 | bool polling = false; | ||
| 65 | }; | ||
| 66 | |||
| 67 | } // namespace InputCommon | ||
diff --git a/src/input_common/main.cpp b/src/input_common/main.cpp index 95e351e24..fd0af1019 100644 --- a/src/input_common/main.cpp +++ b/src/input_common/main.cpp | |||
| @@ -4,8 +4,11 @@ | |||
| 4 | 4 | ||
| 5 | #include <memory> | 5 | #include <memory> |
| 6 | #include <thread> | 6 | #include <thread> |
| 7 | #include <libusb.h> | ||
| 7 | #include "common/param_package.h" | 8 | #include "common/param_package.h" |
| 8 | #include "input_common/analog_from_button.h" | 9 | #include "input_common/analog_from_button.h" |
| 10 | #include "input_common/gcadapter/gc_adapter.h" | ||
| 11 | #include "input_common/gcadapter/gc_poller.h" | ||
| 9 | #include "input_common/keyboard.h" | 12 | #include "input_common/keyboard.h" |
| 10 | #include "input_common/main.h" | 13 | #include "input_common/main.h" |
| 11 | #include "input_common/motion_emu.h" | 14 | #include "input_common/motion_emu.h" |
| @@ -22,8 +25,16 @@ static std::shared_ptr<MotionEmu> motion_emu; | |||
| 22 | static std::unique_ptr<SDL::State> sdl; | 25 | static std::unique_ptr<SDL::State> sdl; |
| 23 | #endif | 26 | #endif |
| 24 | static std::unique_ptr<CemuhookUDP::State> udp; | 27 | static std::unique_ptr<CemuhookUDP::State> udp; |
| 28 | static std::shared_ptr<GCButtonFactory> gcbuttons; | ||
| 29 | static std::shared_ptr<GCAnalogFactory> gcanalog; | ||
| 25 | 30 | ||
| 26 | void Init() { | 31 | void Init() { |
| 32 | auto gcadapter = std::make_shared<GCAdapter::Adapter>(); | ||
| 33 | gcbuttons = std::make_shared<GCButtonFactory>(gcadapter); | ||
| 34 | Input::RegisterFactory<Input::ButtonDevice>("gcpad", gcbuttons); | ||
| 35 | gcanalog = std::make_shared<GCAnalogFactory>(gcadapter); | ||
| 36 | Input::RegisterFactory<Input::AnalogDevice>("gcpad", gcanalog); | ||
| 37 | |||
| 27 | keyboard = std::make_shared<Keyboard>(); | 38 | keyboard = std::make_shared<Keyboard>(); |
| 28 | Input::RegisterFactory<Input::ButtonDevice>("keyboard", keyboard); | 39 | Input::RegisterFactory<Input::ButtonDevice>("keyboard", keyboard); |
| 29 | Input::RegisterFactory<Input::AnalogDevice>("analog_from_button", | 40 | Input::RegisterFactory<Input::AnalogDevice>("analog_from_button", |
| @@ -48,6 +59,11 @@ void Shutdown() { | |||
| 48 | sdl.reset(); | 59 | sdl.reset(); |
| 49 | #endif | 60 | #endif |
| 50 | udp.reset(); | 61 | udp.reset(); |
| 62 | Input::UnregisterFactory<Input::ButtonDevice>("gcpad"); | ||
| 63 | Input::UnregisterFactory<Input::AnalogDevice>("gcpad"); | ||
| 64 | |||
| 65 | gcbuttons.reset(); | ||
| 66 | gcanalog.reset(); | ||
| 51 | } | 67 | } |
| 52 | 68 | ||
| 53 | Keyboard* GetKeyboard() { | 69 | Keyboard* GetKeyboard() { |
| @@ -58,6 +74,14 @@ MotionEmu* GetMotionEmu() { | |||
| 58 | return motion_emu.get(); | 74 | return motion_emu.get(); |
| 59 | } | 75 | } |
| 60 | 76 | ||
| 77 | GCButtonFactory* GetGCButtons() { | ||
| 78 | return gcbuttons.get(); | ||
| 79 | } | ||
| 80 | |||
| 81 | GCAnalogFactory* GetGCAnalogs() { | ||
| 82 | return gcanalog.get(); | ||
| 83 | } | ||
| 84 | |||
| 61 | std::string GenerateKeyboardParam(int key_code) { | 85 | std::string GenerateKeyboardParam(int key_code) { |
| 62 | Common::ParamPackage param{ | 86 | Common::ParamPackage param{ |
| 63 | {"engine", "keyboard"}, | 87 | {"engine", "keyboard"}, |
diff --git a/src/input_common/main.h b/src/input_common/main.h index 77a0ce90b..0e32856f6 100644 --- a/src/input_common/main.h +++ b/src/input_common/main.h | |||
| @@ -7,6 +7,7 @@ | |||
| 7 | #include <memory> | 7 | #include <memory> |
| 8 | #include <string> | 8 | #include <string> |
| 9 | #include <vector> | 9 | #include <vector> |
| 10 | #include "input_common/gcadapter/gc_poller.h" | ||
| 10 | 11 | ||
| 11 | namespace Common { | 12 | namespace Common { |
| 12 | class ParamPackage; | 13 | class ParamPackage; |
| @@ -30,6 +31,10 @@ class MotionEmu; | |||
| 30 | /// Gets the motion emulation factory. | 31 | /// Gets the motion emulation factory. |
| 31 | MotionEmu* GetMotionEmu(); | 32 | MotionEmu* GetMotionEmu(); |
| 32 | 33 | ||
| 34 | GCButtonFactory* GetGCButtons(); | ||
| 35 | |||
| 36 | GCAnalogFactory* GetGCAnalogs(); | ||
| 37 | |||
| 33 | /// Generates a serialized param package for creating a keyboard button device | 38 | /// Generates a serialized param package for creating a keyboard button device |
| 34 | std::string GenerateKeyboardParam(int key_code); | 39 | std::string GenerateKeyboardParam(int key_code); |
| 35 | 40 | ||
diff --git a/src/video_core/buffer_cache/buffer_cache.h b/src/video_core/buffer_cache/buffer_cache.h index cf8bdd021..c6479af9f 100644 --- a/src/video_core/buffer_cache/buffer_cache.h +++ b/src/video_core/buffer_cache/buffer_cache.h | |||
| @@ -322,8 +322,7 @@ protected: | |||
| 322 | } | 322 | } |
| 323 | 323 | ||
| 324 | private: | 324 | private: |
| 325 | MapInterval* MapAddress(const Buffer* block, GPUVAddr gpu_addr, VAddr cpu_addr, | 325 | MapInterval* MapAddress(Buffer* block, GPUVAddr gpu_addr, VAddr cpu_addr, std::size_t size) { |
| 326 | std::size_t size) { | ||
| 327 | const VectorMapInterval overlaps = GetMapsInRange(cpu_addr, size); | 326 | const VectorMapInterval overlaps = GetMapsInRange(cpu_addr, size); |
| 328 | if (overlaps.empty()) { | 327 | if (overlaps.empty()) { |
| 329 | auto& memory_manager = system.GPU().MemoryManager(); | 328 | auto& memory_manager = system.GPU().MemoryManager(); |
| @@ -377,8 +376,7 @@ private: | |||
| 377 | return map; | 376 | return map; |
| 378 | } | 377 | } |
| 379 | 378 | ||
| 380 | void UpdateBlock(const Buffer* block, VAddr start, VAddr end, | 379 | void UpdateBlock(Buffer* block, VAddr start, VAddr end, const VectorMapInterval& overlaps) { |
| 381 | const VectorMapInterval& overlaps) { | ||
| 382 | const IntervalType base_interval{start, end}; | 380 | const IntervalType base_interval{start, end}; |
| 383 | IntervalSet interval_set{}; | 381 | IntervalSet interval_set{}; |
| 384 | interval_set.add(base_interval); | 382 | interval_set.add(base_interval); |
diff --git a/src/video_core/renderer_opengl/gl_buffer_cache.cpp b/src/video_core/renderer_opengl/gl_buffer_cache.cpp index d9f7b4cc6..e461e4c70 100644 --- a/src/video_core/renderer_opengl/gl_buffer_cache.cpp +++ b/src/video_core/renderer_opengl/gl_buffer_cache.cpp | |||
| @@ -34,20 +34,27 @@ Buffer::Buffer(const Device& device, VAddr cpu_addr, std::size_t size) | |||
| 34 | 34 | ||
| 35 | Buffer::~Buffer() = default; | 35 | Buffer::~Buffer() = default; |
| 36 | 36 | ||
| 37 | void Buffer::Upload(std::size_t offset, std::size_t size, const u8* data) const { | 37 | void Buffer::Upload(std::size_t offset, std::size_t size, const u8* data) { |
| 38 | glNamedBufferSubData(Handle(), static_cast<GLintptr>(offset), static_cast<GLsizeiptr>(size), | 38 | glNamedBufferSubData(Handle(), static_cast<GLintptr>(offset), static_cast<GLsizeiptr>(size), |
| 39 | data); | 39 | data); |
| 40 | } | 40 | } |
| 41 | 41 | ||
| 42 | void Buffer::Download(std::size_t offset, std::size_t size, u8* data) const { | 42 | void Buffer::Download(std::size_t offset, std::size_t size, u8* data) { |
| 43 | MICROPROFILE_SCOPE(OpenGL_Buffer_Download); | 43 | MICROPROFILE_SCOPE(OpenGL_Buffer_Download); |
| 44 | const GLsizeiptr gl_size = static_cast<GLsizeiptr>(size); | ||
| 45 | const GLintptr gl_offset = static_cast<GLintptr>(offset); | ||
| 46 | if (read_buffer.handle == 0) { | ||
| 47 | read_buffer.Create(); | ||
| 48 | glNamedBufferData(read_buffer.handle, static_cast<GLsizeiptr>(Size()), nullptr, | ||
| 49 | GL_STREAM_READ); | ||
| 50 | } | ||
| 44 | glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT); | 51 | glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT); |
| 45 | glGetNamedBufferSubData(Handle(), static_cast<GLintptr>(offset), static_cast<GLsizeiptr>(size), | 52 | glCopyNamedBufferSubData(gl_buffer.handle, read_buffer.handle, gl_offset, gl_offset, gl_size); |
| 46 | data); | 53 | glGetNamedBufferSubData(read_buffer.handle, gl_offset, gl_size, data); |
| 47 | } | 54 | } |
| 48 | 55 | ||
| 49 | void Buffer::CopyFrom(const Buffer& src, std::size_t src_offset, std::size_t dst_offset, | 56 | void Buffer::CopyFrom(const Buffer& src, std::size_t src_offset, std::size_t dst_offset, |
| 50 | std::size_t size) const { | 57 | std::size_t size) { |
| 51 | glCopyNamedBufferSubData(src.Handle(), Handle(), static_cast<GLintptr>(src_offset), | 58 | glCopyNamedBufferSubData(src.Handle(), Handle(), static_cast<GLintptr>(src_offset), |
| 52 | static_cast<GLintptr>(dst_offset), static_cast<GLsizeiptr>(size)); | 59 | static_cast<GLintptr>(dst_offset), static_cast<GLsizeiptr>(size)); |
| 53 | } | 60 | } |
diff --git a/src/video_core/renderer_opengl/gl_buffer_cache.h b/src/video_core/renderer_opengl/gl_buffer_cache.h index 59d95adbc..88fdc0536 100644 --- a/src/video_core/renderer_opengl/gl_buffer_cache.h +++ b/src/video_core/renderer_opengl/gl_buffer_cache.h | |||
| @@ -28,12 +28,12 @@ public: | |||
| 28 | explicit Buffer(const Device& device, VAddr cpu_addr, std::size_t size); | 28 | explicit Buffer(const Device& device, VAddr cpu_addr, std::size_t size); |
| 29 | ~Buffer(); | 29 | ~Buffer(); |
| 30 | 30 | ||
| 31 | void Upload(std::size_t offset, std::size_t size, const u8* data) const; | 31 | void Upload(std::size_t offset, std::size_t size, const u8* data); |
| 32 | 32 | ||
| 33 | void Download(std::size_t offset, std::size_t size, u8* data) const; | 33 | void Download(std::size_t offset, std::size_t size, u8* data); |
| 34 | 34 | ||
| 35 | void CopyFrom(const Buffer& src, std::size_t src_offset, std::size_t dst_offset, | 35 | void CopyFrom(const Buffer& src, std::size_t src_offset, std::size_t dst_offset, |
| 36 | std::size_t size) const; | 36 | std::size_t size); |
| 37 | 37 | ||
| 38 | GLuint Handle() const noexcept { | 38 | GLuint Handle() const noexcept { |
| 39 | return gl_buffer.handle; | 39 | return gl_buffer.handle; |
| @@ -45,6 +45,7 @@ public: | |||
| 45 | 45 | ||
| 46 | private: | 46 | private: |
| 47 | OGLBuffer gl_buffer; | 47 | OGLBuffer gl_buffer; |
| 48 | OGLBuffer read_buffer; | ||
| 48 | u64 gpu_address = 0; | 49 | u64 gpu_address = 0; |
| 49 | }; | 50 | }; |
| 50 | 51 | ||
diff --git a/src/video_core/renderer_opengl/maxwell_to_gl.h b/src/video_core/renderer_opengl/maxwell_to_gl.h index 774e70a5b..fe9bd4b5a 100644 --- a/src/video_core/renderer_opengl/maxwell_to_gl.h +++ b/src/video_core/renderer_opengl/maxwell_to_gl.h | |||
| @@ -191,6 +191,12 @@ inline GLenum WrapMode(Tegra::Texture::WrapMode wrap_mode) { | |||
| 191 | } else { | 191 | } else { |
| 192 | return GL_MIRROR_CLAMP_TO_EDGE; | 192 | return GL_MIRROR_CLAMP_TO_EDGE; |
| 193 | } | 193 | } |
| 194 | case Tegra::Texture::WrapMode::MirrorOnceClampOGL: | ||
| 195 | if (GL_EXT_texture_mirror_clamp) { | ||
| 196 | return GL_MIRROR_CLAMP_EXT; | ||
| 197 | } else { | ||
| 198 | return GL_MIRROR_CLAMP_TO_EDGE; | ||
| 199 | } | ||
| 194 | } | 200 | } |
| 195 | UNIMPLEMENTED_MSG("Unimplemented texture wrap mode={}", static_cast<u32>(wrap_mode)); | 201 | UNIMPLEMENTED_MSG("Unimplemented texture wrap mode={}", static_cast<u32>(wrap_mode)); |
| 196 | return GL_REPEAT; | 202 | return GL_REPEAT; |
diff --git a/src/video_core/renderer_vulkan/vk_buffer_cache.cpp b/src/video_core/renderer_vulkan/vk_buffer_cache.cpp index f10f96cd8..2be38d419 100644 --- a/src/video_core/renderer_vulkan/vk_buffer_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_buffer_cache.cpp | |||
| @@ -56,7 +56,7 @@ Buffer::Buffer(const VKDevice& device, VKMemoryManager& memory_manager, VKSchedu | |||
| 56 | 56 | ||
| 57 | Buffer::~Buffer() = default; | 57 | Buffer::~Buffer() = default; |
| 58 | 58 | ||
| 59 | void Buffer::Upload(std::size_t offset, std::size_t size, const u8* data) const { | 59 | void Buffer::Upload(std::size_t offset, std::size_t size, const u8* data) { |
| 60 | const auto& staging = staging_pool.GetUnusedBuffer(size, true); | 60 | const auto& staging = staging_pool.GetUnusedBuffer(size, true); |
| 61 | std::memcpy(staging.commit->Map(size), data, size); | 61 | std::memcpy(staging.commit->Map(size), data, size); |
| 62 | 62 | ||
| @@ -81,7 +81,7 @@ void Buffer::Upload(std::size_t offset, std::size_t size, const u8* data) const | |||
| 81 | }); | 81 | }); |
| 82 | } | 82 | } |
| 83 | 83 | ||
| 84 | void Buffer::Download(std::size_t offset, std::size_t size, u8* data) const { | 84 | void Buffer::Download(std::size_t offset, std::size_t size, u8* data) { |
| 85 | const auto& staging = staging_pool.GetUnusedBuffer(size, true); | 85 | const auto& staging = staging_pool.GetUnusedBuffer(size, true); |
| 86 | scheduler.RequestOutsideRenderPassOperationContext(); | 86 | scheduler.RequestOutsideRenderPassOperationContext(); |
| 87 | 87 | ||
| @@ -110,7 +110,7 @@ void Buffer::Download(std::size_t offset, std::size_t size, u8* data) const { | |||
| 110 | } | 110 | } |
| 111 | 111 | ||
| 112 | void Buffer::CopyFrom(const Buffer& src, std::size_t src_offset, std::size_t dst_offset, | 112 | void Buffer::CopyFrom(const Buffer& src, std::size_t src_offset, std::size_t dst_offset, |
| 113 | std::size_t size) const { | 113 | std::size_t size) { |
| 114 | scheduler.RequestOutsideRenderPassOperationContext(); | 114 | scheduler.RequestOutsideRenderPassOperationContext(); |
| 115 | 115 | ||
| 116 | const VkBuffer dst_buffer = Handle(); | 116 | const VkBuffer dst_buffer = Handle(); |
diff --git a/src/video_core/renderer_vulkan/vk_buffer_cache.h b/src/video_core/renderer_vulkan/vk_buffer_cache.h index 3630aca77..991ee451c 100644 --- a/src/video_core/renderer_vulkan/vk_buffer_cache.h +++ b/src/video_core/renderer_vulkan/vk_buffer_cache.h | |||
| @@ -29,12 +29,12 @@ public: | |||
| 29 | VKStagingBufferPool& staging_pool, VAddr cpu_addr, std::size_t size); | 29 | VKStagingBufferPool& staging_pool, VAddr cpu_addr, std::size_t size); |
| 30 | ~Buffer(); | 30 | ~Buffer(); |
| 31 | 31 | ||
| 32 | void Upload(std::size_t offset, std::size_t size, const u8* data) const; | 32 | void Upload(std::size_t offset, std::size_t size, const u8* data); |
| 33 | 33 | ||
| 34 | void Download(std::size_t offset, std::size_t size, u8* data) const; | 34 | void Download(std::size_t offset, std::size_t size, u8* data); |
| 35 | 35 | ||
| 36 | void CopyFrom(const Buffer& src, std::size_t src_offset, std::size_t dst_offset, | 36 | void CopyFrom(const Buffer& src, std::size_t src_offset, std::size_t dst_offset, |
| 37 | std::size_t size) const; | 37 | std::size_t size); |
| 38 | 38 | ||
| 39 | VkBuffer Handle() const { | 39 | VkBuffer Handle() const { |
| 40 | return *buffer.handle; | 40 | return *buffer.handle; |
diff --git a/src/yuzu/configuration/configure_input_player.cpp b/src/yuzu/configuration/configure_input_player.cpp index a05fa64ba..00433926d 100644 --- a/src/yuzu/configuration/configure_input_player.cpp +++ b/src/yuzu/configuration/configure_input_player.cpp | |||
| @@ -70,6 +70,20 @@ static QString ButtonToText(const Common::ParamPackage& param) { | |||
| 70 | return GetKeyName(param.Get("code", 0)); | 70 | return GetKeyName(param.Get("code", 0)); |
| 71 | } | 71 | } |
| 72 | 72 | ||
| 73 | if (param.Get("engine", "") == "gcpad") { | ||
| 74 | if (param.Has("axis")) { | ||
| 75 | const QString axis_str = QString::fromStdString(param.Get("axis", "")); | ||
| 76 | const QString direction_str = QString::fromStdString(param.Get("direction", "")); | ||
| 77 | |||
| 78 | return QObject::tr("GC Axis %1%2").arg(axis_str, direction_str); | ||
| 79 | } | ||
| 80 | if (param.Has("button")) { | ||
| 81 | const QString button_str = QString::number(int(std::log2(param.Get("button", 0)))); | ||
| 82 | return QObject::tr("GC Button %1").arg(button_str); | ||
| 83 | } | ||
| 84 | return GetKeyName(param.Get("code", 0)); | ||
| 85 | } | ||
| 86 | |||
| 73 | if (param.Get("engine", "") == "sdl") { | 87 | if (param.Get("engine", "") == "sdl") { |
| 74 | if (param.Has("hat")) { | 88 | if (param.Has("hat")) { |
| 75 | const QString hat_str = QString::fromStdString(param.Get("hat", "")); | 89 | const QString hat_str = QString::fromStdString(param.Get("hat", "")); |
| @@ -126,6 +140,25 @@ static QString AnalogToText(const Common::ParamPackage& param, const std::string | |||
| 126 | return {}; | 140 | return {}; |
| 127 | } | 141 | } |
| 128 | 142 | ||
| 143 | if (param.Get("engine", "") == "gcpad") { | ||
| 144 | if (dir == "modifier") { | ||
| 145 | return QObject::tr("[unused]"); | ||
| 146 | } | ||
| 147 | |||
| 148 | if (dir == "left" || dir == "right") { | ||
| 149 | const QString axis_x_str = QString::fromStdString(param.Get("axis_x", "")); | ||
| 150 | |||
| 151 | return QObject::tr("GC Axis %1").arg(axis_x_str); | ||
| 152 | } | ||
| 153 | |||
| 154 | if (dir == "up" || dir == "down") { | ||
| 155 | const QString axis_y_str = QString::fromStdString(param.Get("axis_y", "")); | ||
| 156 | |||
| 157 | return QObject::tr("GC Axis %1").arg(axis_y_str); | ||
| 158 | } | ||
| 159 | |||
| 160 | return {}; | ||
| 161 | } | ||
| 129 | return QObject::tr("[unknown]"); | 162 | return QObject::tr("[unknown]"); |
| 130 | } | 163 | } |
| 131 | 164 | ||
| @@ -332,7 +365,8 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i | |||
| 332 | 365 | ||
| 333 | connect(analog_map_deadzone_and_modifier_slider[analog_id], &QSlider::valueChanged, [=] { | 366 | connect(analog_map_deadzone_and_modifier_slider[analog_id], &QSlider::valueChanged, [=] { |
| 334 | const float slider_value = analog_map_deadzone_and_modifier_slider[analog_id]->value(); | 367 | const float slider_value = analog_map_deadzone_and_modifier_slider[analog_id]->value(); |
| 335 | if (analogs_param[analog_id].Get("engine", "") == "sdl") { | 368 | if (analogs_param[analog_id].Get("engine", "") == "sdl" || |
| 369 | analogs_param[analog_id].Get("engine", "") == "gcpad") { | ||
| 336 | analog_map_deadzone_and_modifier_slider_label[analog_id]->setText( | 370 | analog_map_deadzone_and_modifier_slider_label[analog_id]->setText( |
| 337 | tr("Deadzone: %1%").arg(slider_value)); | 371 | tr("Deadzone: %1%").arg(slider_value)); |
| 338 | analogs_param[analog_id].Set("deadzone", slider_value / 100.0f); | 372 | analogs_param[analog_id].Set("deadzone", slider_value / 100.0f); |
| @@ -352,6 +386,20 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i | |||
| 352 | 386 | ||
| 353 | connect(poll_timer.get(), &QTimer::timeout, [this] { | 387 | connect(poll_timer.get(), &QTimer::timeout, [this] { |
| 354 | Common::ParamPackage params; | 388 | Common::ParamPackage params; |
| 389 | if (InputCommon::GetGCButtons()->IsPolling()) { | ||
| 390 | params = InputCommon::GetGCButtons()->GetNextInput(); | ||
| 391 | if (params.Has("engine")) { | ||
| 392 | SetPollingResult(params, false); | ||
| 393 | return; | ||
| 394 | } | ||
| 395 | } | ||
| 396 | if (InputCommon::GetGCAnalogs()->IsPolling()) { | ||
| 397 | params = InputCommon::GetGCAnalogs()->GetNextInput(); | ||
| 398 | if (params.Has("engine")) { | ||
| 399 | SetPollingResult(params, false); | ||
| 400 | return; | ||
| 401 | } | ||
| 402 | } | ||
| 355 | for (auto& poller : device_pollers) { | 403 | for (auto& poller : device_pollers) { |
| 356 | params = poller->GetNextInput(); | 404 | params = poller->GetNextInput(); |
| 357 | if (params.Has("engine")) { | 405 | if (params.Has("engine")) { |
| @@ -534,7 +582,7 @@ void ConfigureInputPlayer::UpdateButtonLabels() { | |||
| 534 | analog_map_deadzone_and_modifier_slider_label[analog_id]; | 582 | analog_map_deadzone_and_modifier_slider_label[analog_id]; |
| 535 | 583 | ||
| 536 | if (param.Has("engine")) { | 584 | if (param.Has("engine")) { |
| 537 | if (param.Get("engine", "") == "sdl") { | 585 | if (param.Get("engine", "") == "sdl" || param.Get("engine", "") == "gcpad") { |
| 538 | if (!param.Has("deadzone")) { | 586 | if (!param.Has("deadzone")) { |
| 539 | param.Set("deadzone", 0.1f); | 587 | param.Set("deadzone", 0.1f); |
| 540 | } | 588 | } |
| @@ -583,6 +631,11 @@ void ConfigureInputPlayer::HandleClick( | |||
| 583 | 631 | ||
| 584 | grabKeyboard(); | 632 | grabKeyboard(); |
| 585 | grabMouse(); | 633 | grabMouse(); |
| 634 | if (type == InputCommon::Polling::DeviceType::Button) { | ||
| 635 | InputCommon::GetGCButtons()->BeginConfiguration(); | ||
| 636 | } else { | ||
| 637 | InputCommon::GetGCAnalogs()->BeginConfiguration(); | ||
| 638 | } | ||
| 586 | timeout_timer->start(5000); // Cancel after 5 seconds | 639 | timeout_timer->start(5000); // Cancel after 5 seconds |
| 587 | poll_timer->start(200); // Check for new inputs every 200ms | 640 | poll_timer->start(200); // Check for new inputs every 200ms |
| 588 | } | 641 | } |
| @@ -596,6 +649,9 @@ void ConfigureInputPlayer::SetPollingResult(const Common::ParamPackage& params, | |||
| 596 | poller->Stop(); | 649 | poller->Stop(); |
| 597 | } | 650 | } |
| 598 | 651 | ||
| 652 | InputCommon::GetGCButtons()->EndConfiguration(); | ||
| 653 | InputCommon::GetGCAnalogs()->EndConfiguration(); | ||
| 654 | |||
| 599 | if (!abort) { | 655 | if (!abort) { |
| 600 | (*input_setter)(params); | 656 | (*input_setter)(params); |
| 601 | } | 657 | } |
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index f586950e7..fb299a39b 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp | |||
| @@ -2226,7 +2226,7 @@ void GMainWindow::OnReinitializeKeys(ReinitializeKeyBehavior behavior) { | |||
| 2226 | "title.keys_autogenerated"); | 2226 | "title.keys_autogenerated"); |
| 2227 | } | 2227 | } |
| 2228 | 2228 | ||
| 2229 | Core::Crypto::KeyManager& keys = Core::Crypto::KeyManager::instance(); | 2229 | Core::Crypto::KeyManager& keys = Core::Crypto::KeyManager::Instance(); |
| 2230 | if (keys.BaseDeriveNecessary()) { | 2230 | if (keys.BaseDeriveNecessary()) { |
| 2231 | Core::Crypto::PartitionDataManager pdm{vfs->OpenDirectory( | 2231 | Core::Crypto::PartitionDataManager pdm{vfs->OpenDirectory( |
| 2232 | FileUtil::GetUserPath(FileUtil::UserPath::SysDataDir), FileSys::Mode::Read)}; | 2232 | FileUtil::GetUserPath(FileUtil::UserPath::SysDataDir), FileSys::Mode::Read)}; |