early-access version 2251
This commit is contained in:
@@ -605,6 +605,7 @@ struct Values {
|
||||
BasicSetting<bool> extended_logging{false, "extended_logging"};
|
||||
BasicSetting<bool> use_debug_asserts{false, "use_debug_asserts"};
|
||||
BasicSetting<bool> use_auto_stub{false, "use_auto_stub"};
|
||||
BasicSetting<bool> enable_all_controllers{false, "enable_all_controllers"};
|
||||
|
||||
// Miscellaneous
|
||||
BasicSetting<std::string> log_filter{"*:Info", "log_filter"};
|
||||
|
@@ -370,6 +370,11 @@ enum class ControllerType {
|
||||
RightJoycon,
|
||||
Handheld,
|
||||
GameCube,
|
||||
Pokeball,
|
||||
NES,
|
||||
SNES,
|
||||
N64,
|
||||
SegaGenesis,
|
||||
};
|
||||
|
||||
struct PlayerInput {
|
||||
|
@@ -479,6 +479,8 @@ add_library(core STATIC
|
||||
hle/service/ns/language.h
|
||||
hle/service/ns/ns.cpp
|
||||
hle/service/ns/ns.h
|
||||
hle/service/ns/pdm_qry.cpp
|
||||
hle/service/ns/pdm_qry.h
|
||||
hle/service/ns/pl_u.cpp
|
||||
hle/service/ns/pl_u.h
|
||||
hle/service/nvdrv/devices/nvdevice.h
|
||||
|
@@ -27,6 +27,16 @@ NpadStyleIndex EmulatedController::MapSettingsTypeToNPad(Settings::ControllerTyp
|
||||
return NpadStyleIndex::Handheld;
|
||||
case Settings::ControllerType::GameCube:
|
||||
return NpadStyleIndex::GameCube;
|
||||
case Settings::ControllerType::Pokeball:
|
||||
return NpadStyleIndex::Pokeball;
|
||||
case Settings::ControllerType::NES:
|
||||
return NpadStyleIndex::NES;
|
||||
case Settings::ControllerType::SNES:
|
||||
return NpadStyleIndex::SNES;
|
||||
case Settings::ControllerType::N64:
|
||||
return NpadStyleIndex::N64;
|
||||
case Settings::ControllerType::SegaGenesis:
|
||||
return NpadStyleIndex::SegaGenesis;
|
||||
default:
|
||||
return NpadStyleIndex::ProController;
|
||||
}
|
||||
@@ -46,6 +56,16 @@ Settings::ControllerType EmulatedController::MapNPadToSettingsType(NpadStyleInde
|
||||
return Settings::ControllerType::Handheld;
|
||||
case NpadStyleIndex::GameCube:
|
||||
return Settings::ControllerType::GameCube;
|
||||
case NpadStyleIndex::Pokeball:
|
||||
return Settings::ControllerType::Pokeball;
|
||||
case NpadStyleIndex::NES:
|
||||
return Settings::ControllerType::NES;
|
||||
case NpadStyleIndex::SNES:
|
||||
return Settings::ControllerType::SNES;
|
||||
case NpadStyleIndex::N64:
|
||||
return Settings::ControllerType::N64;
|
||||
case NpadStyleIndex::SegaGenesis:
|
||||
return Settings::ControllerType::SegaGenesis;
|
||||
default:
|
||||
return Settings::ControllerType::ProController;
|
||||
}
|
||||
|
@@ -263,6 +263,10 @@ void Controller_NPad::OnInit() {
|
||||
style.fullkey.Assign(1);
|
||||
style.gamecube.Assign(1);
|
||||
style.palma.Assign(1);
|
||||
style.lark.Assign(1);
|
||||
style.lucia.Assign(1);
|
||||
style.lagoon.Assign(1);
|
||||
style.lager.Assign(1);
|
||||
hid_core.SetSupportedStyleTag(style);
|
||||
}
|
||||
|
||||
|
@@ -1883,7 +1883,7 @@ public:
|
||||
{317, nullptr, "GetNpadLeftRightInterfaceType"},
|
||||
{318, nullptr, "HasBattery"},
|
||||
{319, nullptr, "HasLeftRightBattery"},
|
||||
{321, nullptr, "GetUniquePadsFromNpad"},
|
||||
{321, &HidSys::GetUniquePadsFromNpad, "GetUniquePadsFromNpad"},
|
||||
{322, nullptr, "GetIrSensorState"},
|
||||
{323, nullptr, "GetXcdHandleForNpadWithIrSensor"},
|
||||
{324, nullptr, "GetUniquePadButtonSet"},
|
||||
@@ -2054,6 +2054,18 @@ private:
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(ResultSuccess);
|
||||
}
|
||||
|
||||
void GetUniquePadsFromNpad(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto npad_id_type{rp.PopEnum<Core::HID::NpadIdType>()};
|
||||
|
||||
const s64 total_entries = 0;
|
||||
LOG_WARNING(Service_HID, "(STUBBED) called, npad_id_type={}", npad_id_type);
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.Push(total_entries);
|
||||
}
|
||||
};
|
||||
|
||||
class HidTmp final : public ServiceFramework<HidTmp> {
|
||||
|
@@ -12,6 +12,7 @@
|
||||
#include "core/hle/service/ns/errors.h"
|
||||
#include "core/hle/service/ns/language.h"
|
||||
#include "core/hle/service/ns/ns.h"
|
||||
#include "core/hle/service/ns/pdm_qry.h"
|
||||
#include "core/hle/service/ns/pl_u.h"
|
||||
#include "core/hle/service/set/set.h"
|
||||
|
||||
@@ -570,11 +571,29 @@ IFactoryResetInterface::IFactoryResetInterface(Core::System& system_)
|
||||
|
||||
IFactoryResetInterface::~IFactoryResetInterface() = default;
|
||||
|
||||
IReadOnlyApplicationControlDataInterface::IReadOnlyApplicationControlDataInterface(
|
||||
Core::System& system_)
|
||||
: ServiceFramework{system_, "IReadOnlyApplicationControlDataInterface"} {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, nullptr, "GetApplicationControlData"},
|
||||
{1, nullptr, "GetApplicationDesiredLanguage"},
|
||||
{2, nullptr, "ConvertApplicationLanguageToLanguageCode"},
|
||||
{3, nullptr, "ConvertLanguageCodeToApplicationLanguage"},
|
||||
{4, nullptr, "SelectApplicationDesiredLanguage"},
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
RegisterHandlers(functions);
|
||||
}
|
||||
|
||||
IReadOnlyApplicationControlDataInterface::~IReadOnlyApplicationControlDataInterface() = default;
|
||||
|
||||
NS::NS(const char* name, Core::System& system_) : ServiceFramework{system_, name} {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{7988, nullptr, "GetDynamicRightsInterface"},
|
||||
{7989, nullptr, "GetReadOnlyApplicationControlDataInterface"},
|
||||
{7989, &NS::PushInterface<IReadOnlyApplicationControlDataInterface>, "GetReadOnlyApplicationControlDataInterface"},
|
||||
{7991, nullptr, "GetReadOnlyApplicationRecordInterface"},
|
||||
{7992, &NS::PushInterface<IECommerceInterface>, "GetECommerceInterface"},
|
||||
{7993, &NS::PushInterface<IApplicationVersionInterface>, "GetApplicationVersionInterface"},
|
||||
@@ -738,6 +757,8 @@ void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system
|
||||
std::make_shared<NS_SU>(system)->InstallAsService(service_manager);
|
||||
std::make_shared<NS_VM>(system)->InstallAsService(service_manager);
|
||||
|
||||
std::make_shared<PDM_QRY>(system)->InstallAsService(service_manager);
|
||||
|
||||
std::make_shared<PL_U>(system)->InstallAsService(service_manager);
|
||||
}
|
||||
|
||||
|
@@ -74,6 +74,13 @@ public:
|
||||
~IFactoryResetInterface() override;
|
||||
};
|
||||
|
||||
class IReadOnlyApplicationControlDataInterface final
|
||||
: public ServiceFramework<IReadOnlyApplicationControlDataInterface> {
|
||||
public:
|
||||
explicit IReadOnlyApplicationControlDataInterface(Core::System& system_);
|
||||
~IReadOnlyApplicationControlDataInterface() override;
|
||||
};
|
||||
|
||||
class NS final : public ServiceFramework<NS> {
|
||||
public:
|
||||
explicit NS(const char* name, Core::System& system_);
|
||||
|
69
src/core/hle/service/ns/pdm_qry.cpp
Executable file
69
src/core/hle/service/ns/pdm_qry.cpp
Executable file
@@ -0,0 +1,69 @@
|
||||
// Copyright 2021 yuzu Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include "common/logging/log.h"
|
||||
#include "common/uuid.h"
|
||||
#include "core/hle/ipc_helpers.h"
|
||||
#include "core/hle/service/ns/pdm_qry.h"
|
||||
#include "core/hle/service/service.h"
|
||||
#include "core/hle/service/sm/sm.h"
|
||||
|
||||
namespace Service::NS {
|
||||
|
||||
PDM_QRY::PDM_QRY(Core::System& system_) : ServiceFramework{system_, "pdm:qry"} {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, nullptr, "QueryAppletEvent"},
|
||||
{1, nullptr, "QueryPlayStatistics"},
|
||||
{2, nullptr, "QueryPlayStatisticsByUserAccountId"},
|
||||
{3, nullptr, "QueryPlayStatisticsByNetworkServiceAccountId"},
|
||||
{4, nullptr, "QueryPlayStatisticsByApplicationId"},
|
||||
{5, &PDM_QRY::QueryPlayStatisticsByApplicationIdAndUserAccountId, "QueryPlayStatisticsByApplicationIdAndUserAccountId"},
|
||||
{6, nullptr, "QueryPlayStatisticsByApplicationIdAndNetworkServiceAccountId"},
|
||||
{7, nullptr, "QueryLastPlayTimeV0"},
|
||||
{8, nullptr, "QueryPlayEvent"},
|
||||
{9, nullptr, "GetAvailablePlayEventRange"},
|
||||
{10, nullptr, "QueryAccountEvent"},
|
||||
{11, nullptr, "QueryAccountPlayEvent"},
|
||||
{12, nullptr, "GetAvailableAccountPlayEventRange"},
|
||||
{13, nullptr, "QueryApplicationPlayStatisticsForSystemV0"},
|
||||
{14, nullptr, "QueryRecentlyPlayedApplication"},
|
||||
{15, nullptr, "GetRecentlyPlayedApplicationUpdateEvent"},
|
||||
{16, nullptr, "QueryApplicationPlayStatisticsByUserAccountIdForSystemV0"},
|
||||
{17, nullptr, "QueryLastPlayTime"},
|
||||
{18, nullptr, "QueryApplicationPlayStatisticsForSystem"},
|
||||
{19, nullptr, "QueryApplicationPlayStatisticsByUserAccountIdForSystem"},
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
RegisterHandlers(functions);
|
||||
}
|
||||
|
||||
PDM_QRY::~PDM_QRY() = default;
|
||||
|
||||
void PDM_QRY::QueryPlayStatisticsByApplicationIdAndUserAccountId(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto unknown = rp.Pop<bool>();
|
||||
rp.Pop<u8>(); // Padding
|
||||
const auto application_id = rp.Pop<u64>();
|
||||
const auto user_account_uid = rp.PopRaw<Common::UUID>();
|
||||
|
||||
// TODO(German77): Read statistics of the game
|
||||
PlayStatistics statistics{
|
||||
.application_id = application_id,
|
||||
.total_launches = 1,
|
||||
};
|
||||
|
||||
LOG_WARNING(Service_NS,
|
||||
"(STUBBED) called. unknown={}. application_id=0x{:016X}, user_account_uid=0x{}",
|
||||
unknown, application_id, user_account_uid.Format());
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 12};
|
||||
rb.Push(ResultSuccess);
|
||||
rb.PushRaw(statistics);
|
||||
}
|
||||
|
||||
} // namespace Service::NS
|
33
src/core/hle/service/ns/pdm_qry.h
Executable file
33
src/core/hle/service/ns/pdm_qry.h
Executable file
@@ -0,0 +1,33 @@
|
||||
// Copyright 2021 yuzu Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "core/hle/service/service.h"
|
||||
|
||||
namespace Service::NS {
|
||||
|
||||
struct PlayStatistics {
|
||||
u64 application_id{};
|
||||
u32 first_entry_index{};
|
||||
u32 first_timestamp_user{};
|
||||
u32 first_timestamp_network{};
|
||||
u32 last_entry_index{};
|
||||
u32 last_timestamp_user{};
|
||||
u32 last_timestamp_network{};
|
||||
u32 play_time_in_minutes{};
|
||||
u32 total_launches{};
|
||||
};
|
||||
static_assert(sizeof(PlayStatistics) == 0x28, "PlayStatistics is an invalid size");
|
||||
|
||||
class PDM_QRY final : public ServiceFramework<PDM_QRY> {
|
||||
public:
|
||||
explicit PDM_QRY(Core::System& system_);
|
||||
~PDM_QRY() override;
|
||||
|
||||
private:
|
||||
void QueryPlayStatisticsByApplicationIdAndUserAccountId(Kernel::HLERequestContext& ctx);
|
||||
};
|
||||
|
||||
} // namespace Service::NS
|
@@ -430,7 +430,7 @@ void EmitSetSampleMask(EmitContext& ctx, Id value) {
|
||||
}
|
||||
|
||||
void EmitSetFragDepth(EmitContext& ctx, Id value) {
|
||||
if (!ctx.runtime_info.convert_depth_mode) {
|
||||
if (!ctx.runtime_info.convert_depth_mode || ctx.profile.support_native_ndc) {
|
||||
ctx.OpStore(ctx.frag_depth, value);
|
||||
return;
|
||||
}
|
||||
|
@@ -116,7 +116,8 @@ void EmitPrologue(EmitContext& ctx) {
|
||||
}
|
||||
|
||||
void EmitEpilogue(EmitContext& ctx) {
|
||||
if (ctx.stage == Stage::VertexB && ctx.runtime_info.convert_depth_mode) {
|
||||
if (ctx.stage == Stage::VertexB && ctx.runtime_info.convert_depth_mode &&
|
||||
!ctx.profile.support_native_ndc) {
|
||||
ConvertDepthMode(ctx);
|
||||
}
|
||||
if (ctx.stage == Stage::Fragment) {
|
||||
@@ -125,7 +126,7 @@ void EmitEpilogue(EmitContext& ctx) {
|
||||
}
|
||||
|
||||
void EmitEmitVertex(EmitContext& ctx, const IR::Value& stream) {
|
||||
if (ctx.runtime_info.convert_depth_mode) {
|
||||
if (ctx.runtime_info.convert_depth_mode && !ctx.profile.support_native_ndc) {
|
||||
ConvertDepthMode(ctx);
|
||||
}
|
||||
if (stream.IsImmediate()) {
|
||||
|
@@ -36,6 +36,7 @@ struct Profile {
|
||||
bool support_int64_atomics{};
|
||||
bool support_derivative_control{};
|
||||
bool support_geometry_shader_passthrough{};
|
||||
bool support_native_ndc{};
|
||||
bool support_gl_nv_gpu_shader_5{};
|
||||
bool support_gl_amd_gpu_shader_half_float{};
|
||||
bool support_gl_texture_shadow_lod{};
|
||||
|
@@ -194,6 +194,7 @@ ShaderCache::ShaderCache(RasterizerOpenGL& rasterizer_, Core::Frontend::EmuWindo
|
||||
.support_int64_atomics = false,
|
||||
.support_derivative_control = device.HasDerivativeControl(),
|
||||
.support_geometry_shader_passthrough = device.HasGeometryShaderPassthrough(),
|
||||
.support_native_ndc = true,
|
||||
.support_gl_nv_gpu_shader_5 = device.HasNvGpuShader5(),
|
||||
.support_gl_amd_gpu_shader_half_float = device.HasAmdShaderHalfFloat(),
|
||||
.support_gl_texture_shadow_lod = device.HasTextureShadowLod(),
|
||||
|
@@ -522,9 +522,8 @@ void GraphicsPipeline::MakePipeline(VkRenderPass render_pass) {
|
||||
vertex_attributes.push_back({
|
||||
.location = static_cast<u32>(index),
|
||||
.binding = 0,
|
||||
.format = type == 1 ? VK_FORMAT_R32_SFLOAT
|
||||
: type == 2 ? VK_FORMAT_R32_SINT
|
||||
: VK_FORMAT_R32_UINT,
|
||||
.format = type == 1 ? VK_FORMAT_R32_SFLOAT
|
||||
: type == 2 ? VK_FORMAT_R32_SINT : VK_FORMAT_R32_UINT,
|
||||
.offset = 0,
|
||||
});
|
||||
}
|
||||
@@ -614,25 +613,36 @@ void GraphicsPipeline::MakePipeline(VkRenderPass render_pass) {
|
||||
.patchControlPoints = key.state.patch_control_points_minus_one.Value() + 1,
|
||||
};
|
||||
|
||||
void* viewport_next = nullptr;
|
||||
std::array<VkViewportSwizzleNV, Maxwell::NumViewports> swizzles;
|
||||
std::ranges::transform(key.state.viewport_swizzles, swizzles.begin(), UnpackViewportSwizzle);
|
||||
const VkPipelineViewportSwizzleStateCreateInfoNV swizzle_ci{
|
||||
VkPipelineViewportSwizzleStateCreateInfoNV swizzle_ci{
|
||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_SWIZZLE_STATE_CREATE_INFO_NV,
|
||||
.pNext = nullptr,
|
||||
.pNext = viewport_next,
|
||||
.flags = 0,
|
||||
.viewportCount = Maxwell::NumViewports,
|
||||
.pViewportSwizzles = swizzles.data(),
|
||||
};
|
||||
if (device.IsNvViewportSwizzleSupported()) {
|
||||
viewport_next = &swizzle_ci;
|
||||
}
|
||||
VkPipelineViewportDepthClipControlCreateInfoEXT ndc_info{
|
||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_DEPTH_CLIP_CONTROL_CREATE_INFO_EXT,
|
||||
.pNext = viewport_next,
|
||||
.negativeOneToOne = key.state.ndc_minus_one_to_one.Value() != 0 ? VK_TRUE : VK_FALSE,
|
||||
};
|
||||
if (device.IsExtDepthClipControlSupported()) {
|
||||
viewport_next = &ndc_info;
|
||||
}
|
||||
const VkPipelineViewportStateCreateInfo viewport_ci{
|
||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO,
|
||||
.pNext = device.IsNvViewportSwizzleSupported() ? &swizzle_ci : nullptr,
|
||||
.pNext = viewport_next,
|
||||
.flags = 0,
|
||||
.viewportCount = Maxwell::NumViewports,
|
||||
.pViewports = nullptr,
|
||||
.scissorCount = Maxwell::NumViewports,
|
||||
.pScissors = nullptr,
|
||||
};
|
||||
|
||||
VkPipelineRasterizationStateCreateInfo rasterization_ci{
|
||||
.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO,
|
||||
.pNext = nullptr,
|
||||
|
@@ -311,6 +311,7 @@ PipelineCache::PipelineCache(RasterizerVulkan& rasterizer_, Tegra::Engines::Maxw
|
||||
.support_int64_atomics = device.IsExtShaderAtomicInt64Supported(),
|
||||
.support_derivative_control = true,
|
||||
.support_geometry_shader_passthrough = device.IsNvGeometryShaderPassthroughSupported(),
|
||||
.support_native_ndc = device.IsExtDepthClipControlSupported(),
|
||||
|
||||
.warp_size_potentially_larger_than_guest = device.IsWarpSizePotentiallyBiggerThanGuest(),
|
||||
|
||||
|
@@ -556,6 +556,16 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR
|
||||
LOG_INFO(Render_Vulkan, "Device doesn't support depth range unrestricted");
|
||||
}
|
||||
|
||||
VkPhysicalDeviceDepthClipControlFeaturesEXT depth_clip_control_features;
|
||||
if (ext_depth_clip_control) {
|
||||
depth_clip_control_features = {
|
||||
.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEPTH_CLIP_CONTROL_FEATURES_EXT,
|
||||
.pNext = nullptr,
|
||||
.depthClipControl = VK_TRUE,
|
||||
};
|
||||
SetNext(next, depth_clip_control_features);
|
||||
}
|
||||
|
||||
VkDeviceDiagnosticsConfigCreateInfoNV diagnostics_nv;
|
||||
if (Settings::values.enable_nsight_aftermath && nv_device_diagnostics_config) {
|
||||
nsight_aftermath_tracker = std::make_unique<NsightAftermathTracker>();
|
||||
@@ -890,6 +900,7 @@ std::vector<const char*> Device::LoadExtensions(bool requires_surface) {
|
||||
bool has_ext_provoking_vertex{};
|
||||
bool has_ext_vertex_input_dynamic_state{};
|
||||
bool has_ext_line_rasterization{};
|
||||
bool has_ext_depth_clip_control{};
|
||||
for (const std::string& extension : supported_extensions) {
|
||||
const auto test = [&](std::optional<std::reference_wrapper<bool>> status, const char* name,
|
||||
bool push) {
|
||||
@@ -921,6 +932,7 @@ std::vector<const char*> Device::LoadExtensions(bool requires_surface) {
|
||||
test(ext_shader_stencil_export, VK_EXT_SHADER_STENCIL_EXPORT_EXTENSION_NAME, true);
|
||||
test(ext_conservative_rasterization, VK_EXT_CONSERVATIVE_RASTERIZATION_EXTENSION_NAME,
|
||||
true);
|
||||
test(has_ext_depth_clip_control, VK_EXT_DEPTH_CLIP_CONTROL_EXTENSION_NAME, false);
|
||||
test(has_ext_transform_feedback, VK_EXT_TRANSFORM_FEEDBACK_EXTENSION_NAME, false);
|
||||
test(has_ext_custom_border_color, VK_EXT_CUSTOM_BORDER_COLOR_EXTENSION_NAME, false);
|
||||
test(has_ext_extended_dynamic_state, VK_EXT_EXTENDED_DYNAMIC_STATE_EXTENSION_NAME, false);
|
||||
@@ -1083,6 +1095,19 @@ std::vector<const char*> Device::LoadExtensions(bool requires_surface) {
|
||||
ext_line_rasterization = true;
|
||||
}
|
||||
}
|
||||
if (has_ext_depth_clip_control) {
|
||||
VkPhysicalDeviceDepthClipControlFeaturesEXT depth_clip_control_features;
|
||||
depth_clip_control_features.sType =
|
||||
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DEPTH_CLIP_CONTROL_FEATURES_EXT;
|
||||
depth_clip_control_features.pNext = nullptr;
|
||||
features.pNext = &depth_clip_control_features;
|
||||
physical.GetFeatures2KHR(features);
|
||||
|
||||
if (depth_clip_control_features.depthClipControl) {
|
||||
extensions.push_back(VK_EXT_DEPTH_CLIP_CONTROL_EXTENSION_NAME);
|
||||
ext_depth_clip_control = true;
|
||||
}
|
||||
}
|
||||
if (has_khr_workgroup_memory_explicit_layout) {
|
||||
VkPhysicalDeviceWorkgroupMemoryExplicitLayoutFeaturesKHR layout;
|
||||
layout.sType =
|
||||
|
@@ -253,6 +253,11 @@ public:
|
||||
return ext_depth_range_unrestricted;
|
||||
}
|
||||
|
||||
/// Returns true if the device supports VK_EXT_depth_clip_control.
|
||||
bool IsExtDepthClipControlSupported() const {
|
||||
return ext_depth_clip_control;
|
||||
}
|
||||
|
||||
/// Returns true if the device supports VK_EXT_shader_viewport_index_layer.
|
||||
bool IsExtShaderViewportIndexLayerSupported() const {
|
||||
return ext_shader_viewport_index_layer;
|
||||
@@ -412,6 +417,7 @@ private:
|
||||
bool khr_swapchain_mutable_format{}; ///< Support for VK_KHR_swapchain_mutable_format.
|
||||
bool ext_index_type_uint8{}; ///< Support for VK_EXT_index_type_uint8.
|
||||
bool ext_sampler_filter_minmax{}; ///< Support for VK_EXT_sampler_filter_minmax.
|
||||
bool ext_depth_clip_control{}; ///< Support for VK_EXT_depth_clip_control
|
||||
bool ext_depth_range_unrestricted{}; ///< Support for VK_EXT_depth_range_unrestricted.
|
||||
bool ext_shader_viewport_index_layer{}; ///< Support for VK_EXT_shader_viewport_index_layer.
|
||||
bool ext_tooling_info{}; ///< Support for VK_EXT_tooling_info.
|
||||
|
@@ -126,6 +126,8 @@ add_executable(yuzu
|
||||
configuration/configure_web.ui
|
||||
configuration/input_profiles.cpp
|
||||
configuration/input_profiles.h
|
||||
controller_navigation.cpp
|
||||
controller_navigation.h
|
||||
debugger/console.cpp
|
||||
debugger/console.h
|
||||
debugger/controller.cpp
|
||||
|
@@ -201,6 +201,16 @@ QtControllerSelectorDialog::QtControllerSelectorDialog(
|
||||
connect(ui->buttonBox, &QDialogButtonBox::accepted, this,
|
||||
&QtControllerSelectorDialog::ApplyConfiguration);
|
||||
|
||||
controller_navigation = new ControllerNavigation(system.HIDCore(), this);
|
||||
connect(controller_navigation, &ControllerNavigation::TriggerKeyboardEvent,
|
||||
[this](Qt::Key key) {
|
||||
if (!this->isActiveWindow()) {
|
||||
return;
|
||||
}
|
||||
QKeyEvent* event = new QKeyEvent(QEvent::KeyPress, key, Qt::NoModifier);
|
||||
QCoreApplication::postEvent(this, event);
|
||||
});
|
||||
|
||||
// Enhancement: Check if the parameters have already been met before disconnecting controllers.
|
||||
// If all the parameters are met AND only allows a single player,
|
||||
// stop the constructor here as we do not need to continue.
|
||||
@@ -218,7 +228,9 @@ QtControllerSelectorDialog::QtControllerSelectorDialog(
|
||||
resize(0, 0);
|
||||
}
|
||||
|
||||
QtControllerSelectorDialog::~QtControllerSelectorDialog() = default;
|
||||
QtControllerSelectorDialog::~QtControllerSelectorDialog() {
|
||||
controller_navigation->UnloadController();
|
||||
};
|
||||
|
||||
int QtControllerSelectorDialog::exec() {
|
||||
if (parameters_met && parameters.enable_single_mode) {
|
||||
|
@@ -9,6 +9,7 @@
|
||||
#include <QDialog>
|
||||
#include "core/core.h"
|
||||
#include "core/frontend/applets/controller.h"
|
||||
#include "yuzu/controller_navigation.h"
|
||||
|
||||
class GMainWindow;
|
||||
class QCheckBox;
|
||||
@@ -148,6 +149,9 @@ private:
|
||||
|
||||
// Checkboxes representing the "Connected Controllers".
|
||||
std::array<QCheckBox*, NUM_PLAYERS> connected_controller_checkboxes;
|
||||
|
||||
// QObject for navigating the UI with a controller
|
||||
ControllerNavigation* controller_navigation = nullptr;
|
||||
};
|
||||
|
||||
class QtControllerSelector final : public QObject, public Core::Frontend::ControllerApplet {
|
||||
|
@@ -3,6 +3,7 @@
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <mutex>
|
||||
#include <QApplication>
|
||||
#include <QDialogButtonBox>
|
||||
#include <QHeaderView>
|
||||
#include <QLabel>
|
||||
@@ -45,7 +46,7 @@ QPixmap GetIcon(Common::UUID uuid) {
|
||||
}
|
||||
} // Anonymous namespace
|
||||
|
||||
QtProfileSelectionDialog::QtProfileSelectionDialog(QWidget* parent)
|
||||
QtProfileSelectionDialog::QtProfileSelectionDialog(Core::HID::HIDCore& hid_core, QWidget* parent)
|
||||
: QDialog(parent), profile_manager(std::make_unique<Service::Account::ProfileManager>()) {
|
||||
outer_layout = new QVBoxLayout;
|
||||
|
||||
@@ -65,6 +66,7 @@ QtProfileSelectionDialog::QtProfileSelectionDialog(QWidget* parent)
|
||||
tree_view = new QTreeView;
|
||||
item_model = new QStandardItemModel(tree_view);
|
||||
tree_view->setModel(item_model);
|
||||
controller_navigation = new ControllerNavigation(hid_core, this);
|
||||
|
||||
tree_view->setAlternatingRowColors(true);
|
||||
tree_view->setSelectionMode(QHeaderView::SingleSelection);
|
||||
@@ -91,6 +93,14 @@ QtProfileSelectionDialog::QtProfileSelectionDialog(QWidget* parent)
|
||||
scroll_area->setLayout(layout);
|
||||
|
||||
connect(tree_view, &QTreeView::clicked, this, &QtProfileSelectionDialog::SelectUser);
|
||||
connect(controller_navigation, &ControllerNavigation::TriggerKeyboardEvent,
|
||||
[this](Qt::Key key) {
|
||||
if (!this->isActiveWindow()) {
|
||||
return;
|
||||
}
|
||||
QKeyEvent* event = new QKeyEvent(QEvent::KeyPress, key, Qt::NoModifier);
|
||||
QCoreApplication::postEvent(tree_view, event);
|
||||
});
|
||||
|
||||
const auto& profiles = profile_manager->GetAllUsers();
|
||||
for (const auto& user : profiles) {
|
||||
@@ -113,7 +123,9 @@ QtProfileSelectionDialog::QtProfileSelectionDialog(QWidget* parent)
|
||||
resize(550, 400);
|
||||
}
|
||||
|
||||
QtProfileSelectionDialog::~QtProfileSelectionDialog() = default;
|
||||
QtProfileSelectionDialog::~QtProfileSelectionDialog() {
|
||||
controller_navigation->UnloadController();
|
||||
};
|
||||
|
||||
int QtProfileSelectionDialog::exec() {
|
||||
// Skip profile selection when there's only one.
|
||||
|
@@ -10,6 +10,7 @@
|
||||
#include <QTreeView>
|
||||
#include "core/frontend/applets/profile_select.h"
|
||||
#include "core/hle/service/acc/profile_manager.h"
|
||||
#include "yuzu/controller_navigation.h"
|
||||
|
||||
class GMainWindow;
|
||||
class QDialogButtonBox;
|
||||
@@ -24,7 +25,7 @@ class QtProfileSelectionDialog final : public QDialog {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit QtProfileSelectionDialog(QWidget* parent);
|
||||
explicit QtProfileSelectionDialog(Core::HID::HIDCore& hid_core, QWidget* parent);
|
||||
~QtProfileSelectionDialog() override;
|
||||
|
||||
int exec() override;
|
||||
@@ -51,6 +52,7 @@ private:
|
||||
QDialogButtonBox* buttons;
|
||||
|
||||
std::unique_ptr<Service::Account::ProfileManager> profile_manager;
|
||||
ControllerNavigation* controller_navigation = nullptr;
|
||||
};
|
||||
|
||||
class QtProfileSelector final : public QObject, public Core::Frontend::ProfileSelectApplet {
|
||||
|
@@ -508,6 +508,7 @@ void Config::ReadDebuggingValues() {
|
||||
ReadBasicSetting(Settings::values.extended_logging);
|
||||
ReadBasicSetting(Settings::values.use_debug_asserts);
|
||||
ReadBasicSetting(Settings::values.use_auto_stub);
|
||||
ReadBasicSetting(Settings::values.enable_all_controllers);
|
||||
|
||||
qt_config->endGroup();
|
||||
}
|
||||
@@ -1051,6 +1052,7 @@ void Config::SaveDebuggingValues() {
|
||||
WriteBasicSetting(Settings::values.quest_flag);
|
||||
WriteBasicSetting(Settings::values.use_debug_asserts);
|
||||
WriteBasicSetting(Settings::values.disable_macro_jit);
|
||||
WriteBasicSetting(Settings::values.enable_all_controllers);
|
||||
|
||||
qt_config->endGroup();
|
||||
}
|
||||
|
@@ -42,6 +42,7 @@ void ConfigureDebug::SetConfiguration() {
|
||||
ui->quest_flag->setChecked(Settings::values.quest_flag.GetValue());
|
||||
ui->use_debug_asserts->setChecked(Settings::values.use_debug_asserts.GetValue());
|
||||
ui->use_auto_stub->setChecked(Settings::values.use_auto_stub.GetValue());
|
||||
ui->enable_all_controllers->setChecked(Settings::values.enable_all_controllers.GetValue());
|
||||
ui->enable_graphics_debugging->setEnabled(runtime_lock);
|
||||
ui->enable_graphics_debugging->setChecked(Settings::values.renderer_debug.GetValue());
|
||||
ui->enable_shader_feedback->setEnabled(runtime_lock);
|
||||
@@ -69,6 +70,7 @@ void ConfigureDebug::ApplyConfiguration() {
|
||||
Settings::values.quest_flag = ui->quest_flag->isChecked();
|
||||
Settings::values.use_debug_asserts = ui->use_debug_asserts->isChecked();
|
||||
Settings::values.use_auto_stub = ui->use_auto_stub->isChecked();
|
||||
Settings::values.enable_all_controllers = ui->enable_all_controllers->isChecked();
|
||||
Settings::values.renderer_debug = ui->enable_graphics_debugging->isChecked();
|
||||
Settings::values.renderer_shader_feedback = ui->enable_shader_feedback->isChecked();
|
||||
Settings::values.cpu_debug_mode = ui->enable_cpu_debugging->isChecked();
|
||||
|
@@ -211,6 +211,13 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QCheckBox" name="enable_all_controllers">
|
||||
<property name="text">
|
||||
<string>Enable all Controller Types</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
|
@@ -947,6 +947,40 @@ void ConfigureInputPlayer::SetConnectableControllers() {
|
||||
Core::HID::NpadStyleIndex::GameCube);
|
||||
ui->comboControllerType->addItem(tr("GameCube Controller"));
|
||||
}
|
||||
|
||||
// Disable all unsupported controllers
|
||||
if (!Settings::values.enable_all_controllers) {
|
||||
return;
|
||||
}
|
||||
if (enable_all || npad_style_set.palma == 1) {
|
||||
index_controller_type_pairs.emplace_back(ui->comboControllerType->count(),
|
||||
Core::HID::NpadStyleIndex::Pokeball);
|
||||
ui->comboControllerType->addItem(tr("Poke Ball Plus"));
|
||||
}
|
||||
|
||||
if (enable_all || npad_style_set.lark == 1) {
|
||||
index_controller_type_pairs.emplace_back(ui->comboControllerType->count(),
|
||||
Core::HID::NpadStyleIndex::NES);
|
||||
ui->comboControllerType->addItem(tr("NES Controller"));
|
||||
}
|
||||
|
||||
if (enable_all || npad_style_set.lucia == 1) {
|
||||
index_controller_type_pairs.emplace_back(ui->comboControllerType->count(),
|
||||
Core::HID::NpadStyleIndex::SNES);
|
||||
ui->comboControllerType->addItem(tr("SNES Controller"));
|
||||
}
|
||||
|
||||
if (enable_all || npad_style_set.lagoon == 1) {
|
||||
index_controller_type_pairs.emplace_back(ui->comboControllerType->count(),
|
||||
Core::HID::NpadStyleIndex::N64);
|
||||
ui->comboControllerType->addItem(tr("N64 Controller"));
|
||||
}
|
||||
|
||||
if (enable_all || npad_style_set.lager == 1) {
|
||||
index_controller_type_pairs.emplace_back(ui->comboControllerType->count(),
|
||||
Core::HID::NpadStyleIndex::SegaGenesis);
|
||||
ui->comboControllerType->addItem(tr("Sega Genesis"));
|
||||
}
|
||||
};
|
||||
|
||||
if (!is_powered_on) {
|
||||
|
160
src/yuzu/controller_navigation.cpp
Executable file
160
src/yuzu/controller_navigation.cpp
Executable file
@@ -0,0 +1,160 @@
|
||||
// Copyright 2021 yuzu Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included
|
||||
|
||||
#include "common/settings_input.h"
|
||||
#include "core/hid/emulated_controller.h"
|
||||
#include "core/hid/hid_core.h"
|
||||
#include "yuzu/controller_navigation.h"
|
||||
|
||||
ControllerNavigation::ControllerNavigation(Core::HID::HIDCore& hid_core, QWidget* parent) {
|
||||
controller = hid_core.GetEmulatedController(Core::HID::NpadIdType::Player1);
|
||||
Core::HID::ControllerUpdateCallback engine_callback{
|
||||
.on_change = [this](Core::HID::ControllerTriggerType type) { ControllerUpdateEvent(type); },
|
||||
.is_npad_service = false,
|
||||
};
|
||||
callback_key = controller->SetCallback(engine_callback);
|
||||
is_controller_set = true;
|
||||
}
|
||||
|
||||
ControllerNavigation::~ControllerNavigation() {
|
||||
UnloadController();
|
||||
}
|
||||
|
||||
void ControllerNavigation::UnloadController() {
|
||||
if (is_controller_set) {
|
||||
controller->DeleteCallback(callback_key);
|
||||
is_controller_set = false;
|
||||
}
|
||||
}
|
||||
|
||||
void ControllerNavigation::TriggerButton(const Core::HID::ButtonValues& buttons,
|
||||
Settings::NativeButton::Values native_button,
|
||||
Qt::Key key) {
|
||||
if (buttons[native_button].value && !button_values[native_button].locked) {
|
||||
emit TriggerKeyboardEvent(key);
|
||||
}
|
||||
}
|
||||
|
||||
void ControllerNavigation::ControllerUpdateEvent(Core::HID::ControllerTriggerType type) {
|
||||
if (type == Core::HID::ControllerTriggerType::Button) {
|
||||
const auto controller_type = controller->GetNpadStyleIndex();
|
||||
const auto& buttons = controller->GetButtonsValues();
|
||||
for (std::size_t i = 0; i < buttons.size(); ++i) {
|
||||
// Trigger only once
|
||||
if (buttons[i].value == button_values[i].value) {
|
||||
button_values[i].locked = true;
|
||||
} else {
|
||||
button_values[i].value = buttons[i].value;
|
||||
button_values[i].locked = false;
|
||||
}
|
||||
}
|
||||
|
||||
switch (controller_type) {
|
||||
case Core::HID::NpadStyleIndex::ProController:
|
||||
case Core::HID::NpadStyleIndex::JoyconDual:
|
||||
case Core::HID::NpadStyleIndex::Handheld:
|
||||
case Core::HID::NpadStyleIndex::GameCube:
|
||||
TriggerButton(buttons, Settings::NativeButton::A, Qt::Key_Enter);
|
||||
TriggerButton(buttons, Settings::NativeButton::B, Qt::Key_Escape);
|
||||
TriggerButton(buttons, Settings::NativeButton::DDown, Qt::Key_Down);
|
||||
TriggerButton(buttons, Settings::NativeButton::DLeft, Qt::Key_Left);
|
||||
TriggerButton(buttons, Settings::NativeButton::DRight, Qt::Key_Right);
|
||||
TriggerButton(buttons, Settings::NativeButton::DUp, Qt::Key_Up);
|
||||
break;
|
||||
case Core::HID::NpadStyleIndex::JoyconLeft:
|
||||
TriggerButton(buttons, Settings::NativeButton::DDown, Qt::Key_Enter);
|
||||
TriggerButton(buttons, Settings::NativeButton::DLeft, Qt::Key_Escape);
|
||||
break;
|
||||
case Core::HID::NpadStyleIndex::JoyconRight:
|
||||
TriggerButton(buttons, Settings::NativeButton::X, Qt::Key_Enter);
|
||||
TriggerButton(buttons, Settings::NativeButton::A, Qt::Key_Escape);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (type == Core::HID::ControllerTriggerType::Stick) {
|
||||
const auto controller_type = controller->GetNpadStyleIndex();
|
||||
const auto& sticks = controller->GetSticksValues();
|
||||
bool update = false;
|
||||
|
||||
for (std::size_t i = 0; i < sticks.size(); ++i) {
|
||||
// Trigger only once
|
||||
if (sticks[i].down != stick_values[i].down || sticks[i].left != stick_values[i].left ||
|
||||
sticks[i].right != stick_values[i].right || sticks[i].up != stick_values[i].up) {
|
||||
update = true;
|
||||
}
|
||||
stick_values[i] = sticks[i];
|
||||
}
|
||||
|
||||
if (!update) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (controller_type) {
|
||||
case Core::HID::NpadStyleIndex::ProController:
|
||||
case Core::HID::NpadStyleIndex::JoyconDual:
|
||||
case Core::HID::NpadStyleIndex::Handheld:
|
||||
case Core::HID::NpadStyleIndex::GameCube:
|
||||
if (sticks[Settings::NativeAnalog::LStick].down) {
|
||||
emit TriggerKeyboardEvent(Qt::Key_Down);
|
||||
return;
|
||||
}
|
||||
if (sticks[Settings::NativeAnalog::LStick].left) {
|
||||
emit TriggerKeyboardEvent(Qt::Key_Left);
|
||||
return;
|
||||
}
|
||||
if (sticks[Settings::NativeAnalog::LStick].right) {
|
||||
emit TriggerKeyboardEvent(Qt::Key_Right);
|
||||
return;
|
||||
}
|
||||
if (sticks[Settings::NativeAnalog::LStick].up) {
|
||||
emit TriggerKeyboardEvent(Qt::Key_Up);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case Core::HID::NpadStyleIndex::JoyconLeft:
|
||||
if (sticks[Settings::NativeAnalog::LStick].left) {
|
||||
emit TriggerKeyboardEvent(Qt::Key_Down);
|
||||
return;
|
||||
}
|
||||
if (sticks[Settings::NativeAnalog::LStick].up) {
|
||||
emit TriggerKeyboardEvent(Qt::Key_Left);
|
||||
return;
|
||||
}
|
||||
if (sticks[Settings::NativeAnalog::LStick].down) {
|
||||
emit TriggerKeyboardEvent(Qt::Key_Right);
|
||||
return;
|
||||
}
|
||||
if (sticks[Settings::NativeAnalog::LStick].right) {
|
||||
emit TriggerKeyboardEvent(Qt::Key_Up);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
case Core::HID::NpadStyleIndex::JoyconRight:
|
||||
if (sticks[Settings::NativeAnalog::RStick].right) {
|
||||
emit TriggerKeyboardEvent(Qt::Key_Down);
|
||||
return;
|
||||
}
|
||||
if (sticks[Settings::NativeAnalog::RStick].down) {
|
||||
emit TriggerKeyboardEvent(Qt::Key_Left);
|
||||
return;
|
||||
}
|
||||
if (sticks[Settings::NativeAnalog::RStick].up) {
|
||||
emit TriggerKeyboardEvent(Qt::Key_Right);
|
||||
return;
|
||||
}
|
||||
if (sticks[Settings::NativeAnalog::RStick].left) {
|
||||
emit TriggerKeyboardEvent(Qt::Key_Up);
|
||||
return;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
42
src/yuzu/controller_navigation.h
Executable file
42
src/yuzu/controller_navigation.h
Executable file
@@ -0,0 +1,42 @@
|
||||
// Copyright 2021 yuzu Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QKeyEvent>
|
||||
#include <QObject>
|
||||
|
||||
#include "common/input.h"
|
||||
#include "common/settings.h"
|
||||
#include "core/hid/emulated_controller.h"
|
||||
|
||||
namespace Core::HID {
|
||||
class HIDCore;
|
||||
} // namespace Core::HID
|
||||
|
||||
class ControllerNavigation : public QObject {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit ControllerNavigation(Core::HID::HIDCore& hid_core, QWidget* parent = nullptr);
|
||||
~ControllerNavigation();
|
||||
|
||||
/// Disables events from the emulated controller
|
||||
void UnloadController();
|
||||
|
||||
signals:
|
||||
void TriggerKeyboardEvent(Qt::Key key);
|
||||
|
||||
private:
|
||||
void TriggerButton(const Core::HID::ButtonValues& buttons,
|
||||
Settings::NativeButton::Values native_button, Qt::Key key);
|
||||
void ControllerUpdateEvent(Core::HID::ControllerTriggerType type);
|
||||
|
||||
Core::HID::ButtonValues button_values{};
|
||||
Core::HID::SticksValues stick_values{};
|
||||
|
||||
int callback_key;
|
||||
bool is_controller_set{};
|
||||
Core::HID::EmulatedController* controller;
|
||||
};
|
@@ -17,6 +17,7 @@
|
||||
#include <fmt/format.h>
|
||||
#include "common/common_types.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "core/core.h"
|
||||
#include "core/file_sys/patch_manager.h"
|
||||
#include "core/file_sys/registered_cache.h"
|
||||
#include "yuzu/compatibility_list.h"
|
||||
@@ -312,6 +313,7 @@ GameList::GameList(FileSys::VirtualFilesystem vfs, FileSys::ManualContentProvide
|
||||
this->main_window = parent;
|
||||
layout = new QVBoxLayout;
|
||||
tree_view = new QTreeView;
|
||||
controller_navigation = new ControllerNavigation(system.HIDCore(), this);
|
||||
search_field = new GameListSearchField(this);
|
||||
item_model = new QStandardItemModel(tree_view);
|
||||
tree_view->setModel(item_model);
|
||||
@@ -341,6 +343,18 @@ GameList::GameList(FileSys::VirtualFilesystem vfs, FileSys::ManualContentProvide
|
||||
connect(tree_view, &QTreeView::customContextMenuRequested, this, &GameList::PopupContextMenu);
|
||||
connect(tree_view, &QTreeView::expanded, this, &GameList::OnItemExpanded);
|
||||
connect(tree_view, &QTreeView::collapsed, this, &GameList::OnItemExpanded);
|
||||
connect(controller_navigation, &ControllerNavigation::TriggerKeyboardEvent,
|
||||
[this](Qt::Key key) {
|
||||
// Avoid pressing buttons while playing
|
||||
if (system.IsPoweredOn()) {
|
||||
return;
|
||||
}
|
||||
if (!this->isActiveWindow()) {
|
||||
return;
|
||||
}
|
||||
QKeyEvent* event = new QKeyEvent(QEvent::KeyPress, key, Qt::NoModifier);
|
||||
QCoreApplication::postEvent(tree_view, event);
|
||||
});
|
||||
|
||||
// We must register all custom types with the Qt Automoc system so that we are able to use
|
||||
// it with signals/slots. In this case, QList falls under the umbrells of custom types.
|
||||
@@ -353,7 +367,12 @@ GameList::GameList(FileSys::VirtualFilesystem vfs, FileSys::ManualContentProvide
|
||||
setLayout(layout);
|
||||
}
|
||||
|
||||
void GameList::UnloadController() {
|
||||
controller_navigation->UnloadController();
|
||||
}
|
||||
|
||||
GameList::~GameList() {
|
||||
UnloadController();
|
||||
emit ShouldCancelWorker();
|
||||
}
|
||||
|
||||
|
@@ -23,6 +23,7 @@
|
||||
#include "common/common_types.h"
|
||||
#include "uisettings.h"
|
||||
#include "yuzu/compatibility_list.h"
|
||||
#include "yuzu/controller_navigation.h"
|
||||
|
||||
class GameListWorker;
|
||||
class GameListSearchField;
|
||||
@@ -88,6 +89,9 @@ public:
|
||||
void SaveInterfaceLayout();
|
||||
void LoadInterfaceLayout();
|
||||
|
||||
/// Disables events from the emulated controller
|
||||
void UnloadController();
|
||||
|
||||
static const QStringList supported_file_extensions;
|
||||
|
||||
signals:
|
||||
@@ -143,6 +147,7 @@ private:
|
||||
QStandardItemModel* item_model = nullptr;
|
||||
GameListWorker* current_worker = nullptr;
|
||||
QFileSystemWatcher* watcher = nullptr;
|
||||
ControllerNavigation* controller_navigation = nullptr;
|
||||
CompatibilityList compatibility_list;
|
||||
|
||||
friend class GameListSearchField;
|
||||
|
@@ -449,7 +449,7 @@ void GMainWindow::ControllerSelectorReconfigureControllers(
|
||||
}
|
||||
|
||||
void GMainWindow::ProfileSelectorSelectProfile() {
|
||||
QtProfileSelectionDialog dialog(this);
|
||||
QtProfileSelectionDialog dialog(system->HIDCore(), this);
|
||||
dialog.setWindowFlags(Qt::Dialog | Qt::CustomizeWindowHint | Qt::WindowStaysOnTopHint |
|
||||
Qt::WindowTitleHint | Qt::WindowSystemMenuHint |
|
||||
Qt::WindowCloseButtonHint);
|
||||
@@ -1346,7 +1346,7 @@ bool GMainWindow::LoadROM(const QString& filename, u64 program_id, std::size_t p
|
||||
}
|
||||
|
||||
void GMainWindow::SelectAndSetCurrentUser() {
|
||||
QtProfileSelectionDialog dialog(this);
|
||||
QtProfileSelectionDialog dialog(system->HIDCore(), this);
|
||||
dialog.setWindowFlags(Qt::Dialog | Qt::CustomizeWindowHint | Qt::WindowTitleHint |
|
||||
Qt::WindowSystemMenuHint | Qt::WindowCloseButtonHint);
|
||||
dialog.setWindowModality(Qt::WindowModal);
|
||||
@@ -1608,7 +1608,7 @@ void GMainWindow::OnGameListOpenFolder(u64 program_id, GameListOpenTarget target
|
||||
if (has_user_save) {
|
||||
// User save data
|
||||
const auto select_profile = [this] {
|
||||
QtProfileSelectionDialog dialog(this);
|
||||
QtProfileSelectionDialog dialog(system->HIDCore(), this);
|
||||
dialog.setWindowFlags(Qt::Dialog | Qt::CustomizeWindowHint | Qt::WindowTitleHint |
|
||||
Qt::WindowSystemMenuHint | Qt::WindowCloseButtonHint);
|
||||
dialog.setWindowModality(Qt::WindowModal);
|
||||
@@ -3376,7 +3376,10 @@ void GMainWindow::closeEvent(QCloseEvent* event) {
|
||||
UpdateUISettings();
|
||||
game_list->SaveInterfaceLayout();
|
||||
hotkey_registry.SaveHotkeys();
|
||||
|
||||
// Unload controllers early
|
||||
controller_dialog->UnloadController();
|
||||
game_list->UnloadController();
|
||||
system->HIDCore().UnloadInputDevices();
|
||||
|
||||
// Shutdown session if the emu thread is active...
|
||||
|
Reference in New Issue
Block a user