Compare commits

..

13 Commits

Author SHA1 Message Date
872825d4aa Android 197 2024-01-19 01:00:45 +00:00
ed294d35d4 Merge yuzu-emu#12701 2024-01-19 01:00:45 +00:00
5f4efa456d Merge yuzu-emu#12688 2024-01-19 01:00:45 +00:00
e52e4871ff Merge yuzu-emu#12687 2024-01-19 01:00:45 +00:00
5e45e469d3 Merge yuzu-emu#12683 2024-01-19 01:00:45 +00:00
760e601a00 Merge yuzu-emu#12678 2024-01-19 01:00:45 +00:00
dfb63caefc Merge yuzu-emu#12660 2024-01-19 01:00:45 +00:00
0409886ebb Merge yuzu-emu#12644 2024-01-19 01:00:45 +00:00
803ccd7a57 Merge yuzu-emu#12579 2024-01-19 01:00:44 +00:00
3092855d5a Merge pull request #12702 from german77/android-input
input_common: Add android input engine
2024-01-18 09:16:58 -05:00
72f803c366 input_common: Add android input engine 2024-01-17 22:47:56 -06:00
c87b96435d Merge pull request #12699 from t895/overlay-saving
android: Save overlay data while using emulation fragment
2024-01-17 22:56:40 -05:00
116f76e4b6 android: Save overlay data while using emulation fragment
This should have been fully embraced before but the items within the popup menu and the adjust controls dialog fell through. This ensures that everything related to the overlay is saved during emulation and can't be lost during a crash.
2024-01-17 20:14:25 -05:00
63 changed files with 1947 additions and 1122 deletions

View File

@ -2,7 +2,12 @@
|----|----|----|----|----|
| [12579](https://github.com/yuzu-emu/yuzu-android//pull/12579) | [`93ef41f03`](https://github.com/yuzu-emu/yuzu-android//pull/12579/files) | Core: Implement Device Mapping & GPU SMMU | [FernandoS27](https://github.com/FernandoS27/) | Yes |
| [12644](https://github.com/yuzu-emu/yuzu-android//pull/12644) | [`2044a289f`](https://github.com/yuzu-emu/yuzu-android//pull/12644/files) | shader_recompiler: fix Offset operand usage for non-OpImage*Gather | [liamwhite](https://github.com/liamwhite/) | Yes |
| [12660](https://github.com/yuzu-emu/yuzu-android//pull/12660) | [`2cacb9d48`](https://github.com/yuzu-emu/yuzu-android//pull/12660/files) | service: hid: Fully implement abstract vibration | [german77](https://github.com/german77/) | Yes |
| [12678](https://github.com/yuzu-emu/yuzu-android//pull/12678) | [`7f5adf898`](https://github.com/yuzu-emu/yuzu-android//pull/12678/files) | service: set: Implement stubbed functions | [german77](https://github.com/german77/) | Yes |
| [12683](https://github.com/yuzu-emu/yuzu-android//pull/12683) | [`c661b9586`](https://github.com/yuzu-emu/yuzu-android//pull/12683/files) | service: nfc: Create backup when none exist | [german77](https://github.com/german77/) | Yes |
| [12687](https://github.com/yuzu-emu/yuzu-android//pull/12687) | [`0b0e9ef18`](https://github.com/yuzu-emu/yuzu-android//pull/12687/files) | core: hid: Disable special features before disconnecting the controllers | [german77](https://github.com/german77/) | Yes |
| [12688](https://github.com/yuzu-emu/yuzu-android//pull/12688) | [`e9eb017aa`](https://github.com/yuzu-emu/yuzu-android//pull/12688/files) | renderer_vulkan: recreate swapchain when frame size changes | [liamwhite](https://github.com/liamwhite/) | Yes |
| [12701](https://github.com/yuzu-emu/yuzu-android//pull/12701) | [`e4bbb24dc`](https://github.com/yuzu-emu/yuzu-android//pull/12701/files) | vi: check layer state before opening or closing | [liamwhite](https://github.com/liamwhite/) | Yes |
End of merge log. You can find the original README.md below the break.

View File

@ -49,7 +49,6 @@ import org.yuzu.yuzu_emu.utils.ForegroundService
import org.yuzu.yuzu_emu.utils.InputHandler
import org.yuzu.yuzu_emu.utils.Log
import org.yuzu.yuzu_emu.utils.MemoryUtil
import org.yuzu.yuzu_emu.utils.NativeConfig
import org.yuzu.yuzu_emu.utils.NfcReader
import org.yuzu.yuzu_emu.utils.ThemeHelper
import java.text.NumberFormat
@ -171,11 +170,6 @@ class EmulationActivity : AppCompatActivity(), SensorEventListener {
stopMotionSensorListener()
}
override fun onStop() {
super.onStop()
NativeConfig.saveGlobalConfig()
}
override fun onUserLeaveHint() {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.S) {
if (BooleanSetting.PICTURE_IN_PICTURE.getBoolean() && !isInPictureInPictureMode) {

View File

@ -554,6 +554,7 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
findItem(R.id.menu_touchscreen).isChecked = BooleanSetting.TOUCHSCREEN.getBoolean()
}
popup.setOnDismissListener { NativeConfig.saveGlobalConfig() }
popup.setOnMenuItemClickListener {
when (it.itemId) {
R.id.menu_toggle_fps -> {
@ -720,7 +721,9 @@ class EmulationFragment : Fragment(), SurfaceHolder.Callback {
MaterialAlertDialogBuilder(requireContext())
.setTitle(R.string.emulation_control_adjust)
.setView(adjustBinding.root)
.setPositiveButton(android.R.string.ok, null)
.setPositiveButton(android.R.string.ok) { _: DialogInterface?, _: Int ->
NativeConfig.saveGlobalConfig()
}
.setNeutralButton(R.string.slider_default) { _: DialogInterface?, _: Int ->
setControlScale(50)
setControlOpacity(100)

View File

@ -716,22 +716,23 @@ add_library(core STATIC
hle/service/server_manager.h
hle/service/service.cpp
hle/service/service.h
hle/service/set/appln_settings.cpp
hle/service/set/appln_settings.h
hle/service/set/device_settings.cpp
hle/service/set/device_settings.h
hle/service/set/setting_formats/appln_settings.cpp
hle/service/set/setting_formats/appln_settings.h
hle/service/set/setting_formats/device_settings.cpp
hle/service/set/setting_formats/device_settings.h
hle/service/set/setting_formats/system_settings.cpp
hle/service/set/setting_formats/system_settings.h
hle/service/set/setting_formats/private_settings.cpp
hle/service/set/setting_formats/private_settings.h
hle/service/set/factory_settings_server.cpp
hle/service/set/factory_settings_server.h
hle/service/set/firmware_debug_settings_server.cpp
hle/service/set/firmware_debug_settings_server.h
hle/service/set/private_settings.cpp
hle/service/set/private_settings.h
hle/service/set/settings.cpp
hle/service/set/settings.h
hle/service/set/settings_server.cpp
hle/service/set/settings_server.h
hle/service/set/system_settings.cpp
hle/service/set/system_settings.h
hle/service/set/settings_types.h
hle/service/set/system_settings_server.cpp
hle/service/set/system_settings_server.h
hle/service/sm/sm.cpp

View File

@ -20,12 +20,13 @@ void LoopProcess(Core::System& system) {
auto server_manager = std::make_unique<ServerManager>(system);
std::shared_ptr<ResourceManager> resource_manager = std::make_shared<ResourceManager>(system);
std::shared_ptr<HidFirmwareSettings> firmware_settings =
std::make_shared<HidFirmwareSettings>();
std::make_shared<HidFirmwareSettings>(system);
// TODO: Remove this hack when am is emulated properly.
resource_manager->Initialize();
resource_manager->RegisterAppletResourceUserId(system.ApplicationProcess()->GetProcessId(),
true);
resource_manager->SetAruidValidForVibration(system.ApplicationProcess()->GetProcessId(), true);
server_manager->RegisterNamedService(
"hid", std::make_shared<IHidServer>(system, resource_manager, firmware_settings));

View File

@ -22,12 +22,16 @@
#include "hid_core/resources/mouse/mouse.h"
#include "hid_core/resources/npad/npad.h"
#include "hid_core/resources/npad/npad_types.h"
#include "hid_core/resources/npad/npad_vibration.h"
#include "hid_core/resources/palma/palma.h"
#include "hid_core/resources/six_axis/console_six_axis.h"
#include "hid_core/resources/six_axis/seven_six_axis.h"
#include "hid_core/resources/six_axis/six_axis.h"
#include "hid_core/resources/touch_screen/gesture.h"
#include "hid_core/resources/touch_screen/touch_screen.h"
#include "hid_core/resources/vibration/gc_vibration_device.h"
#include "hid_core/resources/vibration/n64_vibration_device.h"
#include "hid_core/resources/vibration/vibration_device.h"
namespace Service::HID {
@ -38,7 +42,7 @@ public:
: ServiceFramework{system_, "IActiveVibrationDeviceList"}, resource_manager(resource) {
// clang-format off
static const FunctionInfo functions[] = {
{0, &IActiveVibrationDeviceList::InitializeVibrationDevice, "InitializeVibrationDevice"},
{0, &IActiveVibrationDeviceList::ActivateVibrationDevice, "ActivateVibrationDevice"},
};
// clang-format on
@ -46,22 +50,49 @@ public:
}
private:
void InitializeVibrationDevice(HLERequestContext& ctx) {
void ActivateVibrationDevice(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto vibration_device_handle{rp.PopRaw<Core::HID::VibrationDeviceHandle>()};
if (resource_manager != nullptr && resource_manager->GetNpad()) {
resource_manager->GetNpad()->InitializeVibrationDevice(vibration_device_handle);
}
LOG_DEBUG(Service_HID, "called, npad_type={}, npad_id={}, device_index={}",
vibration_device_handle.npad_type, vibration_device_handle.npad_id,
vibration_device_handle.device_index);
const auto result = ActivateVibrationDeviceImpl(vibration_device_handle);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
rb.Push(result);
}
Result ActivateVibrationDeviceImpl(const Core::HID::VibrationDeviceHandle& handle) {
std::scoped_lock lock{mutex};
const Result is_valid = IsVibrationHandleValid(handle);
if (is_valid.IsError()) {
return is_valid;
}
for (std::size_t i = 0; i < list_size; i++) {
if (handle.device_index == vibration_device_list[i].device_index &&
handle.npad_id == vibration_device_list[i].npad_id &&
handle.npad_type == vibration_device_list[i].npad_type) {
return ResultSuccess;
}
}
if (list_size == vibration_device_list.size()) {
return ResultVibrationDeviceIndexOutOfRange;
}
const Result result = resource_manager->GetVibrationDevice(handle)->Activate();
if (result.IsError()) {
return result;
}
vibration_device_list[list_size++] = handle;
return ResultSuccess;
}
mutable std::mutex mutex;
std::size_t list_size{};
std::array<Core::HID::VibrationDeviceHandle, 0x100> vibration_device_list{};
std::shared_ptr<ResourceManager> resource_manager;
};
@ -153,7 +184,7 @@ IHidServer::IHidServer(Core::System& system_, std::shared_ptr<ResourceManager> r
{209, &IHidServer::BeginPermitVibrationSession, "BeginPermitVibrationSession"},
{210, &IHidServer::EndPermitVibrationSession, "EndPermitVibrationSession"},
{211, &IHidServer::IsVibrationDeviceMounted, "IsVibrationDeviceMounted"},
{212, nullptr, "SendVibrationValueInBool"},
{212, &IHidServer::SendVibrationValueInBool, "SendVibrationValueInBool"},
{300, &IHidServer::ActivateConsoleSixAxisSensor, "ActivateConsoleSixAxisSensor"},
{301, &IHidServer::StartConsoleSixAxisSensor, "StartConsoleSixAxisSensor"},
{302, &IHidServer::StopConsoleSixAxisSensor, "StopConsoleSixAxisSensor"},
@ -1492,59 +1523,13 @@ void IHidServer::ClearNpadCaptureButtonAssignment(HLERequestContext& ctx) {
void IHidServer::GetVibrationDeviceInfo(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto vibration_device_handle{rp.PopRaw<Core::HID::VibrationDeviceHandle>()};
const auto controller = GetResourceManager()->GetNpad();
Core::HID::VibrationDeviceInfo vibration_device_info;
bool check_device_index = false;
switch (vibration_device_handle.npad_type) {
case Core::HID::NpadStyleIndex::Fullkey:
case Core::HID::NpadStyleIndex::Handheld:
case Core::HID::NpadStyleIndex::JoyconDual:
case Core::HID::NpadStyleIndex::JoyconLeft:
case Core::HID::NpadStyleIndex::JoyconRight:
vibration_device_info.type = Core::HID::VibrationDeviceType::LinearResonantActuator;
check_device_index = true;
break;
case Core::HID::NpadStyleIndex::GameCube:
vibration_device_info.type = Core::HID::VibrationDeviceType::GcErm;
break;
case Core::HID::NpadStyleIndex::N64:
vibration_device_info.type = Core::HID::VibrationDeviceType::N64;
break;
default:
vibration_device_info.type = Core::HID::VibrationDeviceType::Unknown;
break;
}
vibration_device_info.position = Core::HID::VibrationDevicePosition::None;
if (check_device_index) {
switch (vibration_device_handle.device_index) {
case Core::HID::DeviceIndex::Left:
vibration_device_info.position = Core::HID::VibrationDevicePosition::Left;
break;
case Core::HID::DeviceIndex::Right:
vibration_device_info.position = Core::HID::VibrationDevicePosition::Right;
break;
case Core::HID::DeviceIndex::None:
default:
ASSERT_MSG(false, "DeviceIndex should never be None!");
break;
}
}
LOG_DEBUG(Service_HID, "called, vibration_device_type={}, vibration_device_position={}",
vibration_device_info.type, vibration_device_info.position);
const auto result = IsVibrationHandleValid(vibration_device_handle);
if (result.IsError()) {
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(result);
return;
}
Core::HID::VibrationDeviceInfo vibration_device_info{};
const auto result = GetResourceManager()->GetVibrationDeviceInfo(vibration_device_info,
vibration_device_handle);
IPC::ResponseBuilder rb{ctx, 4};
rb.Push(ResultSuccess);
rb.Push(result);
rb.PushRaw(vibration_device_info);
}
@ -1560,16 +1545,16 @@ void IHidServer::SendVibrationValue(HLERequestContext& ctx) {
const auto parameters{rp.PopRaw<Parameters>()};
GetResourceManager()->GetNpad()->VibrateController(parameters.applet_resource_user_id,
parameters.vibration_device_handle,
parameters.vibration_value);
LOG_DEBUG(Service_HID,
"called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}",
parameters.vibration_device_handle.npad_type,
parameters.vibration_device_handle.npad_id,
parameters.vibration_device_handle.device_index, parameters.applet_resource_user_id);
GetResourceManager()->SendVibrationValue(parameters.applet_resource_user_id,
parameters.vibration_device_handle,
parameters.vibration_value);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
@ -1591,10 +1576,28 @@ void IHidServer::GetActualVibrationValue(HLERequestContext& ctx) {
parameters.vibration_device_handle.npad_id,
parameters.vibration_device_handle.device_index, parameters.applet_resource_user_id);
bool has_active_aruid{};
NpadVibrationDevice* device{nullptr};
Core::HID::VibrationValue vibration_value{};
Result result = GetResourceManager()->IsVibrationAruidActive(parameters.applet_resource_user_id,
has_active_aruid);
if (result.IsSuccess() && has_active_aruid) {
result = IsVibrationHandleValid(parameters.vibration_device_handle);
}
if (result.IsSuccess() && has_active_aruid) {
device = GetResourceManager()->GetNSVibrationDevice(parameters.vibration_device_handle);
}
if (device != nullptr) {
result = device->GetActualVibrationValue(vibration_value);
}
if (result.IsError()) {
vibration_value = Core::HID::DEFAULT_VIBRATION_VALUE;
}
IPC::ResponseBuilder rb{ctx, 6};
rb.Push(ResultSuccess);
rb.PushRaw(GetResourceManager()->GetNpad()->GetLastVibration(
parameters.applet_resource_user_id, parameters.vibration_device_handle));
rb.PushRaw(vibration_value);
}
void IHidServer::CreateActiveVibrationDeviceList(HLERequestContext& ctx) {
@ -1609,25 +1612,27 @@ void IHidServer::PermitVibration(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto can_vibrate{rp.Pop<bool>()};
// nnSDK saves this value as a float. Since it can only be 1.0f or 0.0f we simplify this value
// by converting it to a bool
Settings::values.vibration_enabled.SetValue(can_vibrate);
LOG_DEBUG(Service_HID, "called, can_vibrate={}", can_vibrate);
const auto result =
GetResourceManager()->GetNpad()->GetVibrationHandler()->SetVibrationMasterVolume(
can_vibrate ? 1.0f : 0.0f);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
rb.Push(result);
}
void IHidServer::IsVibrationPermitted(HLERequestContext& ctx) {
LOG_DEBUG(Service_HID, "called");
// nnSDK checks if a float is greater than zero. We return the bool we stored earlier
const auto is_enabled = Settings::values.vibration_enabled.GetValue();
f32 master_volume{};
const auto result =
GetResourceManager()->GetNpad()->GetVibrationHandler()->GetVibrationMasterVolume(
master_volume);
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
rb.Push(is_enabled);
rb.Push(result);
rb.Push(master_volume > 0.0f);
}
void IHidServer::SendVibrationValues(HLERequestContext& ctx) {
@ -1645,13 +1650,22 @@ void IHidServer::SendVibrationValues(HLERequestContext& ctx) {
auto vibration_values = std::span(
reinterpret_cast<const Core::HID::VibrationValue*>(vibration_data.data()), vibration_count);
GetResourceManager()->GetNpad()->VibrateControllers(applet_resource_user_id,
vibration_device_handles, vibration_values);
LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
Result result = ResultSuccess;
if (handle_count != vibration_count) {
result = ResultVibrationArraySizeMismatch;
}
for (std::size_t i = 0; i < handle_count; i++) {
if (result.IsSuccess()) {
result = GetResourceManager()->SendVibrationValue(
applet_resource_user_id, vibration_device_handles[i], vibration_values[i]);
}
}
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
rb.Push(result);
}
void IHidServer::SendVibrationGcErmCommand(HLERequestContext& ctx) {
@ -1666,43 +1680,6 @@ void IHidServer::SendVibrationGcErmCommand(HLERequestContext& ctx) {
const auto parameters{rp.PopRaw<Parameters>()};
/**
* Note: This uses yuzu-specific behavior such that the StopHard command produces
* vibrations where freq_low == 0.0f and freq_high == 0.0f, as defined below,
* in order to differentiate between Stop and StopHard commands.
* This is done to reuse the controller vibration functions made for regular controllers.
*/
const auto vibration_value = [parameters] {
switch (parameters.gc_erm_command) {
case Core::HID::VibrationGcErmCommand::Stop:
return Core::HID::VibrationValue{
.low_amplitude = 0.0f,
.low_frequency = 160.0f,
.high_amplitude = 0.0f,
.high_frequency = 320.0f,
};
case Core::HID::VibrationGcErmCommand::Start:
return Core::HID::VibrationValue{
.low_amplitude = 1.0f,
.low_frequency = 160.0f,
.high_amplitude = 1.0f,
.high_frequency = 320.0f,
};
case Core::HID::VibrationGcErmCommand::StopHard:
return Core::HID::VibrationValue{
.low_amplitude = 0.0f,
.low_frequency = 0.0f,
.high_amplitude = 0.0f,
.high_frequency = 0.0f,
};
default:
return Core::HID::DEFAULT_VIBRATION_VALUE;
}
}();
GetResourceManager()->GetNpad()->VibrateController(
parameters.applet_resource_user_id, parameters.vibration_device_handle, vibration_value);
LOG_DEBUG(Service_HID,
"called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}, "
"gc_erm_command={}",
@ -1711,8 +1688,23 @@ void IHidServer::SendVibrationGcErmCommand(HLERequestContext& ctx) {
parameters.vibration_device_handle.device_index, parameters.applet_resource_user_id,
parameters.gc_erm_command);
bool has_active_aruid{};
NpadGcVibrationDevice* gc_device{nullptr};
Result result = GetResourceManager()->IsVibrationAruidActive(parameters.applet_resource_user_id,
has_active_aruid);
if (result.IsSuccess() && has_active_aruid) {
result = IsVibrationHandleValid(parameters.vibration_device_handle);
}
if (result.IsSuccess() && has_active_aruid) {
gc_device = GetResourceManager()->GetGcVibrationDevice(parameters.vibration_device_handle);
}
if (gc_device != nullptr) {
result = gc_device->SendVibrationGcErmCommand(parameters.gc_erm_command);
}
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
rb.Push(result);
}
void IHidServer::GetActualVibrationGcErmCommand(HLERequestContext& ctx) {
@ -1725,33 +1717,31 @@ void IHidServer::GetActualVibrationGcErmCommand(HLERequestContext& ctx) {
const auto parameters{rp.PopRaw<Parameters>()};
const auto last_vibration = GetResourceManager()->GetNpad()->GetLastVibration(
parameters.applet_resource_user_id, parameters.vibration_device_handle);
const auto gc_erm_command = [last_vibration] {
if (last_vibration.low_amplitude != 0.0f || last_vibration.high_amplitude != 0.0f) {
return Core::HID::VibrationGcErmCommand::Start;
}
/**
* Note: This uses yuzu-specific behavior such that the StopHard command produces
* vibrations where freq_low == 0.0f and freq_high == 0.0f, as defined in the HID function
* SendVibrationGcErmCommand, in order to differentiate between Stop and StopHard commands.
* This is done to reuse the controller vibration functions made for regular controllers.
*/
if (last_vibration.low_frequency == 0.0f && last_vibration.high_frequency == 0.0f) {
return Core::HID::VibrationGcErmCommand::StopHard;
}
return Core::HID::VibrationGcErmCommand::Stop;
}();
LOG_DEBUG(Service_HID,
"called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}",
parameters.vibration_device_handle.npad_type,
parameters.vibration_device_handle.npad_id,
parameters.vibration_device_handle.device_index, parameters.applet_resource_user_id);
bool has_active_aruid{};
NpadGcVibrationDevice* gc_device{nullptr};
Core::HID::VibrationGcErmCommand gc_erm_command{};
Result result = GetResourceManager()->IsVibrationAruidActive(parameters.applet_resource_user_id,
has_active_aruid);
if (result.IsSuccess() && has_active_aruid) {
result = IsVibrationHandleValid(parameters.vibration_device_handle);
}
if (result.IsSuccess() && has_active_aruid) {
gc_device = GetResourceManager()->GetGcVibrationDevice(parameters.vibration_device_handle);
}
if (gc_device != nullptr) {
result = gc_device->GetActualVibrationGcErmCommand(gc_erm_command);
}
if (result.IsError()) {
gc_erm_command = Core::HID::VibrationGcErmCommand::Stop;
}
IPC::ResponseBuilder rb{ctx, 4};
rb.Push(ResultSuccess);
rb.PushEnum(gc_erm_command);
@ -1761,21 +1751,24 @@ void IHidServer::BeginPermitVibrationSession(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto applet_resource_user_id{rp.Pop<u64>()};
GetResourceManager()->GetNpad()->SetPermitVibrationSession(true);
LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
const auto result =
GetResourceManager()->GetNpad()->GetVibrationHandler()->BeginPermitVibrationSession(
applet_resource_user_id);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
rb.Push(result);
}
void IHidServer::EndPermitVibrationSession(HLERequestContext& ctx) {
GetResourceManager()->GetNpad()->SetPermitVibrationSession(false);
LOG_DEBUG(Service_HID, "called");
const auto result =
GetResourceManager()->GetNpad()->GetVibrationHandler()->EndPermitVibrationSession();
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
rb.Push(result);
}
void IHidServer::IsVibrationDeviceMounted(HLERequestContext& ctx) {
@ -1795,10 +1788,61 @@ void IHidServer::IsVibrationDeviceMounted(HLERequestContext& ctx) {
parameters.vibration_device_handle.npad_id,
parameters.vibration_device_handle.device_index, parameters.applet_resource_user_id);
bool is_mounted{};
NpadVibrationBase* device{nullptr};
Result result = IsVibrationHandleValid(parameters.vibration_device_handle);
if (result.IsSuccess()) {
device = GetResourceManager()->GetVibrationDevice(parameters.vibration_device_handle);
}
if (device != nullptr) {
is_mounted = device->IsVibrationMounted();
}
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
rb.Push(GetResourceManager()->GetNpad()->IsVibrationDeviceMounted(
parameters.applet_resource_user_id, parameters.vibration_device_handle));
rb.Push(result);
rb.Push(is_mounted);
}
void IHidServer::SendVibrationValueInBool(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
struct Parameters {
Core::HID::VibrationDeviceHandle vibration_device_handle;
INSERT_PADDING_WORDS_NOINIT(1);
u64 applet_resource_user_id;
bool is_vibrating;
};
static_assert(sizeof(Parameters) == 0x18, "Parameters has incorrect size.");
const auto parameters{rp.PopRaw<Parameters>()};
LOG_DEBUG(Service_HID,
"called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}, "
"is_vibrating={}",
parameters.vibration_device_handle.npad_type,
parameters.vibration_device_handle.npad_id,
parameters.vibration_device_handle.device_index, parameters.applet_resource_user_id,
parameters.is_vibrating);
bool has_active_aruid{};
NpadN64VibrationDevice* n64_device{nullptr};
Result result = GetResourceManager()->IsVibrationAruidActive(parameters.applet_resource_user_id,
has_active_aruid);
if (result.IsSuccess() && has_active_aruid) {
result = IsVibrationHandleValid(parameters.vibration_device_handle);
}
if (result.IsSuccess() && has_active_aruid) {
n64_device =
GetResourceManager()->GetN64VibrationDevice(parameters.vibration_device_handle);
}
if (n64_device != nullptr) {
result = n64_device->SendValueInBool(parameters.is_vibrating);
}
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(result);
}
void IHidServer::ActivateConsoleSixAxisSensor(HLERequestContext& ctx) {

View File

@ -97,6 +97,7 @@ private:
void BeginPermitVibrationSession(HLERequestContext& ctx);
void EndPermitVibrationSession(HLERequestContext& ctx);
void IsVibrationDeviceMounted(HLERequestContext& ctx);
void SendVibrationValueInBool(HLERequestContext& ctx);
void ActivateConsoleSixAxisSensor(HLERequestContext& ctx);
void StartConsoleSixAxisSensor(HLERequestContext& ctx);
void StopConsoleSixAxisSensor(HLERequestContext& ctx);

View File

@ -7,6 +7,7 @@
#include "hid_core/resource_manager.h"
#include "hid_core/resources/npad/npad.h"
#include "hid_core/resources/npad/npad_types.h"
#include "hid_core/resources/npad/npad_vibration.h"
#include "hid_core/resources/palma/palma.h"
#include "hid_core/resources/touch_screen/touch_screen.h"
@ -67,14 +68,14 @@ IHidSystemServer::IHidSystemServer(Core::System& system_, std::shared_ptr<Resour
{501, &IHidSystemServer::RegisterAppletResourceUserId, "RegisterAppletResourceUserId"},
{502, &IHidSystemServer::UnregisterAppletResourceUserId, "UnregisterAppletResourceUserId"},
{503, &IHidSystemServer::EnableAppletToGetInput, "EnableAppletToGetInput"},
{504, nullptr, "SetAruidValidForVibration"},
{504, &IHidSystemServer::SetAruidValidForVibration, "SetAruidValidForVibration"},
{505, &IHidSystemServer::EnableAppletToGetSixAxisSensor, "EnableAppletToGetSixAxisSensor"},
{506, &IHidSystemServer::EnableAppletToGetPadInput, "EnableAppletToGetPadInput"},
{507, &IHidSystemServer::EnableAppletToGetTouchScreen, "EnableAppletToGetTouchScreen"},
{510, nullptr, "SetVibrationMasterVolume"},
{511, nullptr, "GetVibrationMasterVolume"},
{512, nullptr, "BeginPermitVibrationSession"},
{513, nullptr, "EndPermitVibrationSession"},
{510, &IHidSystemServer::SetVibrationMasterVolume, "SetVibrationMasterVolume"},
{511, &IHidSystemServer::GetVibrationMasterVolume, "GetVibrationMasterVolume"},
{512, &IHidSystemServer::BeginPermitVibrationSession, "BeginPermitVibrationSession"},
{513, &IHidSystemServer::EndPermitVibrationSession, "EndPermitVibrationSession"},
{514, nullptr, "Unknown514"},
{520, nullptr, "EnableHandheldHids"},
{521, nullptr, "DisableHandheldHids"},
@ -156,7 +157,7 @@ IHidSystemServer::IHidSystemServer(Core::System& system_, std::shared_ptr<Resour
{1152, nullptr, "SetTouchScreenDefaultConfiguration"},
{1153, &IHidSystemServer::GetTouchScreenDefaultConfiguration, "GetTouchScreenDefaultConfiguration"},
{1154, nullptr, "IsFirmwareAvailableForNotification"},
{1155, nullptr, "SetForceHandheldStyleVibration"},
{1155, &IHidSystemServer::SetForceHandheldStyleVibration, "SetForceHandheldStyleVibration"},
{1156, nullptr, "SendConnectionTriggerWithoutTimeoutEvent"},
{1157, nullptr, "CancelConnectionTrigger"},
{1200, nullptr, "IsButtonConfigSupported"},
@ -538,6 +539,27 @@ void IHidSystemServer::EnableAppletToGetInput(HLERequestContext& ctx) {
rb.Push(ResultSuccess);
}
void IHidSystemServer::SetAruidValidForVibration(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
struct Parameters {
bool is_enabled;
INSERT_PADDING_WORDS_NOINIT(1);
u64 applet_resource_user_id;
};
static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
const auto parameters{rp.PopRaw<Parameters>()};
LOG_INFO(Service_HID, "called, is_enabled={}, applet_resource_user_id={}",
parameters.is_enabled, parameters.applet_resource_user_id);
GetResourceManager()->SetAruidValidForVibration(parameters.applet_resource_user_id,
parameters.is_enabled);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
void IHidSystemServer::EnableAppletToGetSixAxisSensor(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
struct Parameters {
@ -601,6 +623,57 @@ void IHidSystemServer::EnableAppletToGetTouchScreen(HLERequestContext& ctx) {
rb.Push(ResultSuccess);
}
void IHidSystemServer::SetVibrationMasterVolume(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto master_volume{rp.Pop<f32>()};
LOG_INFO(Service_HID, "called, volume={}", master_volume);
const auto result =
GetResourceManager()->GetNpad()->GetVibrationHandler()->SetVibrationMasterVolume(
master_volume);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(result);
}
void IHidSystemServer::GetVibrationMasterVolume(HLERequestContext& ctx) {
f32 master_volume{};
const auto result =
GetResourceManager()->GetNpad()->GetVibrationHandler()->GetVibrationMasterVolume(
master_volume);
LOG_INFO(Service_HID, "called, volume={}", master_volume);
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(result);
rb.Push(master_volume);
}
void IHidSystemServer::BeginPermitVibrationSession(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto applet_resource_user_id{rp.Pop<u64>()};
LOG_INFO(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
const auto result =
GetResourceManager()->GetNpad()->GetVibrationHandler()->BeginPermitVibrationSession(
applet_resource_user_id);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(result);
}
void IHidSystemServer::EndPermitVibrationSession(HLERequestContext& ctx) {
LOG_INFO(Service_HID, "called");
const auto result =
GetResourceManager()->GetNpad()->GetVibrationHandler()->EndPermitVibrationSession();
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(result);
}
void IHidSystemServer::IsJoyConAttachedOnAllRail(HLERequestContext& ctx) {
const bool is_attached = true;
@ -749,6 +822,19 @@ void IHidSystemServer::GetTouchScreenDefaultConfiguration(HLERequestContext& ctx
rb.PushRaw(touchscreen_config);
}
void IHidSystemServer::SetForceHandheldStyleVibration(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto is_forced{rp.Pop<bool>()};
LOG_INFO(Service_HID, "called, is_forced={}", is_forced);
GetResourceManager()->SetForceHandheldStyleVibration(is_forced);
GetResourceManager()->GetNpad()->UpdateHandheldAbstractState();
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
void IHidSystemServer::IsUsingCustomButtonConfig(HLERequestContext& ctx) {
const bool is_enabled = false;

View File

@ -42,9 +42,14 @@ private:
void RegisterAppletResourceUserId(HLERequestContext& ctx);
void UnregisterAppletResourceUserId(HLERequestContext& ctx);
void EnableAppletToGetInput(HLERequestContext& ctx);
void SetAruidValidForVibration(HLERequestContext& ctx);
void EnableAppletToGetSixAxisSensor(HLERequestContext& ctx);
void EnableAppletToGetPadInput(HLERequestContext& ctx);
void EnableAppletToGetTouchScreen(HLERequestContext& ctx);
void SetVibrationMasterVolume(HLERequestContext& ctx);
void GetVibrationMasterVolume(HLERequestContext& ctx);
void BeginPermitVibrationSession(HLERequestContext& ctx);
void EndPermitVibrationSession(HLERequestContext& ctx);
void IsJoyConAttachedOnAllRail(HLERequestContext& ctx);
void AcquireConnectionTriggerTimeoutEvent(HLERequestContext& ctx);
void AcquireDeviceRegisteredEventForControllerSupport(HLERequestContext& ctx);
@ -61,6 +66,7 @@ private:
void FinalizeUsbFirmwareUpdate(HLERequestContext& ctx);
void InitializeUsbFirmwareUpdateWithoutMemory(HLERequestContext& ctx);
void GetTouchScreenDefaultConfiguration(HLERequestContext& ctx);
void SetForceHandheldStyleVibration(HLERequestContext& ctx);
void IsUsingCustomButtonConfig(HLERequestContext& ctx);
std::shared_ptr<ResourceManager> GetResourceManager();

View File

@ -441,7 +441,10 @@ Result NfcDevice::Mount(NFP::ModelType model_type, NFP::MountTarget mount_target
device_state = DeviceState::TagMounted;
mount_target = mount_target_;
if (!is_corrupted && mount_target != NFP::MountTarget::Rom) {
const bool create_backup =
mount_target == NFP::MountTarget::All || mount_target == NFP::MountTarget::Ram ||
(mount_target == NFP::MountTarget::Rom && HasBackup(encrypted_tag_data.uuid).IsError());
if (!is_corrupted && create_backup) {
std::vector<u8> data(sizeof(NFP::EncryptedNTAG215File));
memcpy(data.data(), &encrypted_tag_data, sizeof(encrypted_tag_data));
WriteBackupData(encrypted_tag_data.uuid, data);

View File

@ -112,9 +112,7 @@ void Nvnflinger::ShutdownLayers() {
{
const auto lock_guard = Lock();
for (auto& display : displays) {
for (size_t layer = 0; layer < display.GetNumLayers(); ++layer) {
display.GetLayer(layer).GetConsumer().Abandon();
}
display.Abandon();
}
is_abandoned = true;
@ -176,24 +174,28 @@ void Nvnflinger::CreateLayerAtId(VI::Display& display, u64 layer_id) {
display.CreateLayer(layer_id, buffer_id, nvdrv->container);
}
void Nvnflinger::OpenLayer(u64 layer_id) {
bool Nvnflinger::OpenLayer(u64 layer_id) {
const auto lock_guard = Lock();
for (auto& display : displays) {
if (auto* layer = display.FindLayer(layer_id); layer) {
layer->Open();
return layer->Open();
}
}
return false;
}
void Nvnflinger::CloseLayer(u64 layer_id) {
bool Nvnflinger::CloseLayer(u64 layer_id) {
const auto lock_guard = Lock();
for (auto& display : displays) {
if (auto* layer = display.FindLayer(layer_id); layer) {
layer->Close();
return layer->Close();
}
}
return false;
}
void Nvnflinger::DestroyLayer(u64 layer_id) {

View File

@ -74,10 +74,10 @@ public:
[[nodiscard]] std::optional<u64> CreateLayer(u64 display_id);
/// Opens a layer on all displays for the given layer ID.
void OpenLayer(u64 layer_id);
bool OpenLayer(u64 layer_id);
/// Closes a layer on all displays for the given layer ID.
void CloseLayer(u64 layer_id);
bool CloseLayer(u64 layer_id);
/// Destroys the given layer ID.
void DestroyLayer(u64 layer_id);

View File

@ -1,72 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <array>
#include "common/bit_field.h"
#include "common/common_funcs.h"
#include "common/common_types.h"
#include "common/uuid.h"
#include "core/hle/service/time/clock_types.h"
namespace Service::Set {
/// This is nn::settings::system::InitialLaunchFlag
struct InitialLaunchFlag {
union {
u32 raw{};
BitField<0, 1, u32> InitialLaunchCompletionFlag;
BitField<8, 1, u32> InitialLaunchUserAdditionFlag;
BitField<16, 1, u32> InitialLaunchTimestampFlag;
};
};
static_assert(sizeof(InitialLaunchFlag) == 4, "InitialLaunchFlag is an invalid size");
/// This is nn::settings::system::InitialLaunchSettings
struct InitialLaunchSettings {
InitialLaunchFlag flags;
INSERT_PADDING_BYTES(0x4);
Service::Time::Clock::SteadyClockTimePoint timestamp;
};
static_assert(sizeof(InitialLaunchSettings) == 0x20, "InitialLaunchSettings is incorrect size");
#pragma pack(push, 4)
struct InitialLaunchSettingsPacked {
InitialLaunchFlag flags;
Service::Time::Clock::SteadyClockTimePoint timestamp;
};
#pragma pack(pop)
static_assert(sizeof(InitialLaunchSettingsPacked) == 0x1C,
"InitialLaunchSettingsPacked is incorrect size");
struct PrivateSettings {
std::array<u8, 0x10> reserved_00;
// nn::settings::system::InitialLaunchSettings
InitialLaunchSettings initial_launch_settings;
std::array<u8, 0x20> reserved_30;
Common::UUID external_clock_source_id;
s64 shutdown_rtc_value;
s64 external_steady_clock_internal_offset;
std::array<u8, 0x60> reserved_70;
// nn::settings::system::PlatformRegion
std::array<u8, 0x4> platform_region;
std::array<u8, 0x4> reserved_D4;
};
static_assert(offsetof(PrivateSettings, initial_launch_settings) == 0x10);
static_assert(offsetof(PrivateSettings, external_clock_source_id) == 0x50);
static_assert(offsetof(PrivateSettings, reserved_70) == 0x70);
static_assert(offsetof(PrivateSettings, platform_region) == 0xD0);
static_assert(sizeof(PrivateSettings) == 0xD8, "PrivateSettings has the wrong size!");
PrivateSettings DefaultPrivateSettings();
} // namespace Service::Set

View File

@ -1,12 +1,16 @@
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "core/hle/service/set/appln_settings.h"
#include "core/hle/service/set/setting_formats/appln_settings.h"
namespace Service::Set {
ApplnSettings DefaultApplnSettings() {
return {};
ApplnSettings settings{};
settings.mii_author_id = Common::UUID::MakeDefault();
return settings;
}
} // namespace Service::Set

View File

@ -7,24 +7,23 @@
#include <cstddef>
#include "common/common_types.h"
#include "common/uuid.h"
#include "core/hle/service/set/settings_types.h"
namespace Service::Set {
struct ApplnSettings {
std::array<u8, 0x10> reserved_000;
INSERT_PADDING_BYTES(0x10); // Reserved
// nn::util::Uuid MiiAuthorId, copied from system settings 0x94B0
std::array<u8, 0x10> mii_author_id;
std::array<u8, 0x30> reserved_020;
Common::UUID mii_author_id;
INSERT_PADDING_BYTES(0x30); // Reserved
// nn::settings::system::ServiceDiscoveryControlSettings
std::array<u8, 0x4> service_discovery_control_settings;
std::array<u8, 0x20> reserved_054;
u32 service_discovery_control_settings;
INSERT_PADDING_BYTES(0x20); // Reserved
bool in_repair_process_enable_flag;
std::array<u8, 0x3> pad_075;
INSERT_PADDING_BYTES(0x3);
};
static_assert(offsetof(ApplnSettings, mii_author_id) == 0x10);
static_assert(offsetof(ApplnSettings, service_discovery_control_settings) == 0x50);

View File

@ -1,7 +1,7 @@
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "core/hle/service/set/device_settings.h"
#include "core/hle/service/set/setting_formats/device_settings.h"
namespace Service::Set {

View File

@ -7,10 +7,12 @@
#include <cstddef>
#include "common/common_types.h"
#include "common/vector_math.h"
#include "core/hle/service/set/settings_types.h"
namespace Service::Set {
struct DeviceSettings {
std::array<u8, 0x10> reserved_000;
INSERT_PADDING_BYTES(0x10); // Reserved
// nn::settings::BatteryLot
std::array<u8, 0x18> ptm_battery_lot;
@ -19,26 +21,24 @@ struct DeviceSettings {
u8 ptm_battery_version;
// nn::settings::system::PtmCycleCountReliability
u32 ptm_cycle_count_reliability;
std::array<u8, 0x48> reserved_048;
INSERT_PADDING_BYTES(0x48); // Reserved
// nn::settings::system::AnalogStickUserCalibration L
std::array<u8, 0x10> analog_user_stick_calibration_l;
// nn::settings::system::AnalogStickUserCalibration R
std::array<u8, 0x10> analog_user_stick_calibration_r;
std::array<u8, 0x20> reserved_0B0;
INSERT_PADDING_BYTES(0x20); // Reserved
// nn::settings::system::ConsoleSixAxisSensorAccelerationBias
std::array<u8, 0xC> console_six_axis_sensor_acceleration_bias;
Common::Vec3<f32> console_six_axis_sensor_acceleration_bias;
// nn::settings::system::ConsoleSixAxisSensorAngularVelocityBias
std::array<u8, 0xC> console_six_axis_sensor_angular_velocity_bias;
Common::Vec3<f32> console_six_axis_sensor_angular_velocity_bias;
// nn::settings::system::ConsoleSixAxisSensorAccelerationGain
std::array<u8, 0x24> console_six_axis_sensor_acceleration_gain;
// nn::settings::system::ConsoleSixAxisSensorAngularVelocityGain
std::array<u8, 0x24> console_six_axis_sensor_angular_velocity_gain;
// nn::settings::system::ConsoleSixAxisSensorAngularVelocityTimeBias
std::array<u8, 0xC> console_six_axis_sensor_angular_velocity_time_bias;
Common::Vec3<f32> console_six_axis_sensor_angular_velocity_time_bias;
// nn::settings::system::ConsoleSixAxisSensorAngularAcceleration
std::array<u8, 0x24> console_six_axis_sensor_angular_acceleration;
};

View File

@ -1,7 +1,7 @@
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "core/hle/service/set/private_settings.h"
#include "core/hle/service/set/setting_formats/private_settings.h"
namespace Service::Set {

View File

@ -0,0 +1,39 @@
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <array>
#include "common/common_types.h"
#include "common/uuid.h"
#include "core/hle/service/set/settings_types.h"
#include "core/hle/service/time/clock_types.h"
namespace Service::Set {
struct PrivateSettings {
INSERT_PADDING_BYTES(0x10); // Reserved
InitialLaunchSettings initial_launch_settings;
INSERT_PADDING_BYTES(0x20); // Reserved
Common::UUID external_clock_source_id;
s64 shutdown_rtc_value;
s64 external_steady_clock_internal_offset;
INSERT_PADDING_BYTES(0x60); // Reserved
// nn::settings::system::PlatformRegion
s32 platform_region;
INSERT_PADDING_BYTES(0x4); // Reserved
};
static_assert(offsetof(PrivateSettings, initial_launch_settings) == 0x10);
static_assert(offsetof(PrivateSettings, external_clock_source_id) == 0x50);
static_assert(offsetof(PrivateSettings, shutdown_rtc_value) == 0x60);
static_assert(offsetof(PrivateSettings, external_steady_clock_internal_offset) == 0x68);
static_assert(offsetof(PrivateSettings, platform_region) == 0xD0);
static_assert(sizeof(PrivateSettings) == 0xD8, "PrivateSettings has the wrong size!");
PrivateSettings DefaultPrivateSettings();
} // namespace Service::Set

View File

@ -1,7 +1,7 @@
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "core/hle/service/set/system_settings.h"
#include "core/hle/service/set/setting_formats/system_settings.h"
namespace Service::Set {
@ -11,6 +11,8 @@ SystemSettings DefaultSystemSettings() {
settings.version = 0x140000;
settings.flags = 7;
settings.mii_author_id = Common::UUID::MakeDefault();
settings.color_set_id = ColorSet::BasicWhite;
settings.notification_settings = {
@ -45,6 +47,10 @@ SystemSettings DefaultSystemSettings() {
settings.device_time_zone_location_name = {"UTC"};
settings.user_system_clock_automatic_correction_enabled = false;
settings.primary_album_storage = PrimaryAlbumStorage::SdCard;
settings.battery_percentage_flag = true;
settings.chinese_traditional_input_method = ChineseTraditionalInputMethod::Unknown0;
return settings;
}

View File

@ -8,272 +8,14 @@
#include "common/bit_field.h"
#include "common/common_funcs.h"
#include "common/common_types.h"
#include "core/hle/service/set/private_settings.h"
#include "common/uuid.h"
#include "common/vector_math.h"
#include "core/hle/service/set/setting_formats/private_settings.h"
#include "core/hle/service/set/settings_types.h"
#include "core/hle/service/time/clock_types.h"
namespace Service::Set {
/// This is "nn::settings::LanguageCode", which is a NUL-terminated string stored in a u64.
enum class LanguageCode : u64 {
JA = 0x000000000000616A,
EN_US = 0x00000053552D6E65,
FR = 0x0000000000007266,
DE = 0x0000000000006564,
IT = 0x0000000000007469,
ES = 0x0000000000007365,
ZH_CN = 0x0000004E432D687A,
KO = 0x0000000000006F6B,
NL = 0x0000000000006C6E,
PT = 0x0000000000007470,
RU = 0x0000000000007572,
ZH_TW = 0x00000057542D687A,
EN_GB = 0x00000042472D6E65,
FR_CA = 0x00000041432D7266,
ES_419 = 0x00003931342D7365,
ZH_HANS = 0x00736E61482D687A,
ZH_HANT = 0x00746E61482D687A,
PT_BR = 0x00000052422D7470,
};
/// This is nn::settings::system::ErrorReportSharePermission
enum class ErrorReportSharePermission : u32 {
NotConfirmed,
Granted,
Denied,
};
/// This is nn::settings::system::ChineseTraditionalInputMethod
enum class ChineseTraditionalInputMethod : u32 {
Unknown0 = 0,
Unknown1 = 1,
Unknown2 = 2,
};
/// This is nn::settings::system::HomeMenuScheme
struct HomeMenuScheme {
u32 main;
u32 back;
u32 sub;
u32 bezel;
u32 extra;
};
static_assert(sizeof(HomeMenuScheme) == 0x14, "HomeMenuScheme is incorrect size");
/// Indicates the current theme set by the system settings
enum class ColorSet : u32 {
BasicWhite = 0,
BasicBlack = 1,
};
/// Indicates the current console is a retail or kiosk unit
enum class QuestFlag : u8 {
Retail = 0,
Kiosk = 1,
};
/// This is nn::settings::system::RegionCode
enum class RegionCode : u32 {
Japan,
Usa,
Europe,
Australia,
HongKongTaiwanKorea,
China,
};
/// This is nn::settings::system::AccountSettings
struct AccountSettings {
u32 flags;
};
static_assert(sizeof(AccountSettings) == 4, "AccountSettings is an invalid size");
/// This is nn::settings::system::NotificationVolume
enum class NotificationVolume : u32 {
Mute,
Low,
High,
};
/// This is nn::settings::system::NotificationFlag
struct NotificationFlag {
union {
u32 raw{};
BitField<0, 1, u32> RingtoneFlag;
BitField<1, 1, u32> DownloadCompletionFlag;
BitField<8, 1, u32> EnablesNews;
BitField<9, 1, u32> IncomingLampFlag;
};
};
static_assert(sizeof(NotificationFlag) == 4, "NotificationFlag is an invalid size");
/// This is nn::settings::system::NotificationTime
struct NotificationTime {
u32 hour;
u32 minute;
};
static_assert(sizeof(NotificationTime) == 0x8, "NotificationTime is an invalid size");
/// This is nn::settings::system::NotificationSettings
struct NotificationSettings {
NotificationFlag flags;
NotificationVolume volume;
NotificationTime start_time;
NotificationTime stop_time;
};
static_assert(sizeof(NotificationSettings) == 0x18, "NotificationSettings is an invalid size");
/// This is nn::settings::system::AccountNotificationFlag
struct AccountNotificationFlag {
union {
u32 raw{};
BitField<0, 1, u32> FriendOnlineFlag;
BitField<1, 1, u32> FriendRequestFlag;
BitField<8, 1, u32> CoralInvitationFlag;
};
};
static_assert(sizeof(AccountNotificationFlag) == 4, "AccountNotificationFlag is an invalid size");
/// This is nn::settings::system::FriendPresenceOverlayPermission
enum class FriendPresenceOverlayPermission : u8 {
NotConfirmed,
NoDisplay,
FavoriteFriends,
Friends,
};
/// This is nn::settings::system::AccountNotificationSettings
struct AccountNotificationSettings {
Common::UUID uid;
AccountNotificationFlag flags;
FriendPresenceOverlayPermission friend_presence_permission;
FriendPresenceOverlayPermission friend_invitation_permission;
INSERT_PADDING_BYTES(0x2);
};
static_assert(sizeof(AccountNotificationSettings) == 0x18,
"AccountNotificationSettings is an invalid size");
/// This is nn::settings::system::TvFlag
struct TvFlag {
union {
u32 raw{};
BitField<0, 1, u32> Allows4k;
BitField<1, 1, u32> Allows3d;
BitField<2, 1, u32> AllowsCec;
BitField<3, 1, u32> PreventsScreenBurnIn;
};
};
static_assert(sizeof(TvFlag) == 4, "TvFlag is an invalid size");
/// This is nn::settings::system::TvResolution
enum class TvResolution : u32 {
Auto,
Resolution1080p,
Resolution720p,
Resolution480p,
};
/// This is nn::settings::system::HdmiContentType
enum class HdmiContentType : u32 {
None,
Graphics,
Cinema,
Photo,
Game,
};
/// This is nn::settings::system::RgbRange
enum class RgbRange : u32 {
Auto,
Full,
Limited,
};
/// This is nn::settings::system::CmuMode
enum class CmuMode : u32 {
None,
ColorInvert,
HighContrast,
GrayScale,
};
/// This is nn::settings::system::TvSettings
struct TvSettings {
TvFlag flags;
TvResolution tv_resolution;
HdmiContentType hdmi_content_type;
RgbRange rgb_range;
CmuMode cmu_mode;
u32 tv_underscan;
f32 tv_gama;
f32 contrast_ratio;
};
static_assert(sizeof(TvSettings) == 0x20, "TvSettings is an invalid size");
/// This is nn::settings::system::PrimaryAlbumStorage
enum class PrimaryAlbumStorage : u32 {
Nand,
SdCard,
};
/// This is nn::settings::system::HandheldSleepPlan
enum class HandheldSleepPlan : u32 {
Sleep1Min,
Sleep3Min,
Sleep5Min,
Sleep10Min,
Sleep30Min,
Never,
};
/// This is nn::settings::system::ConsoleSleepPlan
enum class ConsoleSleepPlan : u32 {
Sleep1Hour,
Sleep2Hour,
Sleep3Hour,
Sleep6Hour,
Sleep12Hour,
Never,
};
/// This is nn::settings::system::SleepFlag
struct SleepFlag {
union {
u32 raw{};
BitField<0, 1, u32> SleepsWhilePlayingMedia;
BitField<1, 1, u32> WakesAtPowerStateChange;
};
};
static_assert(sizeof(SleepFlag) == 4, "TvFlag is an invalid size");
/// This is nn::settings::system::SleepSettings
struct SleepSettings {
SleepFlag flags;
HandheldSleepPlan handheld_sleep_plan;
ConsoleSleepPlan console_sleep_plan;
};
static_assert(sizeof(SleepSettings) == 0xc, "SleepSettings is incorrect size");
/// This is nn::settings::system::EulaVersionClockType
enum class EulaVersionClockType : u32 {
NetworkSystemClock,
SteadyClock,
};
/// This is nn::settings::system::EulaVersion
struct EulaVersion {
u32 version;
RegionCode region_code;
EulaVersionClockType clock_type;
INSERT_PADDING_BYTES(0x4);
s64 posix_time;
Time::Clock::SteadyClockTimePoint timestamp;
};
static_assert(sizeof(EulaVersion) == 0x30, "EulaVersion is incorrect size");
struct SystemSettings {
// 0/unwritten (1.0.0), 0x20000 (2.0.0), 0x30000 (3.0.0-3.0.1), 0x40001 (4.0.0-4.1.0), 0x50000
// (5.0.0-5.1.0), 0x60000 (6.0.0-6.2.0), 0x70000 (7.0.0), 0x80000 (8.0.0-8.1.1), 0x90000
@ -283,20 +25,16 @@ struct SystemSettings {
// 0/unwritten (1.0.0), 1 (6.0.0-8.1.0), 2 (8.1.1), 7 (9.0.0+).
// if (flags & 2), defaults are written for AnalogStickUserCalibration
u32 flags;
INSERT_PADDING_BYTES(0x8); // Reserved
std::array<u8, 0x8> reserved_00008;
// nn::settings::LanguageCode
LanguageCode language_code;
std::array<u8, 0x38> reserved_00018;
INSERT_PADDING_BYTES(0x38); // Reserved
// nn::settings::system::NetworkSettings
u32 network_setting_count;
bool wireless_lan_enable_flag;
std::array<u8, 0x3> pad_00055;
std::array<u8, 0x8> reserved_00058;
INSERT_PADDING_BYTES(0x3);
INSERT_PADDING_BYTES(0x8); // Reserved
// nn::settings::system::NetworkSettings
std::array<std::array<u8, 0x400>, 32> network_settings_1B0;
@ -304,161 +42,142 @@ struct SystemSettings {
// nn::settings::system::BluetoothDevicesSettings
std::array<u8, 0x4> bluetooth_device_settings_count;
bool bluetooth_enable_flag;
std::array<u8, 0x3> pad_08065;
INSERT_PADDING_BYTES(0x3);
bool bluetooth_afh_enable_flag;
std::array<u8, 0x3> pad_08069;
INSERT_PADDING_BYTES(0x3);
bool bluetooth_boost_enable_flag;
std::array<u8, 0x3> pad_0806D;
INSERT_PADDING_BYTES(0x3);
std::array<std::array<u8, 0x200>, 10> bluetooth_device_settings_first_10;
s32 ldn_channel;
std::array<u8, 0x3C> reserved_09474;
INSERT_PADDING_BYTES(0x3C); // Reserved
// nn::util::Uuid MiiAuthorId
std::array<u8, 0x10> mii_author_id;
Common::UUID mii_author_id;
std::array<u8, 0x30> reserved_094C0;
INSERT_PADDING_BYTES(0x30); // Reserved
// nn::settings::system::NxControllerSettings
u32 nx_controller_settings_count;
std::array<u8, 0xC> reserved_094F4;
INSERT_PADDING_BYTES(0xC); // Reserved
// nn::settings::system::NxControllerSettings,
// nn::settings::system::NxControllerLegacySettings on 13.0.0+
std::array<std::array<u8, 0x40>, 10> nx_controller_legacy_settings;
std::array<u8, 0x170> reserved_09780;
INSERT_PADDING_BYTES(0x170); // Reserved
bool external_rtc_reset_flag;
std::array<u8, 0x3> pad_098F1;
std::array<u8, 0x3C> reserved_098F4;
INSERT_PADDING_BYTES(0x3);
INSERT_PADDING_BYTES(0x3C); // Reserved
s32 push_notification_activity_mode_on_sleep;
INSERT_PADDING_BYTES(0x3C); // Reserved
std::array<u8, 0x3C> reserved_09934;
// nn::settings::system::ErrorReportSharePermission
ErrorReportSharePermission error_report_share_permission;
INSERT_PADDING_BYTES(0x3C); // Reserved
std::array<u8, 0x3C> reserved_09974;
// nn::settings::KeyboardLayout
std::array<u8, 0x4> keyboard_layout;
std::array<u8, 0x3C> reserved_099B4;
KeyboardLayout keyboard_layout;
INSERT_PADDING_BYTES(0x3C); // Reserved
bool web_inspector_flag;
std::array<u8, 0x3> pad_099F1;
INSERT_PADDING_BYTES(0x3);
// nn::settings::system::AllowedSslHost
u32 allowed_ssl_host_count;
bool memory_usage_rate_flag;
std::array<u8, 0x3> pad_099F9;
std::array<u8, 0x34> reserved_099FC;
INSERT_PADDING_BYTES(0x3);
INSERT_PADDING_BYTES(0x34); // Reserved
// nn::settings::system::HostFsMountPoint
std::array<u8, 0x100> host_fs_mount_point;
// nn::settings::system::AllowedSslHost
std::array<std::array<u8, 0x100>, 8> allowed_ssl_hosts;
std::array<u8, 0x6C0> reserved_0A330;
INSERT_PADDING_BYTES(0x6C0); // Reserved
// nn::settings::system::BlePairingSettings
u32 ble_pairing_settings_count;
std::array<u8, 0xC> reserved_0A9F4;
INSERT_PADDING_BYTES(0xC); // Reserved
std::array<std::array<u8, 0x80>, 10> ble_pairing_settings;
// nn::settings::system::AccountOnlineStorageSettings
u32 account_online_storage_settings_count;
std::array<u8, 0xC> reserved_0AF04;
INSERT_PADDING_BYTES(0xC); // Reserved
std::array<std::array<u8, 0x40>, 8> account_online_storage_settings;
bool pctl_ready_flag;
std::array<u8, 0x3> pad_0B111;
std::array<u8, 0x3C> reserved_0B114;
INSERT_PADDING_BYTES(0x3);
INSERT_PADDING_BYTES(0x3C); // Reserved
// nn::settings::system::ThemeId
std::array<u8, 0x80> theme_id_type0;
std::array<u8, 0x80> theme_id_type1;
INSERT_PADDING_BYTES(0x100); // Reserved
std::array<u8, 0x100> reserved_0B250;
// nn::settings::ChineseTraditionalInputMethod
ChineseTraditionalInputMethod chinese_traditional_input_method;
std::array<u8, 0x3C> reserved_0B354;
INSERT_PADDING_BYTES(0x3C); // Reserved
bool zoom_flag;
std::array<u8, 0x3> pad_0B391;
std::array<u8, 0x3C> reserved_0B394;
INSERT_PADDING_BYTES(0x3);
INSERT_PADDING_BYTES(0x3C); // Reserved
// nn::settings::system::ButtonConfigRegisteredSettings
u32 button_config_registered_settings_count;
std::array<u8, 0xC> reserved_0B3D4;
INSERT_PADDING_BYTES(0xC); // Reserved
// nn::settings::system::ButtonConfigSettings
u32 button_config_settings_count;
std::array<u8, 0x4> reserved_0B3E4;
INSERT_PADDING_BYTES(0x4); // Reserved
std::array<std::array<u8, 0x5A8>, 5> button_config_settings;
std::array<u8, 0x13B0> reserved_0D030;
INSERT_PADDING_BYTES(0x13B0); // Reserved
u32 button_config_settings_embedded_count;
std::array<u8, 0x4> reserved_0E3E4;
INSERT_PADDING_BYTES(0x4); // Reserved
std::array<std::array<u8, 0x5A8>, 5> button_config_settings_embedded;
std::array<u8, 0x13B0> reserved_10030;
INSERT_PADDING_BYTES(0x13B0); // Reserved
u32 button_config_settings_left_count;
std::array<u8, 0x4> reserved_113E4;
INSERT_PADDING_BYTES(0x4); // Reserved
std::array<std::array<u8, 0x5A8>, 5> button_config_settings_left;
std::array<u8, 0x13B0> reserved_13030;
INSERT_PADDING_BYTES(0x13B0); // Reserved
u32 button_config_settings_right_count;
std::array<u8, 0x4> reserved_143E4;
INSERT_PADDING_BYTES(0x4); // Reserved
std::array<std::array<u8, 0x5A8>, 5> button_config_settings_right;
std::array<u8, 0x73B0> reserved_16030;
INSERT_PADDING_BYTES(0x73B0); // Reserved
// nn::settings::system::ButtonConfigRegisteredSettings
std::array<u8, 0x5C8> button_config_registered_settings_embedded;
std::array<std::array<u8, 0x5C8>, 10> button_config_registered_settings;
std::array<u8, 0x7FF8> reserved_21378;
INSERT_PADDING_BYTES(0x7FF8); // Reserved
// nn::settings::system::ConsoleSixAxisSensorAccelerationBias
std::array<u8, 0xC> console_six_axis_sensor_acceleration_bias;
Common::Vec3<f32> console_six_axis_sensor_acceleration_bias;
// nn::settings::system::ConsoleSixAxisSensorAngularVelocityBias
std::array<u8, 0xC> console_six_axis_sensor_angular_velocity_bias;
Common::Vec3<f32> console_six_axis_sensor_angular_velocity_bias;
// nn::settings::system::ConsoleSixAxisSensorAccelerationGain
std::array<u8, 0x24> console_six_axis_sensor_acceleration_gain;
// nn::settings::system::ConsoleSixAxisSensorAngularVelocityGain
std::array<u8, 0x24> console_six_axis_sensor_angular_velocity_gain;
// nn::settings::system::ConsoleSixAxisSensorAngularVelocityTimeBias
std::array<u8, 0xC> console_six_axis_sensor_angular_velocity_time_bias;
Common::Vec3<f32> console_six_axis_sensor_angular_velocity_time_bias;
// nn::settings::system::ConsoleSixAxisSensorAngularAcceleration
std::array<u8, 0x24> console_six_axis_sensor_angular_velocity_acceleration;
std::array<u8, 0x70> reserved_29400;
INSERT_PADDING_BYTES(0x70); // Reserved
bool lock_screen_flag;
std::array<u8, 0x3> pad_29471;
std::array<u8, 0x4> reserved_249274;
INSERT_PADDING_BYTES(0x3);
INSERT_PADDING_BYTES(0x4); // Reserved
ColorSet color_set_id;
QuestFlag quest_flag;
// nn::settings::system::RegionCode
RegionCode region_code;
SystemRegionCode region_code;
// Different to nn::settings::system::InitialLaunchSettings?
InitialLaunchSettingsPacked initial_launch_settings_packed;
bool battery_percentage_flag;
std::array<u8, 0x3> pad_294A1;
INSERT_PADDING_BYTES(0x3);
// BitFlagSet<32, nn::settings::system::AppletLaunchFlag>
u32 applet_launch_flag;
@ -469,33 +188,26 @@ struct SystemSettings {
std::array<u8, 0x10> theme_key;
bool field_testing_flag;
std::array<u8, 0x3> pad_294C1;
INSERT_PADDING_BYTES(0x3);
s32 panel_crc_mode;
std::array<u8, 0x28> reserved_294C8;
INSERT_PADDING_BYTES(0x28); // Reserved
// nn::settings::system::BacklightSettings
std::array<u8, 0x2C> backlight_settings_mixed_up;
INSERT_PADDING_BYTES(0x64); // Reserved
std::array<u8, 0x64> reserved_2951C;
// nn::time::SystemClockContext
Service::Time::Clock::SystemClockContext user_system_clock_context;
Service::Time::Clock::SystemClockContext network_system_clock_context;
bool user_system_clock_automatic_correction_enabled;
std::array<u8, 0x3> pad_295C1;
std::array<u8, 0x4> reserved_295C4;
// nn::time::SteadyClockTimePoint
INSERT_PADDING_BYTES(0x3);
INSERT_PADDING_BYTES(0x4); // Reserved
Service::Time::Clock::SteadyClockTimePoint
user_system_clock_automatic_correction_updated_time_point;
INSERT_PADDING_BYTES(0x10); // Reserved
std::array<u8, 0x10> reserved_295E0;
// nn::settings::system::AccountSettings
AccountSettings account_settings;
std::array<u8, 0xFC> reserved_295F4;
INSERT_PADDING_BYTES(0xFC); // Reserved
// nn::settings::system::AudioVolume
std::array<u8, 0x8> audio_volume_type0;
@ -505,47 +217,42 @@ struct SystemSettings {
s32 audio_output_mode_type1;
s32 audio_output_mode_type2;
bool force_mute_on_headphone_removed;
std::array<u8, 0x3> pad_2970D;
INSERT_PADDING_BYTES(0x3);
s32 headphone_volume_warning_count;
bool heaphone_volume_update_flag;
std::array<u8, 0x3> pad_29715;
INSERT_PADDING_BYTES(0x3);
// nn::settings::system::AudioVolume
std::array<u8, 0x8> audio_volume_type2;
// nn::settings::system::AudioOutputMode
s32 audio_output_mode_type3;
s32 audio_output_mode_type4;
bool hearing_protection_safeguard_flag;
std::array<u8, 0x3> pad_29729;
std::array<u8, 0x4> reserved_2972C;
INSERT_PADDING_BYTES(0x3);
INSERT_PADDING_BYTES(0x4); // Reserved
s64 hearing_protection_safeguard_remaining_time;
std::array<u8, 0x38> reserved_29738;
INSERT_PADDING_BYTES(0x38); // Reserved
bool console_information_upload_flag;
std::array<u8, 0x3> pad_29771;
std::array<u8, 0x3C> reserved_29774;
INSERT_PADDING_BYTES(0x3);
INSERT_PADDING_BYTES(0x3C); // Reserved
bool automatic_application_download_flag;
std::array<u8, 0x3> pad_297B1;
INSERT_PADDING_BYTES(0x3);
INSERT_PADDING_BYTES(0x4); // Reserved
std::array<u8, 0x4> reserved_297B4;
// nn::settings::system::NotificationSettings
NotificationSettings notification_settings;
std::array<u8, 0x60> reserved_297D0;
INSERT_PADDING_BYTES(0x60); // Reserved
// nn::settings::system::AccountNotificationSettings
u32 account_notification_settings_count;
std::array<u8, 0xC> reserved_29834;
INSERT_PADDING_BYTES(0xC); // Reserved
std::array<AccountNotificationSettings, 8> account_notification_settings;
std::array<u8, 0x140> reserved_29900;
INSERT_PADDING_BYTES(0x140); // Reserved
f32 vibration_master_volume;
bool usb_full_key_enable_flag;
std::array<u8, 0x3> pad_29A45;
INSERT_PADDING_BYTES(0x3);
// nn::settings::system::AnalogStickUserCalibration
std::array<u8, 0x10> analog_stick_user_calibration_left;
@ -553,85 +260,68 @@ struct SystemSettings {
// nn::settings::system::TouchScreenMode
s32 touch_screen_mode;
INSERT_PADDING_BYTES(0x14); // Reserved
std::array<u8, 0x14> reserved_29A6C;
// nn::settings::system::TvSettings
TvSettings tv_settings;
// nn::settings::system::Edid
std::array<u8, 0x100> edid;
std::array<u8, 0x2E0> reserved_29BA0;
INSERT_PADDING_BYTES(0x2E0); // Reserved
// nn::settings::system::DataDeletionSettings
std::array<u8, 0x8> data_deletion_settings;
std::array<u8, 0x38> reserved_29E88;
INSERT_PADDING_BYTES(0x38); // Reserved
// nn::ncm::ProgramId
std::array<u8, 0x8> initial_system_applet_program_id;
std::array<u8, 0x8> overlay_disp_program_id;
std::array<u8, 0x4> reserved_29ED0;
INSERT_PADDING_BYTES(0x4); // Reserved
bool requires_run_repair_time_reviser;
INSERT_PADDING_BYTES(0x6B); // Reserved
std::array<u8, 0x6B> reserved_29ED5;
// nn::time::LocationName
Service::Time::TimeZone::LocationName device_time_zone_location_name;
std::array<u8, 0x4> reserved_29F64;
// nn::time::SteadyClockTimePoint
INSERT_PADDING_BYTES(0x4); // Reserved
Service::Time::Clock::SteadyClockTimePoint device_time_zone_location_updated_time;
std::array<u8, 0xC0> reserved_29F80;
INSERT_PADDING_BYTES(0xC0); // Reserved
// nn::settings::system::PrimaryAlbumStorage
PrimaryAlbumStorage primary_album_storage;
std::array<u8, 0x3C> reserved_2A044;
INSERT_PADDING_BYTES(0x3C); // Reserved
bool usb_30_enable_flag;
std::array<u8, 0x3> pad_2A081;
INSERT_PADDING_BYTES(0x3);
bool usb_30_host_enable_flag;
std::array<u8, 0x3> pad_2A085;
INSERT_PADDING_BYTES(0x3);
bool usb_30_device_enable_flag;
std::array<u8, 0x3> pad_2A089;
std::array<u8, 0x34> reserved_2A08C;
INSERT_PADDING_BYTES(0x3);
INSERT_PADDING_BYTES(0x34); // Reserved
bool nfc_enable_flag;
std::array<u8, 0x3> pad_2A0C1;
std::array<u8, 0x3C> reserved_2A0C4;
INSERT_PADDING_BYTES(0x3);
INSERT_PADDING_BYTES(0x3C); // Reserved
// nn::settings::system::SleepSettings
SleepSettings sleep_settings;
std::array<u8, 0x34> reserved_2A10C;
INSERT_PADDING_BYTES(0x34); // Reserved
// nn::settings::system::EulaVersion
u32 eula_version_count;
std::array<u8, 0xC> reserved_2A144;
INSERT_PADDING_BYTES(0xC); // Reserved
std::array<EulaVersion, 32> eula_versions;
std::array<u8, 0x200> reserved_2A750;
INSERT_PADDING_BYTES(0x200); // Reserved
// nn::settings::system::DeviceNickName
std::array<u8, 0x80> device_nick_name;
std::array<u8, 0x80> reserved_2A9D0;
INSERT_PADDING_BYTES(0x80); // Reserved
bool auto_update_enable_flag;
std::array<u8, 0x3> pad_2AA51;
std::array<u8, 0x4C> reserved_2AA54;
INSERT_PADDING_BYTES(0x3);
INSERT_PADDING_BYTES(0x4C); // Reserved
// nn::settings::system::BluetoothDevicesSettings
std::array<std::array<u8, 0x200>, 14> bluetooth_device_settings_last_14;
std::array<u8, 0x2000> reserved_2C6A0;
INSERT_PADDING_BYTES(0x2000); // Reserved
// nn::settings::system::NxControllerSettings
std::array<std::array<u8, 0x800>, 10> nx_controller_settings_data_from_offset_30;

View File

@ -4,72 +4,13 @@
#pragma once
#include "core/hle/service/service.h"
#include "core/hle/service/set/system_settings.h"
#include "core/hle/service/set/settings_types.h"
namespace Core {
class System;
}
namespace Service::Set {
enum class KeyboardLayout : u64 {
Japanese = 0,
EnglishUs = 1,
EnglishUsInternational = 2,
EnglishUk = 3,
French = 4,
FrenchCa = 5,
Spanish = 6,
SpanishLatin = 7,
German = 8,
Italian = 9,
Portuguese = 10,
Russian = 11,
Korean = 12,
ChineseSimplified = 13,
ChineseTraditional = 14,
};
constexpr std::array<LanguageCode, 18> available_language_codes = {{
LanguageCode::JA,
LanguageCode::EN_US,
LanguageCode::FR,
LanguageCode::DE,
LanguageCode::IT,
LanguageCode::ES,
LanguageCode::ZH_CN,
LanguageCode::KO,
LanguageCode::NL,
LanguageCode::PT,
LanguageCode::RU,
LanguageCode::ZH_TW,
LanguageCode::EN_GB,
LanguageCode::FR_CA,
LanguageCode::ES_419,
LanguageCode::ZH_HANS,
LanguageCode::ZH_HANT,
LanguageCode::PT_BR,
}};
static constexpr std::array<std::pair<LanguageCode, KeyboardLayout>, 18> language_to_layout{{
{LanguageCode::JA, KeyboardLayout::Japanese},
{LanguageCode::EN_US, KeyboardLayout::EnglishUs},
{LanguageCode::FR, KeyboardLayout::French},
{LanguageCode::DE, KeyboardLayout::German},
{LanguageCode::IT, KeyboardLayout::Italian},
{LanguageCode::ES, KeyboardLayout::Spanish},
{LanguageCode::ZH_CN, KeyboardLayout::ChineseSimplified},
{LanguageCode::KO, KeyboardLayout::Korean},
{LanguageCode::NL, KeyboardLayout::EnglishUsInternational},
{LanguageCode::PT, KeyboardLayout::Portuguese},
{LanguageCode::RU, KeyboardLayout::Russian},
{LanguageCode::ZH_TW, KeyboardLayout::ChineseTraditional},
{LanguageCode::EN_GB, KeyboardLayout::EnglishUk},
{LanguageCode::FR_CA, KeyboardLayout::FrenchCa},
{LanguageCode::ES_419, KeyboardLayout::SpanishLatin},
{LanguageCode::ZH_HANS, KeyboardLayout::ChineseSimplified},
{LanguageCode::ZH_HANT, KeyboardLayout::ChineseTraditional},
{LanguageCode::PT_BR, KeyboardLayout::Portuguese},
}};
LanguageCode GetLanguageCodeFromIndex(std::size_t idx);

View File

@ -0,0 +1,451 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
#pragma once
#include <array>
#include "common/bit_field.h"
#include "common/common_funcs.h"
#include "common/common_types.h"
#include "common/uuid.h"
#include "core/hle/service/time/clock_types.h"
namespace Service::Set {
/// This is nn::settings::system::AudioOutputMode
enum class AudioOutputMode : u32 {
ch_1,
ch_2,
ch_5_1,
ch_7_1,
};
/// This is nn::settings::system::AudioOutputModeTarget
enum class AudioOutputModeTarget : u32 {
Hdmi,
Speaker,
Headphone,
};
/// This is nn::settings::system::AudioVolumeTarget
enum class AudioVolumeTarget : u32 {
Speaker,
Headphone,
};
/// This is nn::settings::system::ClockSourceId
enum class ClockSourceId : u32 {
NetworkSystemClock,
SteadyClock,
};
/// This is nn::settings::system::CmuMode
enum class CmuMode : u32 {
None,
ColorInvert,
HighContrast,
GrayScale,
};
/// This is nn::settings::system::ChineseTraditionalInputMethod
enum class ChineseTraditionalInputMethod : u32 {
Unknown0 = 0,
Unknown1 = 1,
Unknown2 = 2,
};
/// Indicates the current theme set by the system settings
enum class ColorSet : u32 {
BasicWhite = 0,
BasicBlack = 1,
};
/// This is nn::settings::system::ConsoleSleepPlan
enum class ConsoleSleepPlan : u32 {
Sleep1Hour,
Sleep2Hour,
Sleep3Hour,
Sleep6Hour,
Sleep12Hour,
Never,
};
/// This is nn::settings::system::ErrorReportSharePermission
enum class ErrorReportSharePermission : u32 {
NotConfirmed,
Granted,
Denied,
};
/// This is nn::settings::system::EulaVersionClockType
enum class EulaVersionClockType : u32 {
NetworkSystemClock,
SteadyClock,
};
/// This is nn::settings::factory::RegionCode
enum class FactoryRegionCode : u32 {
Japan,
Usa,
Europe,
Australia,
China,
Korea,
Taiwan,
};
/// This is nn::settings::system::FriendPresenceOverlayPermission
enum class FriendPresenceOverlayPermission : u8 {
NotConfirmed,
NoDisplay,
FavoriteFriends,
Friends,
};
enum class GetFirmwareVersionType {
Version1,
Version2,
};
/// This is nn::settings::system::HandheldSleepPlan
enum class HandheldSleepPlan : u32 {
Sleep1Min,
Sleep3Min,
Sleep5Min,
Sleep10Min,
Sleep30Min,
Never,
};
/// This is nn::settings::system::HdmiContentType
enum class HdmiContentType : u32 {
None,
Graphics,
Cinema,
Photo,
Game,
};
enum class KeyboardLayout : u32 {
Japanese = 0,
EnglishUs = 1,
EnglishUsInternational = 2,
EnglishUk = 3,
French = 4,
FrenchCa = 5,
Spanish = 6,
SpanishLatin = 7,
German = 8,
Italian = 9,
Portuguese = 10,
Russian = 11,
Korean = 12,
ChineseSimplified = 13,
ChineseTraditional = 14,
};
/// This is "nn::settings::LanguageCode", which is a NUL-terminated string stored in a u64.
enum class LanguageCode : u64 {
JA = 0x000000000000616A,
EN_US = 0x00000053552D6E65,
FR = 0x0000000000007266,
DE = 0x0000000000006564,
IT = 0x0000000000007469,
ES = 0x0000000000007365,
ZH_CN = 0x0000004E432D687A,
KO = 0x0000000000006F6B,
NL = 0x0000000000006C6E,
PT = 0x0000000000007470,
RU = 0x0000000000007572,
ZH_TW = 0x00000057542D687A,
EN_GB = 0x00000042472D6E65,
FR_CA = 0x00000041432D7266,
ES_419 = 0x00003931342D7365,
ZH_HANS = 0x00736E61482D687A,
ZH_HANT = 0x00746E61482D687A,
PT_BR = 0x00000052422D7470,
};
/// This is nn::settings::system::NotificationVolume
enum class NotificationVolume : u32 {
Mute,
Low,
High,
};
/// This is nn::settings::system::PrimaryAlbumStorage
enum class PrimaryAlbumStorage : u32 {
Nand,
SdCard,
};
/// Indicates the current console is a retail or kiosk unit
enum class QuestFlag : u8 {
Retail = 0,
Kiosk = 1,
};
/// This is nn::settings::system::RgbRange
enum class RgbRange : u32 {
Auto,
Full,
Limited,
};
/// This is nn::settings::system::RegionCode
enum class SystemRegionCode : u32 {
Japan,
Usa,
Europe,
Australia,
HongKongTaiwanKorea,
China,
};
/// This is nn::settings::system::TouchScreenMode
enum class TouchScreenMode : u32 {
Stylus,
Standard,
};
/// This is nn::settings::system::TvResolution
enum class TvResolution : u32 {
Auto,
Resolution1080p,
Resolution720p,
Resolution480p,
};
constexpr std::array<LanguageCode, 18> available_language_codes = {{
LanguageCode::JA,
LanguageCode::EN_US,
LanguageCode::FR,
LanguageCode::DE,
LanguageCode::IT,
LanguageCode::ES,
LanguageCode::ZH_CN,
LanguageCode::KO,
LanguageCode::NL,
LanguageCode::PT,
LanguageCode::RU,
LanguageCode::ZH_TW,
LanguageCode::EN_GB,
LanguageCode::FR_CA,
LanguageCode::ES_419,
LanguageCode::ZH_HANS,
LanguageCode::ZH_HANT,
LanguageCode::PT_BR,
}};
static constexpr std::array<std::pair<LanguageCode, KeyboardLayout>, 18> language_to_layout{{
{LanguageCode::JA, KeyboardLayout::Japanese},
{LanguageCode::EN_US, KeyboardLayout::EnglishUs},
{LanguageCode::FR, KeyboardLayout::French},
{LanguageCode::DE, KeyboardLayout::German},
{LanguageCode::IT, KeyboardLayout::Italian},
{LanguageCode::ES, KeyboardLayout::Spanish},
{LanguageCode::ZH_CN, KeyboardLayout::ChineseSimplified},
{LanguageCode::KO, KeyboardLayout::Korean},
{LanguageCode::NL, KeyboardLayout::EnglishUsInternational},
{LanguageCode::PT, KeyboardLayout::Portuguese},
{LanguageCode::RU, KeyboardLayout::Russian},
{LanguageCode::ZH_TW, KeyboardLayout::ChineseTraditional},
{LanguageCode::EN_GB, KeyboardLayout::EnglishUk},
{LanguageCode::FR_CA, KeyboardLayout::FrenchCa},
{LanguageCode::ES_419, KeyboardLayout::SpanishLatin},
{LanguageCode::ZH_HANS, KeyboardLayout::ChineseSimplified},
{LanguageCode::ZH_HANT, KeyboardLayout::ChineseTraditional},
{LanguageCode::PT_BR, KeyboardLayout::Portuguese},
}};
/// This is nn::settings::system::AccountNotificationFlag
struct AccountNotificationFlag {
union {
u32 raw{};
BitField<0, 1, u32> FriendOnlineFlag;
BitField<1, 1, u32> FriendRequestFlag;
BitField<8, 1, u32> CoralInvitationFlag;
};
};
static_assert(sizeof(AccountNotificationFlag) == 4, "AccountNotificationFlag is an invalid size");
/// This is nn::settings::system::AccountSettings
struct AccountSettings {
u32 flags;
};
static_assert(sizeof(AccountSettings) == 4, "AccountSettings is an invalid size");
/// This is nn::settings::system::DataDeletionFlag
struct DataDeletionFlag {
union {
u32 raw{};
BitField<0, 1, u32> AutomaticDeletionFlag;
};
};
static_assert(sizeof(DataDeletionFlag) == 4, "DataDeletionFlag is an invalid size");
/// This is nn::settings::system::InitialLaunchFlag
struct InitialLaunchFlag {
union {
u32 raw{};
BitField<0, 1, u32> InitialLaunchCompletionFlag;
BitField<8, 1, u32> InitialLaunchUserAdditionFlag;
BitField<16, 1, u32> InitialLaunchTimestampFlag;
};
};
static_assert(sizeof(InitialLaunchFlag) == 4, "InitialLaunchFlag is an invalid size");
/// This is nn::settings::system::SleepFlag
struct SleepFlag {
union {
u32 raw{};
BitField<0, 1, u32> SleepsWhilePlayingMedia;
BitField<1, 1, u32> WakesAtPowerStateChange;
};
};
static_assert(sizeof(SleepFlag) == 4, "TvFlag is an invalid size");
/// This is nn::settings::system::NotificationFlag
struct NotificationFlag {
union {
u32 raw{};
BitField<0, 1, u32> RingtoneFlag;
BitField<1, 1, u32> DownloadCompletionFlag;
BitField<8, 1, u32> EnablesNews;
BitField<9, 1, u32> IncomingLampFlag;
};
};
static_assert(sizeof(NotificationFlag) == 4, "NotificationFlag is an invalid size");
/// This is nn::settings::system::TvFlag
struct TvFlag {
union {
u32 raw{};
BitField<0, 1, u32> Allows4k;
BitField<1, 1, u32> Allows3d;
BitField<2, 1, u32> AllowsCec;
BitField<3, 1, u32> PreventsScreenBurnIn;
};
};
static_assert(sizeof(TvFlag) == 4, "TvFlag is an invalid size");
/// This is nn::settings::system::UserSelectorFlag
struct UserSelectorFlag {
union {
u32 raw{};
BitField<0, 1, u32> SkipIfSingleUser;
BitField<31, 1, u32> Unknown;
};
};
static_assert(sizeof(UserSelectorFlag) == 4, "UserSelectorFlag is an invalid size");
/// This is nn::settings::system::AccountNotificationSettings
struct AccountNotificationSettings {
Common::UUID uid;
AccountNotificationFlag flags;
FriendPresenceOverlayPermission friend_presence_permission;
FriendPresenceOverlayPermission friend_invitation_permission;
INSERT_PADDING_BYTES(0x2);
};
static_assert(sizeof(AccountNotificationSettings) == 0x18,
"AccountNotificationSettings is an invalid size");
/// This is nn::settings::system::EulaVersion
struct EulaVersion {
u32 version;
SystemRegionCode region_code;
EulaVersionClockType clock_type;
INSERT_PADDING_BYTES(0x4);
s64 posix_time;
Time::Clock::SteadyClockTimePoint timestamp;
};
static_assert(sizeof(EulaVersion) == 0x30, "EulaVersion is incorrect size");
struct FirmwareVersionFormat {
u8 major;
u8 minor;
u8 micro;
INSERT_PADDING_BYTES(1);
u8 revision_major;
u8 revision_minor;
INSERT_PADDING_BYTES(2);
std::array<char, 0x20> platform;
std::array<u8, 0x40> version_hash;
std::array<char, 0x18> display_version;
std::array<char, 0x80> display_title;
};
static_assert(sizeof(FirmwareVersionFormat) == 0x100, "FirmwareVersionFormat is an invalid size");
/// This is nn::settings::system::HomeMenuScheme
struct HomeMenuScheme {
u32 main;
u32 back;
u32 sub;
u32 bezel;
u32 extra;
};
static_assert(sizeof(HomeMenuScheme) == 0x14, "HomeMenuScheme is incorrect size");
/// This is nn::settings::system::InitialLaunchSettings
struct InitialLaunchSettings {
InitialLaunchFlag flags;
INSERT_PADDING_BYTES(0x4);
Service::Time::Clock::SteadyClockTimePoint timestamp;
};
static_assert(sizeof(InitialLaunchSettings) == 0x20, "InitialLaunchSettings is incorrect size");
#pragma pack(push, 4)
struct InitialLaunchSettingsPacked {
InitialLaunchFlag flags;
Service::Time::Clock::SteadyClockTimePoint timestamp;
};
#pragma pack(pop)
static_assert(sizeof(InitialLaunchSettingsPacked) == 0x1C,
"InitialLaunchSettingsPacked is incorrect size");
/// This is nn::settings::system::NotificationTime
struct NotificationTime {
u32 hour;
u32 minute;
};
static_assert(sizeof(NotificationTime) == 0x8, "NotificationTime is an invalid size");
/// This is nn::settings::system::NotificationSettings
struct NotificationSettings {
NotificationFlag flags;
NotificationVolume volume;
NotificationTime start_time;
NotificationTime stop_time;
};
static_assert(sizeof(NotificationSettings) == 0x18, "NotificationSettings is an invalid size");
/// This is nn::settings::system::SleepSettings
struct SleepSettings {
SleepFlag flags;
HandheldSleepPlan handheld_sleep_plan;
ConsoleSleepPlan console_sleep_plan;
};
static_assert(sizeof(SleepSettings) == 0xc, "SleepSettings is incorrect size");
/// This is nn::settings::system::TvSettings
struct TvSettings {
TvFlag flags;
TvResolution tv_resolution;
HdmiContentType hdmi_content_type;
RgbRange rgb_range;
CmuMode cmu_mode;
u32 tv_underscan;
f32 tv_gama;
f32 contrast_ratio;
};
static_assert(sizeof(TvSettings) == 0x20, "TvSettings is an invalid size");
} // namespace Service::Set

View File

@ -97,8 +97,8 @@ ISystemSettingsServer::ISystemSettingsServer(Core::System& system_)
{3, &ISystemSettingsServer::GetFirmwareVersion, "GetFirmwareVersion"},
{4, &ISystemSettingsServer::GetFirmwareVersion2, "GetFirmwareVersion2"},
{5, nullptr, "GetFirmwareVersionDigest"},
{7, nullptr, "GetLockScreenFlag"},
{8, nullptr, "SetLockScreenFlag"},
{7, &ISystemSettingsServer::GetLockScreenFlag, "GetLockScreenFlag"},
{8, &ISystemSettingsServer::SetLockScreenFlag, "SetLockScreenFlag"},
{9, nullptr, "GetBacklightSettings"},
{10, nullptr, "SetBacklightSettings"},
{11, nullptr, "SetBluetoothDevicesSettings"},
@ -157,12 +157,12 @@ ISystemSettingsServer::ISystemSettingsServer(Core::System& system_)
{66, nullptr, "SetUsb30EnableFlag"},
{67, nullptr, "GetBatteryLot"},
{68, nullptr, "GetSerialNumber"},
{69, nullptr, "GetNfcEnableFlag"},
{70, nullptr, "SetNfcEnableFlag"},
{69, &ISystemSettingsServer::GetNfcEnableFlag, "GetNfcEnableFlag"},
{70, &ISystemSettingsServer::SetNfcEnableFlag, "SetNfcEnableFlag"},
{71, &ISystemSettingsServer::GetSleepSettings, "GetSleepSettings"},
{72, &ISystemSettingsServer::SetSleepSettings, "SetSleepSettings"},
{73, nullptr, "GetWirelessLanEnableFlag"},
{74, nullptr, "SetWirelessLanEnableFlag"},
{73, &ISystemSettingsServer::GetWirelessLanEnableFlag, "GetWirelessLanEnableFlag"},
{74, &ISystemSettingsServer::SetWirelessLanEnableFlag, "SetWirelessLanEnableFlag"},
{75, &ISystemSettingsServer::GetInitialLaunchSettings, "GetInitialLaunchSettings"},
{76, &ISystemSettingsServer::SetInitialLaunchSettings, "SetInitialLaunchSettings"},
{77, &ISystemSettingsServer::GetDeviceNickName, "GetDeviceNickName"},
@ -176,8 +176,8 @@ ISystemSettingsServer::ISystemSettingsServer(Core::System& system_)
{85, nullptr, "SetPtmBatteryLot"},
{86, nullptr, "GetPtmFuelGaugeParameter"},
{87, nullptr, "SetPtmFuelGaugeParameter"},
{88, nullptr, "GetBluetoothEnableFlag"},
{89, nullptr, "SetBluetoothEnableFlag"},
{88, &ISystemSettingsServer::GetBluetoothEnableFlag, "GetBluetoothEnableFlag"},
{89, &ISystemSettingsServer::SetBluetoothEnableFlag, "SetBluetoothEnableFlag"},
{90, &ISystemSettingsServer::GetMiiAuthorId, "GetMiiAuthorId"},
{91, nullptr, "SetShutdownRtcValue"},
{92, nullptr, "GetShutdownRtcValue"},
@ -510,6 +510,25 @@ void ISystemSettingsServer::SetUserSystemClockContext(HLERequestContext& ctx) {
rb.Push(res);
}
void ISystemSettingsServer::GetLockScreenFlag(HLERequestContext& ctx) {
LOG_INFO(Service_SET, "called, lock_screen_flag={}", m_system_settings.lock_screen_flag);
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
rb.Push(m_system_settings.lock_screen_flag);
}
void ISystemSettingsServer::SetLockScreenFlag(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
m_system_settings.lock_screen_flag = rp.Pop<bool>();
SetSaveNeeded();
LOG_INFO(Service_SET, "called, lock_screen_flag={}", m_system_settings.lock_screen_flag);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
void ISystemSettingsServer::GetAccountSettings(HLERequestContext& ctx) {
LOG_INFO(Service_SET, "called");
@ -531,7 +550,7 @@ void ISystemSettingsServer::SetAccountSettings(HLERequestContext& ctx) {
}
void ISystemSettingsServer::GetEulaVersions(HLERequestContext& ctx) {
LOG_INFO(Service_SET, "called");
LOG_INFO(Service_SET, "called, elements={}", m_system_settings.eula_version_count);
ctx.WriteBuffer(m_system_settings.eula_versions);
@ -557,7 +576,7 @@ void ISystemSettingsServer::SetEulaVersions(HLERequestContext& ctx) {
}
void ISystemSettingsServer::GetColorSetId(HLERequestContext& ctx) {
LOG_DEBUG(Service_SET, "called");
LOG_DEBUG(Service_SET, "called, color_set=", m_system_settings.color_set_id);
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
@ -576,7 +595,13 @@ void ISystemSettingsServer::SetColorSetId(HLERequestContext& ctx) {
}
void ISystemSettingsServer::GetNotificationSettings(HLERequestContext& ctx) {
LOG_INFO(Service_SET, "called");
LOG_INFO(Service_SET, "called, flags={}, volume={}, head_time={}:{}, tailt_time={}:{}",
m_system_settings.notification_settings.flags.raw,
m_system_settings.notification_settings.volume,
m_system_settings.notification_settings.start_time.hour,
m_system_settings.notification_settings.start_time.minute,
m_system_settings.notification_settings.stop_time.hour,
m_system_settings.notification_settings.stop_time.minute);
IPC::ResponseBuilder rb{ctx, 8};
rb.Push(ResultSuccess);
@ -601,7 +626,8 @@ void ISystemSettingsServer::SetNotificationSettings(HLERequestContext& ctx) {
}
void ISystemSettingsServer::GetAccountNotificationSettings(HLERequestContext& ctx) {
LOG_INFO(Service_SET, "called");
LOG_INFO(Service_SET, "called, elements={}",
m_system_settings.account_notification_settings_count);
ctx.WriteBuffer(m_system_settings.account_notification_settings);
@ -645,6 +671,7 @@ using Settings =
static Settings GetSettings() {
Settings ret;
// AM
ret["hbloader"]["applet_heap_size"] = ToBytes(u64{0x0});
ret["hbloader"]["applet_heap_reservation_size"] = ToBytes(u64{0x8600000});
@ -656,6 +683,24 @@ static Settings GetSettings() {
ret["time"]["standard_steady_clock_test_offset_minutes"] = ToBytes(s32{0});
ret["time"]["standard_user_clock_initial_year"] = ToBytes(s32{2023});
// HID
ret["hid_debug"]["enables_debugpad"] = ToBytes(bool{true});
ret["hid_debug"]["manages_devices"] = ToBytes(bool{true});
ret["hid_debug"]["manages_touch_ic_i2c"] = ToBytes(bool{true});
ret["hid_debug"]["emulate_future_device"] = ToBytes(bool{false});
ret["hid_debug"]["emulate_mcu_hardware_error"] = ToBytes(bool{false});
ret["hid_debug"]["enables_rail"] = ToBytes(bool{true});
ret["hid_debug"]["emulate_firmware_update_failure"] = ToBytes(bool{false});
ret["hid_debug"]["failure_firmware_update"] = ToBytes(s32{0});
ret["hid_debug"]["ble_disabled"] = ToBytes(bool{false});
ret["hid_debug"]["dscale_disabled"] = ToBytes(bool{false});
ret["hid_debug"]["force_handheld"] = ToBytes(bool{true});
ret["hid_debug"]["disabled_features_per_id"] = std::vector<u8>(0xa8);
ret["hid_debug"]["touch_firmware_auto_update_disabled"] = ToBytes(bool{false});
// Settings
ret["settings_debug"]["is_debug_mode_enabled"] = ToBytes(bool{false});
return ret;
}
@ -708,7 +753,15 @@ void ISystemSettingsServer::GetSettingsItemValue(HLERequestContext& ctx) {
}
void ISystemSettingsServer::GetTvSettings(HLERequestContext& ctx) {
LOG_INFO(Service_SET, "called");
LOG_INFO(Service_SET,
"called, flags={}, cmu_mode={}, contrast_ratio={}, hdmi_content_type={}, "
"rgb_range={}, tv_gama={}, tv_resolution={}, tv_underscan={}",
m_system_settings.tv_settings.flags.raw, m_system_settings.tv_settings.cmu_mode,
m_system_settings.tv_settings.contrast_ratio,
m_system_settings.tv_settings.hdmi_content_type,
m_system_settings.tv_settings.rgb_range, m_system_settings.tv_settings.tv_gama,
m_system_settings.tv_settings.tv_resolution,
m_system_settings.tv_settings.tv_underscan);
IPC::ResponseBuilder rb{ctx, 10};
rb.Push(ResultSuccess);
@ -735,23 +788,26 @@ void ISystemSettingsServer::SetTvSettings(HLERequestContext& ctx) {
}
void ISystemSettingsServer::GetDebugModeFlag(HLERequestContext& ctx) {
LOG_DEBUG(Service_SET, "called");
bool is_debug_mode_enabled = false;
GetSettingsItemValue<bool>(is_debug_mode_enabled, "settings_debug", "is_debug_mode_enabled");
LOG_DEBUG(Service_SET, "called, is_debug_mode_enabled={}", is_debug_mode_enabled);
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
rb.Push<u32>(0);
rb.Push(is_debug_mode_enabled);
}
void ISystemSettingsServer::GetQuestFlag(HLERequestContext& ctx) {
LOG_WARNING(Service_SET, "(STUBBED) called");
LOG_INFO(Service_SET, "called, quest_flag={}", m_system_settings.quest_flag);
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
rb.PushEnum(QuestFlag::Retail);
rb.PushEnum(m_system_settings.quest_flag);
}
void ISystemSettingsServer::GetDeviceTimeZoneLocationName(HLERequestContext& ctx) {
LOG_WARNING(Service_SET, "called");
LOG_INFO(Service_SET, "called");
Service::Time::TimeZone::LocationName name{};
auto res = GetDeviceTimeZoneLocationName(name);
@ -762,7 +818,7 @@ void ISystemSettingsServer::GetDeviceTimeZoneLocationName(HLERequestContext& ctx
}
void ISystemSettingsServer::SetDeviceTimeZoneLocationName(HLERequestContext& ctx) {
LOG_WARNING(Service_SET, "called");
LOG_INFO(Service_SET, "called");
IPC::RequestParser rp{ctx};
auto name{rp.PopRaw<Service::Time::TimeZone::LocationName>()};
@ -775,7 +831,7 @@ void ISystemSettingsServer::SetDeviceTimeZoneLocationName(HLERequestContext& ctx
void ISystemSettingsServer::SetRegionCode(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
m_system_settings.region_code = rp.PopEnum<RegionCode>();
m_system_settings.region_code = rp.PopEnum<SystemRegionCode>();
SetSaveNeeded();
LOG_INFO(Service_SET, "called, region_code={}", m_system_settings.region_code);
@ -832,15 +888,38 @@ void ISystemSettingsServer::SetUserSystemClockAutomaticCorrectionEnabled(HLERequ
}
void ISystemSettingsServer::GetPrimaryAlbumStorage(HLERequestContext& ctx) {
LOG_WARNING(Service_SET, "(STUBBED) called");
LOG_INFO(Service_SET, "called, primary_album_storage={}",
m_system_settings.primary_album_storage);
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
rb.PushEnum(PrimaryAlbumStorage::SdCard);
rb.PushEnum(m_system_settings.primary_album_storage);
}
void ISystemSettingsServer::GetNfcEnableFlag(HLERequestContext& ctx) {
LOG_INFO(Service_SET, "called, nfc_enable_flag={}", m_system_settings.nfc_enable_flag);
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
rb.Push<u8>(m_system_settings.nfc_enable_flag);
}
void ISystemSettingsServer::SetNfcEnableFlag(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
m_system_settings.nfc_enable_flag = rp.Pop<bool>();
SetSaveNeeded();
LOG_INFO(Service_SET, "called, nfc_enable_flag={}", m_system_settings.nfc_enable_flag);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
void ISystemSettingsServer::GetSleepSettings(HLERequestContext& ctx) {
LOG_INFO(Service_SET, "called");
LOG_INFO(Service_SET, "called, flags={}, handheld_sleep_plan={}, console_sleep_plan={}",
m_system_settings.sleep_settings.flags.raw,
m_system_settings.sleep_settings.handheld_sleep_plan,
m_system_settings.sleep_settings.console_sleep_plan);
IPC::ResponseBuilder rb{ctx, 5};
rb.Push(ResultSuccess);
@ -861,8 +940,32 @@ void ISystemSettingsServer::SetSleepSettings(HLERequestContext& ctx) {
rb.Push(ResultSuccess);
}
void ISystemSettingsServer::GetWirelessLanEnableFlag(HLERequestContext& ctx) {
LOG_INFO(Service_SET, "called, wireless_lan_enable_flag={}",
m_system_settings.wireless_lan_enable_flag);
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
rb.Push(m_system_settings.wireless_lan_enable_flag);
}
void ISystemSettingsServer::SetWirelessLanEnableFlag(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
m_system_settings.wireless_lan_enable_flag = rp.Pop<bool>();
SetSaveNeeded();
LOG_INFO(Service_SET, "called, wireless_lan_enable_flag={}",
m_system_settings.wireless_lan_enable_flag);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
void ISystemSettingsServer::GetInitialLaunchSettings(HLERequestContext& ctx) {
LOG_INFO(Service_SET, "called");
LOG_INFO(Service_SET, "called, flags={}, timestamp={}",
m_system_settings.initial_launch_settings_packed.flags.raw,
m_system_settings.initial_launch_settings_packed.timestamp.time_point);
IPC::ResponseBuilder rb{ctx, 10};
rb.Push(ResultSuccess);
rb.PushRaw(m_system_settings.initial_launch_settings_packed);
@ -913,35 +1016,51 @@ void ISystemSettingsServer::GetProductModel(HLERequestContext& ctx) {
rb.Push(product_model);
}
void ISystemSettingsServer::GetMiiAuthorId(HLERequestContext& ctx) {
const auto author_id = Common::UUID::MakeDefault();
void ISystemSettingsServer::GetBluetoothEnableFlag(HLERequestContext& ctx) {
LOG_INFO(Service_SET, "called, bluetooth_enable_flag={}",
m_system_settings.bluetooth_enable_flag);
LOG_WARNING(Service_SET, "(STUBBED) called, author_id={}", author_id.FormattedString());
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
rb.Push<u8>(m_system_settings.bluetooth_enable_flag);
}
void ISystemSettingsServer::SetBluetoothEnableFlag(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
m_system_settings.bluetooth_enable_flag = rp.Pop<bool>();
SetSaveNeeded();
LOG_INFO(Service_SET, "called, bluetooth_enable_flag={}",
m_system_settings.bluetooth_enable_flag);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
void ISystemSettingsServer::GetMiiAuthorId(HLERequestContext& ctx) {
LOG_INFO(Service_SET, "called, author_id={}",
m_system_settings.mii_author_id.FormattedString());
IPC::ResponseBuilder rb{ctx, 6};
rb.Push(ResultSuccess);
rb.PushRaw(author_id);
rb.PushRaw(m_system_settings.mii_author_id);
}
void ISystemSettingsServer::GetAutoUpdateEnableFlag(HLERequestContext& ctx) {
u8 auto_update_flag{};
LOG_WARNING(Service_SET, "(STUBBED) called, auto_update_flag={}", auto_update_flag);
LOG_INFO(Service_SET, "called, auto_update_flag={}", m_system_settings.auto_update_enable_flag);
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
rb.Push(auto_update_flag);
rb.Push(m_system_settings.auto_update_enable_flag);
}
void ISystemSettingsServer::GetBatteryPercentageFlag(HLERequestContext& ctx) {
u8 battery_percentage_flag{1};
LOG_WARNING(Service_SET, "(STUBBED) called, battery_percentage_flag={}",
battery_percentage_flag);
LOG_DEBUG(Service_SET, "called, battery_percentage_flag={}",
m_system_settings.battery_percentage_flag);
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
rb.Push(battery_percentage_flag);
rb.Push(m_system_settings.battery_percentage_flag);
}
void ISystemSettingsServer::SetExternalSteadyClockInternalOffset(HLERequestContext& ctx) {
@ -968,11 +1087,12 @@ void ISystemSettingsServer::GetExternalSteadyClockInternalOffset(HLERequestConte
}
void ISystemSettingsServer::GetErrorReportSharePermission(HLERequestContext& ctx) {
LOG_WARNING(Service_SET, "(STUBBED) called");
LOG_INFO(Service_SET, "called, error_report_share_permission={}",
m_system_settings.error_report_share_permission);
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
rb.PushEnum(ErrorReportSharePermission::Denied);
rb.PushEnum(m_system_settings.error_report_share_permission);
}
void ISystemSettingsServer::GetAppletLaunchFlags(HLERequestContext& ctx) {
@ -1014,7 +1134,7 @@ void ISystemSettingsServer::GetKeyboardLayout(HLERequestContext& ctx) {
}
void ISystemSettingsServer::GetDeviceTimeZoneLocationUpdatedTime(HLERequestContext& ctx) {
LOG_WARNING(Service_SET, "called.");
LOG_INFO(Service_SET, "called");
Service::Time::Clock::SteadyClockTimePoint time_point{};
auto res = GetDeviceTimeZoneLocationUpdatedTime(time_point);
@ -1025,7 +1145,7 @@ void ISystemSettingsServer::GetDeviceTimeZoneLocationUpdatedTime(HLERequestConte
}
void ISystemSettingsServer::SetDeviceTimeZoneLocationUpdatedTime(HLERequestContext& ctx) {
LOG_WARNING(Service_SET, "called.");
LOG_INFO(Service_SET, "called");
IPC::RequestParser rp{ctx};
auto time_point{rp.PopRaw<Service::Time::Clock::SteadyClockTimePoint>()};
@ -1038,7 +1158,7 @@ void ISystemSettingsServer::SetDeviceTimeZoneLocationUpdatedTime(HLERequestConte
void ISystemSettingsServer::GetUserSystemClockAutomaticCorrectionUpdatedTime(
HLERequestContext& ctx) {
LOG_WARNING(Service_SET, "called.");
LOG_INFO(Service_SET, "called");
Service::Time::Clock::SteadyClockTimePoint time_point{};
auto res = GetUserSystemClockAutomaticCorrectionUpdatedTime(time_point);
@ -1050,7 +1170,7 @@ void ISystemSettingsServer::GetUserSystemClockAutomaticCorrectionUpdatedTime(
void ISystemSettingsServer::SetUserSystemClockAutomaticCorrectionUpdatedTime(
HLERequestContext& ctx) {
LOG_WARNING(Service_SET, "called.");
LOG_INFO(Service_SET, "called");
IPC::RequestParser rp{ctx};
auto time_point{rp.PopRaw<Service::Time::Clock::SteadyClockTimePoint>()};
@ -1062,11 +1182,12 @@ void ISystemSettingsServer::SetUserSystemClockAutomaticCorrectionUpdatedTime(
}
void ISystemSettingsServer::GetChineseTraditionalInputMethod(HLERequestContext& ctx) {
LOG_WARNING(Service_SET, "(STUBBED) called");
LOG_INFO(Service_SET, "called, chinese_traditional_input_method={}",
m_system_settings.chinese_traditional_input_method);
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
rb.PushEnum(ChineseTraditionalInputMethod::Unknown0);
rb.PushEnum(m_system_settings.chinese_traditional_input_method);
}
void ISystemSettingsServer::GetHomeMenuScheme(HLERequestContext& ctx) {
@ -1094,11 +1215,11 @@ void ISystemSettingsServer::GetHomeMenuSchemeModel(HLERequestContext& ctx) {
}
void ISystemSettingsServer::GetFieldTestingFlag(HLERequestContext& ctx) {
LOG_WARNING(Service_SET, "(STUBBED) called");
LOG_INFO(Service_SET, "called, field_testing_flag={}", m_system_settings.field_testing_flag);
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
rb.Push<u8>(false);
rb.Push(m_system_settings.field_testing_flag);
}
void ISystemSettingsServer::SetupSettings() {

View File

@ -12,10 +12,11 @@
#include "common/uuid.h"
#include "core/hle/result.h"
#include "core/hle/service/service.h"
#include "core/hle/service/set/appln_settings.h"
#include "core/hle/service/set/device_settings.h"
#include "core/hle/service/set/private_settings.h"
#include "core/hle/service/set/system_settings.h"
#include "core/hle/service/set/setting_formats/appln_settings.h"
#include "core/hle/service/set/setting_formats/device_settings.h"
#include "core/hle/service/set/setting_formats/private_settings.h"
#include "core/hle/service/set/setting_formats/system_settings.h"
#include "core/hle/service/set/settings_types.h"
#include "core/hle/service/time/clock_types.h"
#include "core/hle/service/time/time_zone_types.h"
@ -24,25 +25,6 @@ class System;
}
namespace Service::Set {
enum class GetFirmwareVersionType {
Version1,
Version2,
};
struct FirmwareVersionFormat {
u8 major;
u8 minor;
u8 micro;
INSERT_PADDING_BYTES(1);
u8 revision_major;
u8 revision_minor;
INSERT_PADDING_BYTES(2);
std::array<char, 0x20> platform;
std::array<u8, 0x40> version_hash;
std::array<char, 0x18> display_version;
std::array<char, 0x80> display_title;
};
static_assert(sizeof(FirmwareVersionFormat) == 0x100, "FirmwareVersionFormat is an invalid size");
Result GetFirmwareVersionImpl(FirmwareVersionFormat& out_firmware, Core::System& system,
GetFirmwareVersionType type);
@ -55,6 +37,18 @@ public:
Result GetSettingsItemValue(std::vector<u8>& out_value, const std::string& category,
const std::string& name);
template <typename T>
Result GetSettingsItemValue(T& value, const std::string& category, const std::string& name) {
std::vector<u8> data;
const auto result = GetSettingsItemValue(data, category, name);
if (result.IsError()) {
return result;
}
ASSERT(data.size() >= sizeof(T));
std::memcpy(&value, data.data(), sizeof(T));
return result;
}
Result GetExternalSteadyClockSourceId(Common::UUID& out_id);
Result SetExternalSteadyClockSourceId(Common::UUID id);
Result GetUserSystemClockContext(Service::Time::Clock::SystemClockContext& out_context);
@ -80,6 +74,8 @@ private:
void SetLanguageCode(HLERequestContext& ctx);
void GetFirmwareVersion(HLERequestContext& ctx);
void GetFirmwareVersion2(HLERequestContext& ctx);
void GetLockScreenFlag(HLERequestContext& ctx);
void SetLockScreenFlag(HLERequestContext& ctx);
void GetExternalSteadyClockSourceId(HLERequestContext& ctx);
void SetExternalSteadyClockSourceId(HLERequestContext& ctx);
void GetUserSystemClockContext(HLERequestContext& ctx);
@ -108,13 +104,19 @@ private:
void IsUserSystemClockAutomaticCorrectionEnabled(HLERequestContext& ctx);
void SetUserSystemClockAutomaticCorrectionEnabled(HLERequestContext& ctx);
void GetPrimaryAlbumStorage(HLERequestContext& ctx);
void GetNfcEnableFlag(HLERequestContext& ctx);
void SetNfcEnableFlag(HLERequestContext& ctx);
void GetSleepSettings(HLERequestContext& ctx);
void SetSleepSettings(HLERequestContext& ctx);
void GetWirelessLanEnableFlag(HLERequestContext& ctx);
void SetWirelessLanEnableFlag(HLERequestContext& ctx);
void GetInitialLaunchSettings(HLERequestContext& ctx);
void SetInitialLaunchSettings(HLERequestContext& ctx);
void GetDeviceNickName(HLERequestContext& ctx);
void SetDeviceNickName(HLERequestContext& ctx);
void GetProductModel(HLERequestContext& ctx);
void GetBluetoothEnableFlag(HLERequestContext& ctx);
void SetBluetoothEnableFlag(HLERequestContext& ctx);
void GetMiiAuthorId(HLERequestContext& ctx);
void GetAutoUpdateEnableFlag(HLERequestContext& ctx);
void GetBatteryPercentageFlag(HLERequestContext& ctx);

View File

@ -91,6 +91,10 @@ void Display::CreateLayer(u64 layer_id, u32 binder_id,
layers.emplace_back(std::make_unique<Layer>(layer_id, binder_id, *core, *producer,
std::move(buffer_item_consumer)));
if (is_abandoned) {
this->FindLayer(layer_id)->GetConsumer().Abandon();
}
hos_binder_driver_server.RegisterProducer(std::move(producer));
}
@ -103,6 +107,13 @@ void Display::DestroyLayer(u64 layer_id) {
[layer_id](const auto& layer) { return layer->GetLayerId() == layer_id; });
}
void Display::Abandon() {
for (auto& layer : layers) {
layer->GetConsumer().Abandon();
}
is_abandoned = true;
}
Layer* Display::FindLayer(u64 layer_id) {
const auto itr =
std::find_if(layers.begin(), layers.end(), [layer_id](const std::unique_ptr<Layer>& layer) {

View File

@ -98,6 +98,8 @@ public:
layers.clear();
}
void Abandon();
/// Attempts to find a layer with the given ID.
///
/// @param layer_id The layer ID.
@ -124,6 +126,7 @@ private:
std::vector<std::unique_ptr<Layer>> layers;
Kernel::KEvent* vsync_event{};
bool is_abandoned{};
};
} // namespace Service::VI

View File

@ -4,6 +4,7 @@
#pragma once
#include <memory>
#include <utility>
#include "common/common_types.h"
@ -75,12 +76,12 @@ public:
return open;
}
void Close() {
open = false;
bool Close() {
return std::exchange(open, false);
}
void Open() {
open = true;
bool Open() {
return !std::exchange(open, true);
}
private:

View File

@ -719,7 +719,12 @@ private:
return;
}
nvnflinger.OpenLayer(layer_id);
if (!nvnflinger.OpenLayer(layer_id)) {
LOG_WARNING(Service_VI, "Tried to open layer which was already open");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultOperationFailed);
return;
}
android::OutputParcel parcel;
parcel.WriteInterface(NativeWindow{*buffer_queue_id});
@ -737,7 +742,12 @@ private:
LOG_DEBUG(Service_VI, "called. layer_id=0x{:016X}", layer_id);
nvnflinger.CloseLayer(layer_id);
if (!nvnflinger.CloseLayer(layer_id)) {
LOG_WARNING(Service_VI, "Tried to close layer which was not open");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultOperationFailed);
return;
}
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);

View File

@ -110,6 +110,7 @@ void EmulatedController::ReloadFromSettings() {
original_npad_type = npad_type;
}
SetPollingMode(EmulatedDeviceIndex::RightIndex, Common::Input::PollingMode::Active);
Disconnect();
if (player.connected) {
Connect();
@ -144,8 +145,8 @@ void EmulatedController::ReloadColorsFromSettings() {
void EmulatedController::LoadDevices() {
// TODO(german77): Use more buttons to detect the correct device
const auto left_joycon = button_params[Settings::NativeButton::DRight];
const auto right_joycon = button_params[Settings::NativeButton::A];
const auto& left_joycon = button_params[Settings::NativeButton::DRight];
const auto& right_joycon = button_params[Settings::NativeButton::A];
// Triggers for GC controllers
trigger_params[LeftIndex] = button_params[Settings::NativeButton::ZL];
@ -1208,20 +1209,43 @@ void EmulatedController::SetNfc(const Common::Input::CallbackStatus& callback) {
controller.nfc_state = controller.nfc_values;
}
bool EmulatedController::SetVibration(std::size_t device_index, VibrationValue vibration) {
bool EmulatedController::SetVibration(bool should_vibrate) {
VibrationValue vibration_value = DEFAULT_VIBRATION_VALUE;
if (should_vibrate) {
vibration_value.high_amplitude = 1.0f;
vibration_value.low_amplitude = 1.0f;
}
return SetVibration(DeviceIndex::Left, vibration_value);
}
bool EmulatedController::SetVibration(u32 slot, Core::HID::VibrationGcErmCommand erm_command) {
VibrationValue vibration_value = DEFAULT_VIBRATION_VALUE;
if (erm_command == Core::HID::VibrationGcErmCommand::Start) {
vibration_value.high_amplitude = 1.0f;
vibration_value.low_amplitude = 1.0f;
}
return SetVibration(DeviceIndex::Left, vibration_value);
}
bool EmulatedController::SetVibration(DeviceIndex device_index, const VibrationValue& vibration) {
if (!is_initialized) {
return false;
}
if (device_index >= output_devices.size()) {
if (device_index >= DeviceIndex::MaxDeviceIndex) {
return false;
}
if (!output_devices[device_index]) {
const std::size_t index = static_cast<std::size_t>(device_index);
if (!output_devices[index]) {
return false;
}
const auto player_index = Service::HID::NpadIdTypeToIndex(npad_id_type);
const auto& player = Settings::values.players.GetValue()[player_index];
const f32 strength = static_cast<f32>(player.vibration_strength) / 100.0f;
last_vibration_value = vibration;
if (!player.vibration_enabled) {
return false;
}
@ -1239,8 +1263,11 @@ bool EmulatedController::SetVibration(std::size_t device_index, VibrationValue v
.high_frequency = vibration.high_frequency,
.type = type,
};
return output_devices[device_index]->SetVibration(status) ==
Common::Input::DriverResult::Success;
return output_devices[index]->SetVibration(status) == Common::Input::DriverResult::Success;
}
VibrationValue EmulatedController::GetActualVibrationValue(DeviceIndex device_index) const {
return last_vibration_value;
}
bool EmulatedController::IsVibrationEnabled(std::size_t device_index) {

View File

@ -355,11 +355,28 @@ public:
/// Returns the latest ntag status from the controller
const NfcState& GetNfc() const;
/**
* Sends an on/off vibration to the left device
* @return true if vibration had no errors
*/
bool SetVibration(bool should_vibrate);
/**
* Sends an GC vibration to the left device
* @return true if vibration had no errors
*/
bool SetVibration(u32 slot, Core::HID::VibrationGcErmCommand erm_command);
/**
* Sends a specific vibration to the output device
* @return true if vibration had no errors
*/
bool SetVibration(std::size_t device_index, VibrationValue vibration);
bool SetVibration(DeviceIndex device_index, const VibrationValue& vibration);
/**
* @return The last sent vibration
*/
VibrationValue GetActualVibrationValue(DeviceIndex device_index) const;
/**
* Sends a small vibration to the output device
@ -564,6 +581,7 @@ private:
f32 motion_sensitivity{Core::HID::MotionInput::IsAtRestStandard};
u32 turbo_button_state{0};
std::size_t nfc_handles{0};
VibrationValue last_vibration_value{DEFAULT_VIBRATION_VALUE};
// Temporary values to avoid doing changes while the controller is in configuring mode
NpadStyleIndex tmp_npad_type{NpadStyleIndex::None};

View File

@ -7,6 +7,7 @@
#include "core/hle/kernel/k_shared_memory.h"
#include "core/hle/service/ipc_helpers.h"
#include "hid_core/hid_core.h"
#include "hid_core/hid_util.h"
#include "hid_core/resource_manager.h"
#include "hid_core/resources/applet_resource.h"
@ -27,6 +28,10 @@
#include "hid_core/resources/touch_screen/gesture.h"
#include "hid_core/resources/touch_screen/touch_screen.h"
#include "hid_core/resources/unique_pad/unique_pad.h"
#include "hid_core/resources/vibration/gc_vibration_device.h"
#include "hid_core/resources/vibration/n64_vibration_device.h"
#include "hid_core/resources/vibration/vibration_base.h"
#include "hid_core/resources/vibration/vibration_device.h"
namespace Service::HID {
@ -52,6 +57,7 @@ void ResourceManager::Initialize() {
system.HIDCore().ReloadInputDevices();
handheld_config = std::make_shared<HandheldConfig>();
InitializeHidCommonSampler();
InitializeTouchScreenSampler();
InitializeConsoleSixAxisSampler();
@ -174,7 +180,7 @@ void ResourceManager::InitializeHidCommonSampler() {
debug_pad->SetAppletResource(applet_resource, &shared_mutex);
digitizer->SetAppletResource(applet_resource, &shared_mutex);
keyboard->SetAppletResource(applet_resource, &shared_mutex);
npad->SetNpadExternals(applet_resource, &shared_mutex);
npad->SetNpadExternals(applet_resource, &shared_mutex, handheld_config);
six_axis->SetAppletResource(applet_resource, &shared_mutex);
mouse->SetAppletResource(applet_resource, &shared_mutex);
debug_mouse->SetAppletResource(applet_resource, &shared_mutex);
@ -257,6 +263,121 @@ void ResourceManager::EnableTouchScreen(u64 aruid, bool is_enabled) {
applet_resource->EnableTouchScreen(aruid, is_enabled);
}
NpadVibrationBase* ResourceManager::GetVibrationDevice(
const Core::HID::VibrationDeviceHandle& handle) {
return npad->GetVibrationDevice(handle);
}
NpadN64VibrationDevice* ResourceManager::GetN64VibrationDevice(
const Core::HID::VibrationDeviceHandle& handle) {
return npad->GetN64VibrationDevice(handle);
}
NpadVibrationDevice* ResourceManager::GetNSVibrationDevice(
const Core::HID::VibrationDeviceHandle& handle) {
return npad->GetNSVibrationDevice(handle);
}
NpadGcVibrationDevice* ResourceManager::GetGcVibrationDevice(
const Core::HID::VibrationDeviceHandle& handle) {
return npad->GetGcVibrationDevice(handle);
}
Result ResourceManager::SetAruidValidForVibration(u64 aruid, bool is_enabled) {
std::scoped_lock lock{shared_mutex};
const bool has_changed = applet_resource->SetAruidValidForVibration(aruid, is_enabled);
if (has_changed) {
auto devices = npad->GetAllVibrationDevices();
for ([[maybe_unused]] auto* device : devices) {
// TODO
}
}
auto* vibration_handler = npad->GetVibrationHandler();
if (aruid != vibration_handler->GetSessionAruid()) {
vibration_handler->EndPermitVibrationSession();
}
return ResultSuccess;
}
void ResourceManager::SetForceHandheldStyleVibration(bool is_forced) {
handheld_config->is_force_handheld_style_vibration = is_forced;
}
Result ResourceManager::IsVibrationAruidActive(u64 aruid, bool& is_active) const {
std::scoped_lock lock{shared_mutex};
is_active = applet_resource->IsVibrationAruidActive(aruid);
return ResultSuccess;
}
Result ResourceManager::GetVibrationDeviceInfo(Core::HID::VibrationDeviceInfo& device_info,
const Core::HID::VibrationDeviceHandle& handle) {
bool check_device_index = false;
const Result is_valid = IsVibrationHandleValid(handle);
if (is_valid.IsError()) {
return is_valid;
}
switch (handle.npad_type) {
case Core::HID::NpadStyleIndex::Fullkey:
case Core::HID::NpadStyleIndex::Handheld:
case Core::HID::NpadStyleIndex::JoyconDual:
case Core::HID::NpadStyleIndex::JoyconLeft:
case Core::HID::NpadStyleIndex::JoyconRight:
device_info.type = Core::HID::VibrationDeviceType::LinearResonantActuator;
check_device_index = true;
break;
case Core::HID::NpadStyleIndex::GameCube:
device_info.type = Core::HID::VibrationDeviceType::GcErm;
break;
case Core::HID::NpadStyleIndex::N64:
device_info.type = Core::HID::VibrationDeviceType::N64;
break;
default:
device_info.type = Core::HID::VibrationDeviceType::Unknown;
break;
}
device_info.position = Core::HID::VibrationDevicePosition::None;
if (check_device_index) {
switch (handle.device_index) {
case Core::HID::DeviceIndex::Left:
device_info.position = Core::HID::VibrationDevicePosition::Left;
break;
case Core::HID::DeviceIndex::Right:
device_info.position = Core::HID::VibrationDevicePosition::Right;
break;
case Core::HID::DeviceIndex::None:
default:
ASSERT_MSG(false, "DeviceIndex should never be None!");
break;
}
}
return ResultSuccess;
}
Result ResourceManager::SendVibrationValue(u64 aruid,
const Core::HID::VibrationDeviceHandle& handle,
const Core::HID::VibrationValue& value) {
bool has_active_aruid{};
NpadVibrationDevice* device{nullptr};
Result result = IsVibrationAruidActive(aruid, has_active_aruid);
if (result.IsSuccess() && has_active_aruid) {
result = IsVibrationHandleValid(handle);
}
if (result.IsSuccess() && has_active_aruid) {
device = GetNSVibrationDevice(handle);
}
if (device != nullptr) {
result = device->SendVibrationValue(value);
}
return result;
}
void ResourceManager::UpdateControllers(std::chrono::nanoseconds ns_late) {
auto& core_timing = system.CoreTiming();
debug_pad->OnUpdate(core_timing);

View File

@ -10,6 +10,12 @@ namespace Core {
class System;
}
namespace Core::HID {
struct VibrationDeviceHandle;
struct VibrationValue;
struct VibrationDeviceInfo;
} // namespace Core::HID
namespace Core::Timing {
struct EventType;
}
@ -37,6 +43,11 @@ class SixAxis;
class SleepButton;
class TouchScreen;
class UniquePad;
class NpadVibrationBase;
class NpadN64VibrationDevice;
class NpadGcVibrationDevice;
class NpadVibrationDevice;
struct HandheldConfig;
class ResourceManager {
@ -79,6 +90,18 @@ public:
void EnablePadInput(u64 aruid, bool is_enabled);
void EnableTouchScreen(u64 aruid, bool is_enabled);
NpadVibrationBase* GetVibrationDevice(const Core::HID::VibrationDeviceHandle& handle);
NpadN64VibrationDevice* GetN64VibrationDevice(const Core::HID::VibrationDeviceHandle& handle);
NpadVibrationDevice* GetNSVibrationDevice(const Core::HID::VibrationDeviceHandle& handle);
NpadGcVibrationDevice* GetGcVibrationDevice(const Core::HID::VibrationDeviceHandle& handle);
Result SetAruidValidForVibration(u64 aruid, bool is_enabled);
void SetForceHandheldStyleVibration(bool is_forced);
Result IsVibrationAruidActive(u64 aruid, bool& is_active) const;
Result GetVibrationDeviceInfo(Core::HID::VibrationDeviceInfo& device_info,
const Core::HID::VibrationDeviceHandle& handle);
Result SendVibrationValue(u64 aruid, const Core::HID::VibrationDeviceHandle& handle,
const Core::HID::VibrationValue& value);
void UpdateControllers(std::chrono::nanoseconds ns_late);
void UpdateNpad(std::chrono::nanoseconds ns_late);
void UpdateMouseKeyboard(std::chrono::nanoseconds ns_late);
@ -113,6 +136,8 @@ private:
std::shared_ptr<TouchScreen> touch_screen = nullptr;
std::shared_ptr<UniquePad> unique_pad = nullptr;
std::shared_ptr<HandheldConfig> handheld_config = nullptr;
// TODO: Create these resources
// std::shared_ptr<AudioControl> audio_control = nullptr;
// std::shared_ptr<ButtonConfig> button_config = nullptr;

View File

@ -115,7 +115,7 @@ Result NpadAbstractIrSensorHandler::GetXcdHandleForNpadWithIrSensor(u64& handle)
if (sensor_state < NpadIrSensorState::Available) {
return ResultIrSensorIsNotReady;
}
handle = xcd_handle;
// handle = xcd_handle;
return ResultSuccess;
}

View File

@ -7,6 +7,10 @@
#include "core/hle/result.h"
#include "hid_core/hid_types.h"
namespace Core::HID {
class EmulatedController;
}
namespace Kernel {
class KEvent;
class KReadableEvent;
@ -50,7 +54,7 @@ private:
s32 ref_counter{};
Kernel::KEvent* ir_sensor_event{nullptr};
u64 xcd_handle{};
Core::HID::EmulatedController* xcd_handle{};
NpadIrSensorState sensor_state{};
};
} // namespace Service::HID

View File

@ -1,6 +1,7 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
#include "hid_core/hid_core.h"
#include "hid_core/hid_result.h"
#include "hid_core/resources/abstracted_pad/abstract_pad.h"
#include "hid_core/resources/applet_resource.h"
@ -16,7 +17,7 @@ void AbstractPad::SetExternals(AppletResourceHolder* applet_resource,
CaptureButtonResource* capture_button_resource,
HomeButtonResource* home_button_resource,
SixAxisResource* sixaxis_resource, PalmaResource* palma_resource,
VibrationHandler* vibration) {
NpadVibration* vibration, Core::HID::HIDCore* core) {
applet_resource_holder = applet_resource;
properties_handler.SetAppletResource(applet_resource_holder);
@ -35,13 +36,14 @@ void AbstractPad::SetExternals(AppletResourceHolder* applet_resource,
mcu_handler.SetAbstractPadHolder(&abstract_pad_holder);
mcu_handler.SetPropertiesHandler(&properties_handler);
std::array<NpadVibrationDevice*, 2> vibration_devices{&vibration_left, &vibration_right};
vibration_handler.SetAppletResource(applet_resource_holder);
vibration_handler.SetAbstractPadHolder(&abstract_pad_holder);
vibration_handler.SetPropertiesHandler(&properties_handler);
vibration_handler.SetN64Vibration(&vibration_n64);
vibration_handler.SetVibration(vibration_devices);
vibration_handler.SetVibration(&vibration_left, &vibration_right);
vibration_handler.SetGcVibration(&vibration_gc);
vibration_handler.SetVibrationHandler(vibration);
vibration_handler.SetHidCore(core);
sixaxis_handler.SetAppletResource(applet_resource_holder);
sixaxis_handler.SetAbstractPadHolder(&abstract_pad_holder);
@ -239,11 +241,6 @@ NpadVibrationDevice* AbstractPad::GetVibrationDevice(Core::HID::DeviceIndex devi
return &vibration_left;
}
void AbstractPad::GetLeftRightVibrationDevice(std::vector<NpadVibrationDevice*> list) {
list.emplace_back(&vibration_left);
list.emplace_back(&vibration_right);
}
NpadGcVibrationDevice* AbstractPad::GetGCVibrationDevice() {
return &vibration_gc;
}

View File

@ -32,7 +32,6 @@ class AppletResource;
class SixAxisResource;
class PalmaResource;
class NPadResource;
class AbstractPad;
class NpadLastActiveHandler;
class NpadIrNfcHandler;
class UniquePads;
@ -44,7 +43,6 @@ class NpadGcVibration;
class CaptureButtonResource;
class HomeButtonResource;
class VibrationHandler;
struct HandheldConfig;
@ -57,7 +55,8 @@ public:
void SetExternals(AppletResourceHolder* applet_resource,
CaptureButtonResource* capture_button_resource,
HomeButtonResource* home_button_resource, SixAxisResource* sixaxis_resource,
PalmaResource* palma_resource, VibrationHandler* vibration);
PalmaResource* palma_resource, NpadVibration* vibration,
Core::HID::HIDCore* core);
void SetNpadId(Core::HID::NpadIdType npad_id);
Result Activate();
@ -78,7 +77,6 @@ public:
NpadN64VibrationDevice* GetN64VibrationDevice();
NpadVibrationDevice* GetVibrationDevice(Core::HID::DeviceIndex device_index);
void GetLeftRightVibrationDevice(std::vector<NpadVibrationDevice*> list);
NpadGcVibrationDevice* GetGCVibrationDevice();
Core::HID::NpadIdType GetLastActiveNpad();

View File

@ -1,6 +1,8 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
#include "hid_core/frontend/emulated_controller.h"
#include "hid_core/hid_core.h"
#include "hid_core/hid_result.h"
#include "hid_core/hid_util.h"
#include "hid_core/resources/abstracted_pad/abstract_pad_holder.h"
@ -30,14 +32,22 @@ void NpadAbstractVibrationHandler::SetPropertiesHandler(NpadAbstractPropertiesHa
properties_handler = handler;
}
void NpadAbstractVibrationHandler::SetVibrationHandler(NpadVibration* handler) {
vibration_handler = handler;
}
void NpadAbstractVibrationHandler::SetHidCore(Core::HID::HIDCore* core) {
hid_core = core;
}
void NpadAbstractVibrationHandler::SetN64Vibration(NpadN64VibrationDevice* n64_device) {
n64_vibration_device = n64_device;
}
void NpadAbstractVibrationHandler::SetVibration(std::span<NpadVibrationDevice*> device) {
for (std::size_t i = 0; i < device.size() && i < vibration_device.size(); i++) {
vibration_device[i] = device[i];
}
void NpadAbstractVibrationHandler::SetVibration(NpadVibrationDevice* left_device,
NpadVibrationDevice* right_device) {
left_vibration_device = left_device;
right_vibration_device = right_device;
}
void NpadAbstractVibrationHandler::SetGcVibration(NpadGcVibrationDevice* gc_device) {
@ -69,5 +79,29 @@ void NpadAbstractVibrationHandler::UpdateVibrationState() {
if (!is_handheld_hid_enabled && is_force_handheld_style_vibration) {
// TODO
}
// TODO: This function isn't accurate. It's supposed to get 5 abstracted pads from the
// NpadAbstractPropertiesHandler but this handler isn't fully implemented yet
IAbstractedPad abstracted_pad{};
const auto npad_id = properties_handler->GetNpadId();
abstracted_pad.xcd_handle = hid_core->GetEmulatedController(npad_id);
abstracted_pad.internal_flags.is_connected.Assign(abstracted_pad.xcd_handle->IsConnected());
if (abstracted_pad.internal_flags.is_connected) {
left_vibration_device->Mount(abstracted_pad, Core::HID::DeviceIndex::Left,
vibration_handler);
right_vibration_device->Mount(abstracted_pad, Core::HID::DeviceIndex::Right,
vibration_handler);
gc_vibration_device->Mount(abstracted_pad, 0, vibration_handler);
gc_vibration_device->Mount(abstracted_pad, 0, vibration_handler);
n64_vibration_device->Mount(abstracted_pad, vibration_handler);
return;
}
left_vibration_device->Unmount();
right_vibration_device->Unmount();
gc_vibration_device->Unmount();
gc_vibration_device->Unmount();
n64_vibration_device->Unmount();
}
} // namespace Service::HID

View File

@ -9,6 +9,10 @@
#include "core/hle/result.h"
#include "hid_core/hid_types.h"
namespace Core::HID {
class HIDCore;
}
namespace Service::HID {
struct AppletResourceHolder;
class NpadAbstractedPadHolder;
@ -27,9 +31,11 @@ public:
void SetAbstractPadHolder(NpadAbstractedPadHolder* holder);
void SetAppletResource(AppletResourceHolder* applet_resource);
void SetPropertiesHandler(NpadAbstractPropertiesHandler* handler);
void SetVibrationHandler(NpadVibration* handler);
void SetHidCore(Core::HID::HIDCore* core);
void SetN64Vibration(NpadN64VibrationDevice* n64_device);
void SetVibration(std::span<NpadVibrationDevice*> device);
void SetVibration(NpadVibrationDevice* left_device, NpadVibrationDevice* right_device);
void SetGcVibration(NpadGcVibrationDevice* gc_device);
Result IncrementRefCounter();
@ -41,9 +47,11 @@ private:
AppletResourceHolder* applet_resource_holder{nullptr};
NpadAbstractedPadHolder* abstract_pad_holder{nullptr};
NpadAbstractPropertiesHandler* properties_handler{nullptr};
Core::HID::HIDCore* hid_core{nullptr};
NpadN64VibrationDevice* n64_vibration_device{nullptr};
std::array<NpadVibrationDevice*, 2> vibration_device{};
NpadVibrationDevice* left_vibration_device{};
NpadVibrationDevice* right_vibration_device{};
NpadGcVibrationDevice* gc_vibration_device{nullptr};
NpadVibration* vibration_handler{nullptr};
s32 ref_counter{};

View File

@ -200,6 +200,25 @@ void AppletResource::EnableInput(u64 aruid, bool is_enabled) {
data[index].flag.enable_touchscreen.Assign(is_enabled);
}
bool AppletResource::SetAruidValidForVibration(u64 aruid, bool is_enabled) {
const u64 index = GetIndexFromAruid(aruid);
if (index >= AruidIndexMax) {
return false;
}
if (!is_enabled && aruid == active_vibration_aruid) {
active_vibration_aruid = SystemAruid;
return true;
}
if (is_enabled && aruid != active_vibration_aruid) {
active_vibration_aruid = aruid;
return true;
}
return false;
}
void AppletResource::EnableSixAxisSensor(u64 aruid, bool is_enabled) {
const u64 index = GetIndexFromAruid(aruid);
if (index >= AruidIndexMax) {

View File

@ -101,6 +101,7 @@ public:
Result DestroySevenSixAxisTransferMemory();
void EnableInput(u64 aruid, bool is_enabled);
bool SetAruidValidForVibration(u64 aruid, bool is_enabled);
void EnableSixAxisSensor(u64 aruid, bool is_enabled);
void EnablePadInput(u64 aruid, bool is_enabled);
void EnableTouchScreen(u64 aruid, bool is_enabled);

View File

@ -1,11 +1,14 @@
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
#include "core/hle/service/set/system_settings_server.h"
#include "core/hle/service/sm/sm.h"
#include "hid_core/resources/hid_firmware_settings.h"
namespace Service::HID {
HidFirmwareSettings::HidFirmwareSettings() {
HidFirmwareSettings::HidFirmwareSettings(Core::System& system) {
m_set_sys = system.ServiceManager().GetService<Service::Set::ISystemSettingsServer>("set:sys");
LoadSettings(true);
}
@ -18,21 +21,25 @@ void HidFirmwareSettings::LoadSettings(bool reload_config) {
return;
}
// TODO: Use nn::settings::fwdbg::GetSettingsItemValue to load config values
is_debug_pad_enabled = true;
is_device_managed = true;
is_touch_i2c_managed = is_device_managed;
is_future_devices_emulated = false;
is_mcu_hardware_error_emulated = false;
is_rail_enabled = true;
is_firmware_update_failure_emulated = false;
m_set_sys->GetSettingsItemValue<bool>(is_debug_pad_enabled, "hid_debug", "enables_debugpad");
m_set_sys->GetSettingsItemValue<bool>(is_device_managed, "hid_debug", "manages_devices");
m_set_sys->GetSettingsItemValue<bool>(is_touch_i2c_managed, "hid_debug",
"manages_touch_ic_i2c");
m_set_sys->GetSettingsItemValue<bool>(is_future_devices_emulated, "hid_debug",
"emulate_future_device");
m_set_sys->GetSettingsItemValue<bool>(is_mcu_hardware_error_emulated, "hid_debug",
"emulate_mcu_hardware_error");
m_set_sys->GetSettingsItemValue<bool>(is_rail_enabled, "hid_debug", "enables_rail");
m_set_sys->GetSettingsItemValue<bool>(is_firmware_update_failure_emulated, "hid_debug",
"emulate_firmware_update_failure");
is_firmware_update_failure = {};
is_ble_disabled = false;
is_dscale_disabled = false;
is_handheld_forced = true;
m_set_sys->GetSettingsItemValue<bool>(is_ble_disabled, "hid_debug", "ble_disabled");
m_set_sys->GetSettingsItemValue<bool>(is_dscale_disabled, "hid_debug", "dscale_disabled");
m_set_sys->GetSettingsItemValue<bool>(is_handheld_forced, "hid_debug", "force_handheld");
features_per_id_disabled = {};
is_touch_firmware_auto_update_disabled = false;
m_set_sys->GetSettingsItemValue<bool>(is_touch_firmware_auto_update_disabled, "hid_debug",
"touch_firmware_auto_update_disabled");
is_initialized = true;
}

View File

@ -5,6 +5,14 @@
#include "common/common_types.h"
namespace Core {
class System;
}
namespace Service::Set {
class ISystemSettingsServer;
}
namespace Service::HID {
/// Loads firmware config from nn::settings::fwdbg
@ -13,7 +21,7 @@ public:
using FirmwareSetting = std::array<u8, 4>;
using FeaturesPerId = std::array<bool, 0xA8>;
HidFirmwareSettings();
HidFirmwareSettings(Core::System& system);
void Reload();
void LoadSettings(bool reload_config);
@ -49,6 +57,8 @@ private:
bool is_touch_firmware_auto_update_disabled{};
FirmwareSetting is_firmware_update_failure{};
FeaturesPerId features_per_id_disabled{};
std::shared_ptr<Service::Set::ISystemSettingsServer> m_set_sys;
};
} // namespace Service::HID

View File

@ -21,6 +21,7 @@
#include "hid_core/hid_util.h"
#include "hid_core/resources/applet_resource.h"
#include "hid_core/resources/npad/npad.h"
#include "hid_core/resources/npad/npad_vibration.h"
#include "hid_core/resources/shared_memory_format.h"
namespace Service::HID {
@ -31,10 +32,6 @@ NPad::NPad(Core::HID::HIDCore& hid_core_, KernelHelpers::ServiceContext& service
for (std::size_t i = 0; i < controller_data[aruid_index].size(); ++i) {
auto& controller = controller_data[aruid_index][i];
controller.device = hid_core.GetEmulatedControllerByIndex(i);
controller.vibration[Core::HID::EmulatedDeviceIndex::LeftIndex].latest_vibration_value =
Core::HID::DEFAULT_VIBRATION_VALUE;
controller.vibration[Core::HID::EmulatedDeviceIndex::RightIndex]
.latest_vibration_value = Core::HID::DEFAULT_VIBRATION_VALUE;
Core::HID::ControllerUpdateCallback engine_callback{
.on_change =
[this, i](Core::HID::ControllerTriggerType type) { ControllerUpdate(type, i); },
@ -43,6 +40,10 @@ NPad::NPad(Core::HID::HIDCore& hid_core_, KernelHelpers::ServiceContext& service
controller.callback_key = controller.device->SetCallback(engine_callback);
}
}
for (std::size_t i = 0; i < abstracted_pads.size(); ++i) {
abstracted_pads[i] = AbstractPad{};
abstracted_pads[i].SetNpadId(IndexToNpadIdType(i));
}
}
NPad::~NPad() {
@ -359,6 +360,7 @@ void NPad::InitNewlyAddedController(u64 aruid, Core::HID::NpadIdType npad_id) {
npad_resource.SignalStyleSetUpdateEvent(aruid, npad_id);
WriteEmptyEntry(controller.shared_memory);
hid_core.SetLastActiveController(npad_id);
abstracted_pads[NpadIdTypeToIndex(npad_id)].Update();
}
void NPad::WriteEmptyEntry(NpadInternalState* npad) {
@ -740,171 +742,6 @@ bool NPad::SetNpadMode(u64 aruid, Core::HID::NpadIdType& new_npad_id, Core::HID:
return true;
}
bool NPad::VibrateControllerAtIndex(u64 aruid, Core::HID::NpadIdType npad_id,
std::size_t device_index,
const Core::HID::VibrationValue& vibration_value) {
auto& controller = GetControllerFromNpadIdType(aruid, npad_id);
if (!controller.device->IsConnected()) {
return false;
}
if (!controller.device->IsVibrationEnabled(device_index)) {
if (controller.vibration[device_index].latest_vibration_value.low_amplitude != 0.0f ||
controller.vibration[device_index].latest_vibration_value.high_amplitude != 0.0f) {
// Send an empty vibration to stop any vibrations.
Core::HID::VibrationValue vibration{0.0f, 160.0f, 0.0f, 320.0f};
controller.device->SetVibration(device_index, vibration);
// Then reset the vibration value to its default value.
controller.vibration[device_index].latest_vibration_value =
Core::HID::DEFAULT_VIBRATION_VALUE;
}
return false;
}
if (!Settings::values.enable_accurate_vibrations.GetValue()) {
using std::chrono::duration_cast;
using std::chrono::milliseconds;
using std::chrono::steady_clock;
const auto now = steady_clock::now();
// Filter out non-zero vibrations that are within 15ms of each other.
if ((vibration_value.low_amplitude != 0.0f || vibration_value.high_amplitude != 0.0f) &&
duration_cast<milliseconds>(
now - controller.vibration[device_index].last_vibration_timepoint) <
milliseconds(15)) {
return false;
}
controller.vibration[device_index].last_vibration_timepoint = now;
}
Core::HID::VibrationValue vibration{
vibration_value.low_amplitude, vibration_value.low_frequency,
vibration_value.high_amplitude, vibration_value.high_frequency};
return controller.device->SetVibration(device_index, vibration);
}
void NPad::VibrateController(u64 aruid,
const Core::HID::VibrationDeviceHandle& vibration_device_handle,
const Core::HID::VibrationValue& vibration_value) {
if (IsVibrationHandleValid(vibration_device_handle).IsError()) {
return;
}
if (!Settings::values.vibration_enabled.GetValue() && !permit_vibration_session_enabled) {
return;
}
auto& controller = GetControllerFromHandle(aruid, vibration_device_handle);
const auto device_index = static_cast<std::size_t>(vibration_device_handle.device_index);
if (!controller.vibration[device_index].device_mounted || !controller.device->IsConnected()) {
return;
}
if (vibration_device_handle.device_index == Core::HID::DeviceIndex::None) {
ASSERT_MSG(false, "DeviceIndex should never be None!");
return;
}
// Some games try to send mismatched parameters in the device handle, block these.
if ((controller.device->GetNpadStyleIndex() == Core::HID::NpadStyleIndex::JoyconLeft &&
(vibration_device_handle.npad_type == Core::HID::NpadStyleIndex::JoyconRight ||
vibration_device_handle.device_index == Core::HID::DeviceIndex::Right)) ||
(controller.device->GetNpadStyleIndex() == Core::HID::NpadStyleIndex::JoyconRight &&
(vibration_device_handle.npad_type == Core::HID::NpadStyleIndex::JoyconLeft ||
vibration_device_handle.device_index == Core::HID::DeviceIndex::Left))) {
return;
}
// Filter out vibrations with equivalent values to reduce unnecessary state changes.
if (vibration_value.low_amplitude ==
controller.vibration[device_index].latest_vibration_value.low_amplitude &&
vibration_value.high_amplitude ==
controller.vibration[device_index].latest_vibration_value.high_amplitude) {
return;
}
if (VibrateControllerAtIndex(aruid, controller.device->GetNpadIdType(), device_index,
vibration_value)) {
controller.vibration[device_index].latest_vibration_value = vibration_value;
}
}
void NPad::VibrateControllers(
u64 aruid, std::span<const Core::HID::VibrationDeviceHandle> vibration_device_handles,
std::span<const Core::HID::VibrationValue> vibration_values) {
if (!Settings::values.vibration_enabled.GetValue() && !permit_vibration_session_enabled) {
return;
}
ASSERT_OR_EXECUTE_MSG(
vibration_device_handles.size() == vibration_values.size(), { return; },
"The amount of device handles does not match with the amount of vibration values,"
"this is undefined behavior!");
for (std::size_t i = 0; i < vibration_device_handles.size(); ++i) {
VibrateController(aruid, vibration_device_handles[i], vibration_values[i]);
}
}
Core::HID::VibrationValue NPad::GetLastVibration(
u64 aruid, const Core::HID::VibrationDeviceHandle& vibration_device_handle) const {
if (IsVibrationHandleValid(vibration_device_handle).IsError()) {
return {};
}
const auto& controller = GetControllerFromHandle(aruid, vibration_device_handle);
const auto device_index = static_cast<std::size_t>(vibration_device_handle.device_index);
return controller.vibration[device_index].latest_vibration_value;
}
void NPad::InitializeVibrationDevice(
const Core::HID::VibrationDeviceHandle& vibration_device_handle) {
if (IsVibrationHandleValid(vibration_device_handle).IsError()) {
return;
}
const auto aruid = applet_resource_holder.applet_resource->GetActiveAruid();
const auto npad_index = static_cast<Core::HID::NpadIdType>(vibration_device_handle.npad_id);
const auto device_index = static_cast<std::size_t>(vibration_device_handle.device_index);
if (aruid == 0) {
return;
}
InitializeVibrationDeviceAtIndex(aruid, npad_index, device_index);
}
void NPad::InitializeVibrationDeviceAtIndex(u64 aruid, Core::HID::NpadIdType npad_id,
std::size_t device_index) {
auto& controller = GetControllerFromNpadIdType(aruid, npad_id);
if (!Settings::values.vibration_enabled.GetValue()) {
controller.vibration[device_index].device_mounted = false;
return;
}
controller.vibration[device_index].device_mounted =
controller.device->IsVibrationEnabled(device_index);
}
void NPad::SetPermitVibrationSession(bool permit_vibration_session) {
permit_vibration_session_enabled = permit_vibration_session;
}
bool NPad::IsVibrationDeviceMounted(
u64 aruid, const Core::HID::VibrationDeviceHandle& vibration_device_handle) const {
if (IsVibrationHandleValid(vibration_device_handle).IsError()) {
return false;
}
const auto& controller = GetControllerFromHandle(aruid, vibration_device_handle);
const auto device_index = static_cast<std::size_t>(vibration_device_handle.device_index);
return controller.vibration[device_index].device_mounted;
}
Result NPad::AcquireNpadStyleSetUpdateEventHandle(u64 aruid, Kernel::KReadableEvent** out_event,
Core::HID::NpadIdType npad_id) {
std::scoped_lock lock{mutex};
@ -936,11 +773,6 @@ Result NPad::DisconnectNpad(u64 aruid, Core::HID::NpadIdType npad_id) {
LOG_DEBUG(Service_HID, "Npad disconnected {}", npad_id);
auto& controller = GetControllerFromNpadIdType(aruid, npad_id);
for (std::size_t device_idx = 0; device_idx < controller.vibration.size(); ++device_idx) {
// Send an empty vibration to stop any vibrations.
VibrateControllerAtIndex(aruid, npad_id, device_idx, {});
controller.vibration[device_idx].device_mounted = false;
}
auto* shared_memory = controller.shared_memory;
// Don't reset shared_memory->assignment_mode this value is persistent
@ -1236,22 +1068,17 @@ void NPad::UnregisterAppletResourceUserId(u64 aruid) {
}
void NPad::SetNpadExternals(std::shared_ptr<AppletResource> resource,
std::recursive_mutex* shared_mutex) {
std::recursive_mutex* shared_mutex,
std::shared_ptr<HandheldConfig> handheld_config) {
applet_resource_holder.applet_resource = resource;
applet_resource_holder.shared_mutex = shared_mutex;
applet_resource_holder.shared_npad_resource = &npad_resource;
}
applet_resource_holder.handheld_config = handheld_config;
NPad::NpadControllerData& NPad::GetControllerFromHandle(
u64 aruid, const Core::HID::VibrationDeviceHandle& device_handle) {
const auto npad_id = static_cast<Core::HID::NpadIdType>(device_handle.npad_id);
return GetControllerFromNpadIdType(aruid, npad_id);
}
const NPad::NpadControllerData& NPad::GetControllerFromHandle(
u64 aruid, const Core::HID::VibrationDeviceHandle& device_handle) const {
const auto npad_id = static_cast<Core::HID::NpadIdType>(device_handle.npad_id);
return GetControllerFromNpadIdType(aruid, npad_id);
for (auto& abstract_pad : abstracted_pads) {
abstract_pad.SetExternals(&applet_resource_holder, nullptr, nullptr, nullptr, nullptr,
&vibration_handler, &hid_core);
}
}
NPad::NpadControllerData& NPad::GetControllerFromHandle(
@ -1389,4 +1216,97 @@ Result NPad::GetLastActiveNpad(Core::HID::NpadIdType& out_npad_id) const {
return ResultSuccess;
}
NpadVibration* NPad::GetVibrationHandler() {
return &vibration_handler;
}
std::vector<NpadVibrationBase*> NPad::GetAllVibrationDevices() {
std::vector<NpadVibrationBase*> vibration_devices;
for (auto& abstract_pad : abstracted_pads) {
auto* left_device = abstract_pad.GetVibrationDevice(Core::HID::DeviceIndex::Left);
auto* right_device = abstract_pad.GetVibrationDevice(Core::HID::DeviceIndex::Right);
auto* n64_device = abstract_pad.GetGCVibrationDevice();
auto* gc_device = abstract_pad.GetGCVibrationDevice();
if (left_device != nullptr) {
vibration_devices.emplace_back(left_device);
}
if (right_device != nullptr) {
vibration_devices.emplace_back(right_device);
}
if (n64_device != nullptr) {
vibration_devices.emplace_back(n64_device);
}
if (gc_device != nullptr) {
vibration_devices.emplace_back(gc_device);
}
}
return vibration_devices;
}
NpadVibrationBase* NPad::GetVibrationDevice(const Core::HID::VibrationDeviceHandle& handle) {
if (IsVibrationHandleValid(handle).IsError()) {
return nullptr;
}
const auto npad_index = NpadIdTypeToIndex(static_cast<Core::HID::NpadIdType>(handle.npad_id));
const auto style_inde = static_cast<Core::HID::NpadStyleIndex>(handle.npad_type);
if (style_inde == Core::HID::NpadStyleIndex::GameCube) {
return abstracted_pads[npad_index].GetGCVibrationDevice();
}
if (style_inde == Core::HID::NpadStyleIndex::N64) {
return abstracted_pads[npad_index].GetN64VibrationDevice();
}
return abstracted_pads[npad_index].GetVibrationDevice(handle.device_index);
}
NpadN64VibrationDevice* NPad::GetN64VibrationDevice(
const Core::HID::VibrationDeviceHandle& handle) {
if (IsVibrationHandleValid(handle).IsError()) {
return nullptr;
}
const auto npad_index = NpadIdTypeToIndex(static_cast<Core::HID::NpadIdType>(handle.npad_id));
const auto style_inde = static_cast<Core::HID::NpadStyleIndex>(handle.npad_type);
if (style_inde != Core::HID::NpadStyleIndex::N64) {
return nullptr;
}
return abstracted_pads[npad_index].GetN64VibrationDevice();
}
NpadVibrationDevice* NPad::GetNSVibrationDevice(const Core::HID::VibrationDeviceHandle& handle) {
if (IsVibrationHandleValid(handle).IsError()) {
return nullptr;
}
const auto npad_index = NpadIdTypeToIndex(static_cast<Core::HID::NpadIdType>(handle.npad_id));
const auto style_inde = static_cast<Core::HID::NpadStyleIndex>(handle.npad_type);
if (style_inde == Core::HID::NpadStyleIndex::GameCube ||
style_inde == Core::HID::NpadStyleIndex::N64) {
return nullptr;
}
return abstracted_pads[npad_index].GetVibrationDevice(handle.device_index);
}
NpadGcVibrationDevice* NPad::GetGcVibrationDevice(const Core::HID::VibrationDeviceHandle& handle) {
if (IsVibrationHandleValid(handle).IsError()) {
return nullptr;
}
const auto npad_index = NpadIdTypeToIndex(static_cast<Core::HID::NpadIdType>(handle.npad_id));
const auto style_inde = static_cast<Core::HID::NpadStyleIndex>(handle.npad_type);
if (style_inde != Core::HID::NpadStyleIndex::GameCube) {
return nullptr;
}
return abstracted_pads[npad_index].GetGCVibrationDevice();
}
void NPad::UpdateHandheldAbstractState() {
std::scoped_lock lock{mutex};
abstracted_pads[NpadIdTypeToIndex(Core::HID::NpadIdType::Handheld)].Update();
}
} // namespace Service::HID

View File

@ -10,9 +10,15 @@
#include "common/common_types.h"
#include "hid_core/hid_types.h"
#include "hid_core/resources/abstracted_pad/abstract_pad.h"
#include "hid_core/resources/controller_base.h"
#include "hid_core/resources/npad/npad_resource.h"
#include "hid_core/resources/npad/npad_types.h"
#include "hid_core/resources/npad/npad_vibration.h"
#include "hid_core/resources/vibration/gc_vibration_device.h"
#include "hid_core/resources/vibration/n64_vibration_device.h"
#include "hid_core/resources/vibration/vibration_base.h"
#include "hid_core/resources/vibration/vibration_device.h"
namespace Core::HID {
class EmulatedController;
@ -32,6 +38,7 @@ union Result;
namespace Service::HID {
class AppletResource;
struct HandheldConfig;
struct NpadInternalState;
struct NpadSixAxisSensorLifo;
struct NpadSharedMemoryFormat;
@ -68,31 +75,6 @@ public:
bool SetNpadMode(u64 aruid, Core::HID::NpadIdType& new_npad_id, Core::HID::NpadIdType npad_id,
NpadJoyDeviceType npad_device_type, NpadJoyAssignmentMode assignment_mode);
bool VibrateControllerAtIndex(u64 aruid, Core::HID::NpadIdType npad_id,
std::size_t device_index,
const Core::HID::VibrationValue& vibration_value);
void VibrateController(u64 aruid,
const Core::HID::VibrationDeviceHandle& vibration_device_handle,
const Core::HID::VibrationValue& vibration_value);
void VibrateControllers(
u64 aruid, std::span<const Core::HID::VibrationDeviceHandle> vibration_device_handles,
std::span<const Core::HID::VibrationValue> vibration_values);
Core::HID::VibrationValue GetLastVibration(
u64 aruid, const Core::HID::VibrationDeviceHandle& vibration_device_handle) const;
void InitializeVibrationDevice(const Core::HID::VibrationDeviceHandle& vibration_device_handle);
void InitializeVibrationDeviceAtIndex(u64 aruid, Core::HID::NpadIdType npad_id,
std::size_t device_index);
void SetPermitVibrationSession(bool permit_vibration_session);
bool IsVibrationDeviceMounted(
u64 aruid, const Core::HID::VibrationDeviceHandle& vibration_device_handle) const;
Result AcquireNpadStyleSetUpdateEventHandle(u64 aruid, Kernel::KReadableEvent** out_event,
Core::HID::NpadIdType npad_id);
@ -145,7 +127,8 @@ public:
Result RegisterAppletResourceUserId(u64 aruid);
void UnregisterAppletResourceUserId(u64 aruid);
void SetNpadExternals(std::shared_ptr<AppletResource> resource,
std::recursive_mutex* shared_mutex);
std::recursive_mutex* shared_mutex,
std::shared_ptr<HandheldConfig> handheld_config);
AppletDetailedUiType GetAppletDetailedUiType(Core::HID::NpadIdType npad_id);
@ -161,18 +144,20 @@ public:
Result GetLastActiveNpad(Core::HID::NpadIdType& out_npad_id) const;
private:
struct VibrationData {
bool device_mounted{};
Core::HID::VibrationValue latest_vibration_value{};
std::chrono::steady_clock::time_point last_vibration_timepoint{};
};
NpadVibration* GetVibrationHandler();
std::vector<NpadVibrationBase*> GetAllVibrationDevices();
NpadVibrationBase* GetVibrationDevice(const Core::HID::VibrationDeviceHandle& handle);
NpadN64VibrationDevice* GetN64VibrationDevice(const Core::HID::VibrationDeviceHandle& handle);
NpadVibrationDevice* GetNSVibrationDevice(const Core::HID::VibrationDeviceHandle& handle);
NpadGcVibrationDevice* GetGcVibrationDevice(const Core::HID::VibrationDeviceHandle& handle);
void UpdateHandheldAbstractState();
private:
struct NpadControllerData {
NpadInternalState* shared_memory = nullptr;
Core::HID::EmulatedController* device = nullptr;
std::array<VibrationData, 2> vibration{};
bool is_connected{};
// Dual joycons can have only one side connected
@ -191,10 +176,6 @@ private:
void RequestPadStateUpdate(u64 aruid, Core::HID::NpadIdType npad_id);
void WriteEmptyEntry(NpadInternalState* npad);
NpadControllerData& GetControllerFromHandle(
u64 aruid, const Core::HID::VibrationDeviceHandle& device_handle);
const NpadControllerData& GetControllerFromHandle(
u64 aruid, const Core::HID::VibrationDeviceHandle& device_handle) const;
NpadControllerData& GetControllerFromHandle(
u64 aruid, const Core::HID::SixAxisSensorHandle& device_handle);
const NpadControllerData& GetControllerFromHandle(
@ -215,11 +196,13 @@ private:
mutable std::mutex mutex;
NPadResource npad_resource;
AppletResourceHolder applet_resource_holder{};
std::array<AbstractPad, MaxSupportedNpadIdTypes> abstracted_pads;
NpadVibration vibration_handler{};
Kernel::KEvent* input_event{nullptr};
std::mutex* input_mutex{nullptr};
std::atomic<u64> press_state{};
bool permit_vibration_session_enabled;
std::array<std::array<NpadControllerData, MaxSupportedNpadIdTypes>, AruidIndexMax>
controller_data{};
};

View File

@ -8,6 +8,10 @@
#include "common/common_types.h"
#include "hid_core/hid_types.h"
namespace Core::HID {
class EmulatedController;
}
namespace Service::HID {
static constexpr std::size_t MaxSupportedNpadIdTypes = 10;
static constexpr std::size_t StyleIndexCount = 7;
@ -348,7 +352,7 @@ struct IAbstractedPad {
u8 indicator;
std::vector<f32> virtual_six_axis_sensor_acceleration;
std::vector<f32> virtual_six_axis_sensor_angle;
u64 xcd_handle;
Core::HID::EmulatedController* xcd_handle;
u64 color;
};
} // namespace Service::HID

View File

@ -77,4 +77,8 @@ Result NpadVibration::EndPermitVibrationSession() {
return ResultSuccess;
}
u64 NpadVibration::GetSessionAruid() const {
return session_aruid;
}
} // namespace Service::HID

View File

@ -25,6 +25,8 @@ public:
Result BeginPermitVibrationSession(u64 aruid);
Result EndPermitVibrationSession();
u64 GetSessionAruid() const;
private:
f32 volume{};
u64 session_aruid{};

View File

@ -1,6 +1,7 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
#include "hid_core/frontend/emulated_controller.h"
#include "hid_core/hid_result.h"
#include "hid_core/resources/npad/npad_types.h"
#include "hid_core/resources/npad/npad_vibration.h"
@ -10,24 +11,25 @@ namespace Service::HID {
NpadGcVibrationDevice::NpadGcVibrationDevice() {}
Result NpadGcVibrationDevice::IncrementRefCounter() {
Result NpadGcVibrationDevice::Activate() {
if (ref_counter == 0 && is_mounted) {
f32 volume = 1.0f;
const auto result = vibration_handler->GetVibrationVolume(volume);
if (result.IsSuccess()) {
// TODO: SendVibrationGcErmCommand
xcd_handle->SetVibration(adapter_slot, Core::HID::VibrationGcErmCommand::Stop);
}
}
ref_counter++;
return ResultSuccess;
}
Result NpadGcVibrationDevice::DecrementRefCounter() {
if (ref_counter == 1 && !is_mounted) {
Result NpadGcVibrationDevice::Deactivate() {
if (ref_counter == 1 && is_mounted) {
f32 volume = 1.0f;
const auto result = vibration_handler->GetVibrationVolume(volume);
if (result.IsSuccess()) {
// TODO: SendVibrationGcErmCommand
xcd_handle->SetVibration(adapter_slot, Core::HID::VibrationGcErmCommand::Stop);
}
}
@ -38,6 +40,48 @@ Result NpadGcVibrationDevice::DecrementRefCounter() {
return ResultSuccess;
}
Result NpadGcVibrationDevice::Mount(IAbstractedPad& abstracted_pad, u32 slot,
NpadVibration* handler) {
if (!abstracted_pad.internal_flags.is_connected) {
return ResultSuccess;
}
// TODO: This device doesn't use a xcd handle instead has an GC adapter handle. This is just to
// keep compatibility with the front end.
xcd_handle = abstracted_pad.xcd_handle;
adapter_slot = slot;
vibration_handler = handler;
is_mounted = true;
if (ref_counter == 0) {
return ResultSuccess;
}
f32 volume{1.0f};
const auto result = vibration_handler->GetVibrationVolume(volume);
if (result.IsSuccess()) {
xcd_handle->SetVibration(adapter_slot, Core::HID::VibrationGcErmCommand::Stop);
}
return ResultSuccess;
}
Result NpadGcVibrationDevice::Unmount() {
if (ref_counter == 0 || !is_mounted) {
is_mounted = false;
return ResultSuccess;
}
f32 volume{1.0f};
const auto result = vibration_handler->GetVibrationVolume(volume);
if (result.IsSuccess()) {
xcd_handle->SetVibration(adapter_slot, Core::HID::VibrationGcErmCommand::Stop);
}
is_mounted = false;
return ResultSuccess;
}
Result NpadGcVibrationDevice::SendVibrationGcErmCommand(Core::HID::VibrationGcErmCommand command) {
if (!is_mounted) {
return ResultSuccess;
@ -55,7 +99,7 @@ Result NpadGcVibrationDevice::SendVibrationGcErmCommand(Core::HID::VibrationGcEr
return ResultSuccess;
}
}
// TODO: SendVibrationGcErmCommand
xcd_handle->SetVibration(adapter_slot, command);
return ResultSuccess;
}

View File

@ -20,12 +20,18 @@ class NpadGcVibrationDevice final : public NpadVibrationBase {
public:
explicit NpadGcVibrationDevice();
Result IncrementRefCounter() override;
Result DecrementRefCounter() override;
Result Activate() override;
Result Deactivate() override;
Result Mount(IAbstractedPad& abstracted_pad, u32 slot, NpadVibration* handler);
Result Unmount();
Result SendVibrationGcErmCommand(Core::HID::VibrationGcErmCommand command);
Result GetActualVibrationGcErmCommand(Core::HID::VibrationGcErmCommand& out_command);
Result SendVibrationNotificationPattern(Core::HID::VibrationGcErmCommand command);
private:
u32 adapter_slot;
};
} // namespace Service::HID

View File

@ -1,6 +1,7 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
#include "hid_core/frontend/emulated_controller.h"
#include "hid_core/hid_result.h"
#include "hid_core/resources/npad/npad_types.h"
#include "hid_core/resources/npad/npad_vibration.h"
@ -10,12 +11,12 @@ namespace Service::HID {
NpadN64VibrationDevice::NpadN64VibrationDevice() {}
Result NpadN64VibrationDevice::IncrementRefCounter() {
Result NpadN64VibrationDevice::Activate() {
if (ref_counter == 0 && is_mounted) {
f32 volume = 1.0f;
const auto result = vibration_handler->GetVibrationVolume(volume);
if (result.IsSuccess()) {
// TODO: SendVibrationInBool
xcd_handle->SetVibration(false);
}
}
@ -23,19 +24,12 @@ Result NpadN64VibrationDevice::IncrementRefCounter() {
return ResultSuccess;
}
Result NpadN64VibrationDevice::DecrementRefCounter() {
if (ref_counter == 1) {
if (!is_mounted) {
ref_counter = 0;
if (is_mounted != false) {
// TODO: SendVibrationInBool
}
return ResultSuccess;
}
Result NpadN64VibrationDevice::Deactivate() {
if (ref_counter == 1 && is_mounted) {
f32 volume = 1.0f;
const auto result = vibration_handler->GetVibrationVolume(volume);
if (result.IsSuccess()) {
// TODO
xcd_handle->SetVibration(false);
}
}
@ -46,6 +40,43 @@ Result NpadN64VibrationDevice::DecrementRefCounter() {
return ResultSuccess;
}
Result NpadN64VibrationDevice::Mount(IAbstractedPad& abstracted_pad, NpadVibration* handler) {
if (!abstracted_pad.internal_flags.is_connected) {
return ResultSuccess;
}
xcd_handle = abstracted_pad.xcd_handle;
vibration_handler = handler;
is_mounted = true;
if (ref_counter == 0) {
return ResultSuccess;
}
f32 volume{1.0f};
const auto result = vibration_handler->GetVibrationVolume(volume);
if (result.IsSuccess()) {
xcd_handle->SetVibration(false);
}
return ResultSuccess;
}
Result NpadN64VibrationDevice::Unmount() {
if (ref_counter == 0 || !is_mounted) {
is_mounted = false;
return ResultSuccess;
}
f32 volume{1.0f};
const auto result = vibration_handler->GetVibrationVolume(volume);
if (result.IsSuccess()) {
xcd_handle->SetVibration(false);
}
is_mounted = false;
return ResultSuccess;
}
Result NpadN64VibrationDevice::SendValueInBool(bool is_vibrating) {
if (ref_counter < 1) {
return ResultVibrationNotInitialized;
@ -56,7 +87,7 @@ Result NpadN64VibrationDevice::SendValueInBool(bool is_vibrating) {
if (result.IsError()) {
return result;
}
// TODO: SendVibrationInBool
xcd_handle->SetVibration(false);
}
return ResultSuccess;
}

View File

@ -14,14 +14,18 @@
namespace Service::HID {
class NpadVibration;
struct IAbstractedPad;
/// Handles Npad request from HID interfaces
class NpadN64VibrationDevice final : public NpadVibrationBase {
public:
explicit NpadN64VibrationDevice();
Result IncrementRefCounter() override;
Result DecrementRefCounter() override;
Result Activate() override;
Result Deactivate() override;
Result Mount(IAbstractedPad& abstracted_pad, NpadVibration* handler);
Result Unmount();
Result SendValueInBool(bool is_vibrating);
Result SendVibrationNotificationPattern(u32 pattern);

View File

@ -10,12 +10,12 @@ namespace Service::HID {
NpadVibrationBase::NpadVibrationBase() {}
Result NpadVibrationBase::IncrementRefCounter() {
Result NpadVibrationBase::Activate() {
ref_counter++;
return ResultSuccess;
}
Result NpadVibrationBase::DecrementRefCounter() {
Result NpadVibrationBase::Deactivate() {
if (ref_counter > 0) {
ref_counter--;
}

View File

@ -6,6 +6,10 @@
#include "common/common_types.h"
#include "core/hle/result.h"
namespace Core::HID {
class EmulatedController;
}
namespace Service::HID {
class NpadVibration;
@ -14,13 +18,13 @@ class NpadVibrationBase {
public:
explicit NpadVibrationBase();
virtual Result IncrementRefCounter();
virtual Result DecrementRefCounter();
virtual Result Activate();
virtual Result Deactivate();
bool IsVibrationMounted() const;
protected:
u64 xcd_handle{};
Core::HID::EmulatedController* xcd_handle{nullptr};
s32 ref_counter{};
bool is_mounted{};
NpadVibration* vibration_handler{nullptr};

View File

@ -1,6 +1,7 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
#include "hid_core/frontend/emulated_controller.h"
#include "hid_core/hid_result.h"
#include "hid_core/resources/npad/npad_types.h"
#include "hid_core/resources/npad/npad_vibration.h"
@ -10,12 +11,30 @@ namespace Service::HID {
NpadVibrationDevice::NpadVibrationDevice() {}
Result NpadVibrationDevice::IncrementRefCounter() {
Result NpadVibrationDevice::Activate() {
if (ref_counter == 0 && is_mounted) {
f32 volume = 1.0f;
const auto result = vibration_handler->GetVibrationVolume(volume);
if (result.IsSuccess()) {
xcd_handle->SetVibration(device_index, Core::HID::DEFAULT_VIBRATION_VALUE);
// TODO: SendNotificationPattern;
}
}
ref_counter++;
return ResultSuccess;
}
Result NpadVibrationDevice::DecrementRefCounter() {
Result NpadVibrationDevice::Deactivate() {
if (ref_counter == 1 && is_mounted) {
f32 volume = 1.0f;
const auto result = vibration_handler->GetVibrationVolume(volume);
if (result.IsSuccess()) {
xcd_handle->SetVibration(device_index, Core::HID::DEFAULT_VIBRATION_VALUE);
// TODO: SendNotificationPattern;
}
}
if (ref_counter > 0) {
ref_counter--;
}
@ -23,6 +42,45 @@ Result NpadVibrationDevice::DecrementRefCounter() {
return ResultSuccess;
}
Result NpadVibrationDevice::Mount(IAbstractedPad& abstracted_pad, Core::HID::DeviceIndex index,
NpadVibration* handler) {
if (!abstracted_pad.internal_flags.is_connected) {
return ResultSuccess;
}
xcd_handle = abstracted_pad.xcd_handle;
device_index = index;
vibration_handler = handler;
is_mounted = true;
if (ref_counter == 0) {
return ResultSuccess;
}
f32 volume{1.0f};
const auto result = vibration_handler->GetVibrationVolume(volume);
if (result.IsSuccess()) {
xcd_handle->SetVibration(false);
}
return ResultSuccess;
}
Result NpadVibrationDevice::Unmount() {
if (ref_counter == 0 || !is_mounted) {
is_mounted = false;
return ResultSuccess;
}
f32 volume{1.0f};
const auto result = vibration_handler->GetVibrationVolume(volume);
if (result.IsSuccess()) {
xcd_handle->SetVibration(device_index, Core::HID::DEFAULT_VIBRATION_VALUE);
}
is_mounted = false;
return ResultSuccess;
}
Result NpadVibrationDevice::SendVibrationValue(const Core::HID::VibrationValue& value) {
if (ref_counter == 0) {
return ResultVibrationNotInitialized;
@ -37,7 +95,7 @@ Result NpadVibrationDevice::SendVibrationValue(const Core::HID::VibrationValue&
return result;
}
if (volume <= 0.0f) {
// TODO: SendVibrationValue
xcd_handle->SetVibration(device_index, Core::HID::DEFAULT_VIBRATION_VALUE);
return ResultSuccess;
}
@ -45,7 +103,7 @@ Result NpadVibrationDevice::SendVibrationValue(const Core::HID::VibrationValue&
vibration_value.high_amplitude *= volume;
vibration_value.low_amplitude *= volume;
// TODO: SendVibrationValue
xcd_handle->SetVibration(device_index, vibration_value);
return ResultSuccess;
}
@ -63,11 +121,11 @@ Result NpadVibrationDevice::SendVibrationNotificationPattern([[maybe_unused]] u3
pattern = 0;
}
// return xcd_handle->SendVibrationNotificationPattern(pattern);
// TODO: SendVibrationNotificationPattern;
return ResultSuccess;
}
Result NpadVibrationDevice::GetActualVibrationValue(Core::HID::VibrationValue& out_value) {
Result NpadVibrationDevice::GetActualVibrationValue(Core::HID::VibrationValue& out_value) const {
if (ref_counter < 1) {
return ResultVibrationNotInitialized;
}
@ -77,7 +135,7 @@ Result NpadVibrationDevice::GetActualVibrationValue(Core::HID::VibrationValue& o
return ResultSuccess;
}
// TODO: SendVibrationValue
out_value = xcd_handle->GetActualVibrationValue(device_index);
return ResultSuccess;
}

View File

@ -12,6 +12,10 @@
#include "hid_core/resources/npad/npad_types.h"
#include "hid_core/resources/vibration/vibration_base.h"
namespace Core::HID {
enum class DeviceIndex : u8;
}
namespace Service::HID {
class NpadVibration;
@ -20,16 +24,20 @@ class NpadVibrationDevice final : public NpadVibrationBase {
public:
explicit NpadVibrationDevice();
Result IncrementRefCounter();
Result DecrementRefCounter();
Result Activate();
Result Deactivate();
Result Mount(IAbstractedPad& abstracted_pad, Core::HID::DeviceIndex index,
NpadVibration* handler);
Result Unmount();
Result SendVibrationValue(const Core::HID::VibrationValue& value);
Result SendVibrationNotificationPattern(u32 pattern);
Result GetActualVibrationValue(Core::HID::VibrationValue& out_value);
Result GetActualVibrationValue(Core::HID::VibrationValue& out_value) const;
private:
u32 device_index{};
Core::HID::DeviceIndex device_index{};
};
} // namespace Service::HID

View File

@ -2,6 +2,8 @@
# SPDX-License-Identifier: GPL-2.0-or-later
add_library(input_common STATIC
drivers/android.cpp
drivers/android.h
drivers/camera.cpp
drivers/camera.h
drivers/keyboard.cpp

View File

@ -0,0 +1,48 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
#include "input_common/drivers/android.h"
namespace InputCommon {
Android::Android(std::string input_engine_) : InputEngine(std::move(input_engine_)) {}
void Android::RegisterController(std::size_t controller_number) {
PreSetController(GetIdentifier(controller_number));
}
void Android::SetButtonState(std::size_t controller_number, int button_id, bool value) {
const auto identifier = GetIdentifier(controller_number);
SetButton(identifier, button_id, value);
}
void Android::SetAxisState(std::size_t controller_number, int axis_id, float value) {
const auto identifier = GetIdentifier(controller_number);
SetAxis(identifier, axis_id, value);
}
void Android::SetMotionState(std::size_t controller_number, u64 delta_timestamp, float gyro_x,
float gyro_y, float gyro_z, float accel_x, float accel_y,
float accel_z) {
const auto identifier = GetIdentifier(controller_number);
const BasicMotion motion_data{
.gyro_x = gyro_x,
.gyro_y = gyro_y,
.gyro_z = gyro_z,
.accel_x = accel_x,
.accel_y = accel_y,
.accel_z = accel_z,
.delta_timestamp = delta_timestamp,
};
SetMotion(identifier, 0, motion_data);
}
PadIdentifier Android::GetIdentifier(std::size_t controller_number) const {
return {
.guid = Common::UUID{},
.port = controller_number,
.pad = 0,
};
}
} // namespace InputCommon

View File

@ -0,0 +1,54 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
#pragma once
#include "input_common/input_engine.h"
namespace InputCommon {
/**
* A virtual controller that is always assigned to the game input
*/
class Android final : public InputEngine {
public:
explicit Android(std::string input_engine_);
/**
* Registers controller number to accept new inputs
* @param controller_number the controller number that will take this action
*/
void RegisterController(std::size_t controller_number);
/**
* Sets the status of all buttons bound with the key to pressed
* @param controller_number the controller number that will take this action
* @param button_id the id of the button
* @param value indicates if the button is pressed or not
*/
void SetButtonState(std::size_t controller_number, int button_id, bool value);
/**
* Sets the status of a analog input to a specific player index
* @param controller_number the controller number that will take this action
* @param axis_id the id of the axis to move
* @param value the analog position of the axis
*/
void SetAxisState(std::size_t controller_number, int axis_id, float value);
/**
* Sets the status of the motion sensor to a specific player index
* @param controller_number the controller number that will take this action
* @param delta_timestamp time passed since last reading
* @param gyro_x,gyro_y,gyro_z the gyro sensor readings
* @param accel_x,accel_y,accel_z the accelerometer reading
*/
void SetMotionState(std::size_t controller_number, u64 delta_timestamp, float gyro_x,
float gyro_y, float gyro_z, float accel_x, float accel_y, float accel_z);
private:
/// Returns the correct identifier corresponding to the player index
PadIdentifier GetIdentifier(std::size_t controller_number) const;
};
} // namespace InputCommon

View File

@ -210,6 +210,9 @@ bool MappingFactory::IsDriverValid(const MappingData& data) const {
if (data.engine == "analog_from_button") {
return false;
}
if (data.engine == "virtual_gamepad") {
return false;
}
return true;
}

View File

@ -4,6 +4,7 @@
#include <memory>
#include "common/input.h"
#include "common/param_package.h"
#include "input_common/drivers/android.h"
#include "input_common/drivers/camera.h"
#include "input_common/drivers/keyboard.h"
#include "input_common/drivers/mouse.h"
@ -78,6 +79,7 @@ struct InputSubsystem::Impl {
RegisterEngine("cemuhookudp", udp_client);
RegisterEngine("tas", tas_input);
RegisterEngine("camera", camera);
RegisterEngine("android", android);
RegisterEngine("virtual_amiibo", virtual_amiibo);
RegisterEngine("virtual_gamepad", virtual_gamepad);
#ifdef HAVE_SDL2
@ -109,6 +111,7 @@ struct InputSubsystem::Impl {
UnregisterEngine(udp_client);
UnregisterEngine(tas_input);
UnregisterEngine(camera);
UnregisterEngine(android);
UnregisterEngine(virtual_amiibo);
UnregisterEngine(virtual_gamepad);
#ifdef HAVE_SDL2
@ -129,6 +132,8 @@ struct InputSubsystem::Impl {
devices.insert(devices.end(), keyboard_devices.begin(), keyboard_devices.end());
auto mouse_devices = mouse->GetInputDevices();
devices.insert(devices.end(), mouse_devices.begin(), mouse_devices.end());
auto android_devices = android->GetInputDevices();
devices.insert(devices.end(), android_devices.begin(), android_devices.end());
#ifdef HAVE_LIBUSB
auto gcadapter_devices = gcadapter->GetInputDevices();
devices.insert(devices.end(), gcadapter_devices.begin(), gcadapter_devices.end());
@ -157,6 +162,9 @@ struct InputSubsystem::Impl {
if (engine == mouse->GetEngineName()) {
return mouse;
}
if (engine == android->GetEngineName()) {
return android;
}
#ifdef HAVE_LIBUSB
if (engine == gcadapter->GetEngineName()) {
return gcadapter;
@ -237,6 +245,9 @@ struct InputSubsystem::Impl {
if (engine == mouse->GetEngineName()) {
return true;
}
if (engine == android->GetEngineName()) {
return true;
}
#ifdef HAVE_LIBUSB
if (engine == gcadapter->GetEngineName()) {
return true;
@ -265,6 +276,7 @@ struct InputSubsystem::Impl {
void BeginConfiguration() {
keyboard->BeginConfiguration();
mouse->BeginConfiguration();
android->BeginConfiguration();
#ifdef HAVE_LIBUSB
gcadapter->BeginConfiguration();
#endif
@ -278,6 +290,7 @@ struct InputSubsystem::Impl {
void EndConfiguration() {
keyboard->EndConfiguration();
mouse->EndConfiguration();
android->EndConfiguration();
#ifdef HAVE_LIBUSB
gcadapter->EndConfiguration();
#endif
@ -308,6 +321,7 @@ struct InputSubsystem::Impl {
std::shared_ptr<TasInput::Tas> tas_input;
std::shared_ptr<CemuhookUDP::UDPClient> udp_client;
std::shared_ptr<Camera> camera;
std::shared_ptr<Android> android;
std::shared_ptr<VirtualAmiibo> virtual_amiibo;
std::shared_ptr<VirtualGamepad> virtual_gamepad;
@ -373,6 +387,14 @@ const Camera* InputSubsystem::GetCamera() const {
return impl->camera.get();
}
Android* InputSubsystem::GetAndroid() {
return impl->android.get();
}
const Android* InputSubsystem::GetAndroid() const {
return impl->android.get();
}
VirtualAmiibo* InputSubsystem::GetVirtualAmiibo() {
return impl->virtual_amiibo.get();
}

View File

@ -29,6 +29,7 @@ enum Values : int;
}
namespace InputCommon {
class Android;
class Camera;
class Keyboard;
class Mouse;
@ -103,6 +104,12 @@ public:
/// Retrieves the underlying camera input device.
[[nodiscard]] const Camera* GetCamera() const;
/// Retrieves the underlying android input device.
[[nodiscard]] Android* GetAndroid();
/// Retrieves the underlying android input device.
[[nodiscard]] const Android* GetAndroid() const;
/// Retrieves the underlying virtual amiibo input device.
[[nodiscard]] VirtualAmiibo* GetVirtualAmiibo();

View File

@ -116,8 +116,8 @@ void ConfigureVibration::VibrateController(Core::HID::ControllerTriggerType type
.high_amplitude = 1.0f,
.high_frequency = 320.0f,
};
controller->SetVibration(0, vibration);
controller->SetVibration(1, vibration);
controller->SetVibration(Core::HID::DeviceIndex::Left, vibration);
controller->SetVibration(Core::HID::DeviceIndex::Right, vibration);
// Restore previous values
player.vibration_enabled = old_vibration_enabled;
@ -127,7 +127,7 @@ void ConfigureVibration::VibrateController(Core::HID::ControllerTriggerType type
void ConfigureVibration::StopVibrations() {
for (std::size_t i = 0; i < NUM_PLAYERS; ++i) {
auto controller = hid_core.GetEmulatedControllerByIndex(i);
controller->SetVibration(0, Core::HID::DEFAULT_VIBRATION_VALUE);
controller->SetVibration(1, Core::HID::DEFAULT_VIBRATION_VALUE);
controller->SetVibration(Core::HID::DeviceIndex::Left, Core::HID::DEFAULT_VIBRATION_VALUE);
controller->SetVibration(Core::HID::DeviceIndex::Right, Core::HID::DEFAULT_VIBRATION_VALUE);
}
}