Compare commits

...

43 Commits

Author SHA1 Message Date
David Marcec
d67c6d5d01 Addressed issues 2020-09-21 15:56:45 +10:00
David Marcec
e6266bb49f Fix vulkan VkPipelineShaderStageCreateInfo 2020-09-20 17:54:54 +10:00
David Marcec
35795a042c style: C++20 module keyword fixup
With C++20, "module" is now considered a keyword, this PR removes mentions of the word "module".
2020-09-20 16:33:47 +10:00
bunnei
8a85a562ed Merge pull request #4643 from FearlessTobi/decrease-pad-update-interval
Test: Decrease pad_update_ns
2020-09-19 00:39:50 -07:00
Rodrigo Locatti
059dd724d6 Merge pull request #4684 from lioncash/desig4
fermi_2d: Make use of designated initializers
2020-09-18 19:14:56 +00:00
Lioncash
91bca9eb0b fermi_2d: Make use of designated initializers
Same behavior, less repetition. We can also ensure all members of Config
are initialized.
2020-09-18 13:55:21 -04:00
David
050a4a401b Merge pull request #4680 from Morph1984/fix-motion-mapping
configure_input_player: Fixes motion mapping using ConfigureButtonClick
2020-09-18 21:03:50 +10:00
Morph
70499b8cbd configure_input_player: Fixes motion mapping using ConfigureButtonClick 2020-09-18 03:56:31 -04:00
bunnei
8568f44ffa Merge pull request #4647 from Morph1984/readd-context-menu
configure_input_player: Re-add "Clear" context menu option
2020-09-17 22:59:13 -07:00
bunnei
669005b75e Merge pull request #4676 from Morph1984/GetPreviousProgramIndex-impl
am: Stub GetPreviousProgramIndex
2020-09-17 22:12:57 -07:00
Morph
40a72e9cd5 am: Stub GetPreviousProgramIndex
- Used in Super Mario 3D All-Stars
2020-09-17 22:03:02 -04:00
Morph
65d9def873 configure_input_player: Re-add "Clear" context menu option
The context menu was removed in Mjölnir Part 1 as part of the input rewrite as we were unaware of it's usage statistics.
However, as this was the only way to clear the inputs of individual buttons, this PR will re-add it back in.
2020-09-17 21:57:06 -04:00
Rodrigo Locatti
53fc5d0190 Merge pull request #4670 from lioncash/initializer
arm_dynarmic_cp15: Initialize member variables
2020-09-17 21:20:53 +00:00
Rodrigo Locatti
9bdca01c27 Merge pull request #4665 from lioncash/sm-kernel
service/sm: Eliminate dependency on the global system instance
2020-09-17 21:20:39 +00:00
Rodrigo Locatti
8100275309 Merge pull request #4666 from lioncash/unused-func
service: Remove unused funcation
2020-09-17 21:19:48 +00:00
Rodrigo Locatti
131532b570 Merge pull request #4671 from lioncash/nfp-copy
command_generator/nfp: Eliminate unnecessary copies
2020-09-17 21:19:12 +00:00
Rodrigo Locatti
31461589c5 Merge pull request #4672 from lioncash/narrowing
decoder/texture: Eliminate narrowing conversion in GetTldCode()
2020-09-17 21:17:54 +00:00
Rodrigo Locatti
9f51242524 Merge pull request #4673 from lioncash/fallthrough
decode/image: Eliminate switch fallthrough in DecodeImage()
2020-09-17 21:17:16 +00:00
bunnei
3f6d83b27c Merge pull request #4594 from german77/MotionHID
hid/configuration: Implement motion controls to HID
2020-09-17 12:39:01 -07:00
Lioncash
4944d48ee8 decode/image: Eliminate switch fallthrough in DecodeImage()
Fortunately this didn't result in any issues, given the block that code
was falling through to would immediately break.
2020-09-17 15:12:18 -04:00
Lioncash
ffc66f089d decoder/texture: Eliminate narrowing conversion in GetTldCode()
The assignment was previously truncating a u64 value to a bool.
2020-09-17 15:04:17 -04:00
Lioncash
362e2940be audio_core/command_generator: Use const references where applicable
In a lot of cases, we can make use of const references rather than
non-const references.

While we're in the area we can silence some truncation and sign
conversion warnings.
2020-09-17 13:52:55 -04:00
Lioncash
9539e4d8fd audio_core/command_generator: Avoid an unnecessary copy in GenerateFinalMixCommand() 2020-09-17 13:45:24 -04:00
Lioncash
aca3621146 nfp: Eliminate two unnecessary copies
GetAmiiboBuffer() returns by const reference, so we can use a reference
instead of taking the returned buffer by value.
2020-09-17 13:35:55 -04:00
Lioncash
1ee9ceb5af arm_dynarmic_cp15: Initialize member variables
Ensures that the member variables are always initialized to a
deterministic value on creation.
2020-09-17 13:03:49 -04:00
bunnei
382bf1faf4 Merge pull request #4668 from lioncash/port
control_metadata: Resolve typo in Portuguese language name
2020-09-17 09:55:01 -07:00
Lioncash
02b8b6677a control_metadata: Resolve typo in Portuguese language name
This isn't used anywhere, so this is a trivial fix.
2020-09-17 11:45:30 -04:00
Lioncash
8bbd82863d service: Remove unused funcation
This is now completely unused, so it can be removed.
2020-09-17 11:03:26 -04:00
Lioncash
057aa6275d service/sm: Slightly more efficient string name validation
We can check the end of the string first for null-termination, rather
than the beginning of the string.
2020-09-17 10:54:12 -04:00
Lioncash
78b1bc3b61 service/sm: Eliminate dependency on the global system instance 2020-09-17 10:43:54 -04:00
bunnei
fcd0925ecf Merge pull request #4653 from ReinUsesLisp/gc-warns
gc_adapter: Disable MSVC nonstandard extension warning on libusb.h
2020-09-16 22:33:58 -07:00
bunnei
1eae35621e Merge pull request #4663 from ReinUsesLisp/wswitch
video_core: Enforce -Werror=switch
2020-09-16 20:43:23 -07:00
Rodrigo Locatti
62de0220fe Merge pull request #4662 from lioncash/factory
bis_factory/romfs_factory: Eliminate dependencies on the global system instance
2020-09-16 23:43:30 +00:00
ReinUsesLisp
eb914b6c50 video_core: Enforce -Werror=switch
This forces us to fix all -Wswitch warnings in video_core.
2020-09-16 17:48:01 -03:00
ReinUsesLisp
bc8ace9917 gc_adapter: Disable MSVC nonstandard extension warning on libusb.h
Pragma disable zero-sized array nonstandard extension warning on MSVC.
2020-09-14 19:38:08 -03:00
FearlessTobi
57162e1df3 Test: Decrease pad_update_ns
There have been reports of quite heavy input lag in the past.
Compared to Citra for example, our pad_update_ns value is very high.
So let's decrease it and see if it helps with this problem.
2020-09-10 16:38:53 +02:00
Morph
5b6268d26a configure_input: Hook up the motion button and checkbox
This allows toggling motion on or off, and allows access to the motion configuration.
Also changes the [waiting] text for motion buttons to Shake! as this is how motion is connected to a player.
2020-09-05 09:46:34 -04:00
german
797564599f Minor cleanup 2020-09-05 09:42:21 -04:00
german
6ee8eab670 Add cemu hook changes related to PR #4609 2020-09-04 21:48:13 -05:00
german
0774b17846 Remove RealMotionDevice 2020-09-04 21:48:13 -05:00
Morph
8e18b61972 configure_input_player: Show/hide motion buttons based on the controller 2020-09-04 21:48:13 -05:00
Morph
df3cbd4758 controllers/npad: Simplify motion entry assignment
Simplifies the motion assignment in the Dual Joycon entry and assigns index 1 of the motion entry (Motion 2) for the right joycon.
2020-09-04 21:48:13 -05:00
german
ff679f3d17 Include HID and configuration changes related to motion 2020-09-04 21:48:03 -05:00
98 changed files with 1342 additions and 438 deletions

View File

@@ -196,7 +196,7 @@ void CommandGenerator::PreCommand() {
for (std::size_t i = 0; i < splitter_context.GetInfoCount(); i++) {
const auto& base = splitter_context.GetInfo(i);
std::string graph = fmt::format("b[{}]", i);
auto* head = base.GetHead();
const auto* head = base.GetHead();
while (head != nullptr) {
graph += fmt::format("->{}", head->GetMixId());
head = head->GetNextDestination();
@@ -214,7 +214,7 @@ void CommandGenerator::PostCommand() {
void CommandGenerator::GenerateDataSourceCommand(ServerVoiceInfo& voice_info, VoiceState& dsp_state,
s32 channel) {
auto& in_params = voice_info.GetInParams();
const auto& in_params = voice_info.GetInParams();
const auto depop = in_params.should_depop;
if (depop) {
@@ -405,7 +405,7 @@ void CommandGenerator::GenerateBiquadFilterEffectCommand(s32 mix_buffer_offset,
}
void CommandGenerator::GenerateAuxCommand(s32 mix_buffer_offset, EffectBase* info, bool enabled) {
auto aux = dynamic_cast<EffectAuxInfo*>(info);
auto* aux = dynamic_cast<EffectAuxInfo*>(info);
const auto& params = aux->GetParams();
if (aux->GetSendBuffer() != 0 && aux->GetRecvBuffer() != 0) {
const auto max_channels = params.count;
@@ -571,7 +571,7 @@ void CommandGenerator::GenerateSubMixCommand(ServerMixInfo& mix_info) {
if (dumping_frame) {
LOG_DEBUG(Audio, "(DSP_TRACE) GenerateSubMixCommand");
}
auto& in_params = mix_info.GetInParams();
const auto& in_params = mix_info.GetInParams();
GenerateDepopForMixBuffersCommand(in_params.buffer_count, in_params.buffer_offset,
in_params.sample_rate);
@@ -650,7 +650,7 @@ void CommandGenerator::GenerateFinalMixCommand() {
LOG_DEBUG(Audio, "(DSP_TRACE) GenerateFinalMixCommand");
}
auto& mix_info = mix_context.GetFinalMixInfo();
const auto in_params = mix_info.GetInParams();
const auto& in_params = mix_info.GetInParams();
GenerateDepopForMixBuffersCommand(in_params.buffer_count, in_params.buffer_offset,
in_params.sample_rate);
@@ -674,7 +674,7 @@ void CommandGenerator::GenerateFinalMixCommand() {
s32 CommandGenerator::DecodePcm16(ServerVoiceInfo& voice_info, VoiceState& dsp_state,
s32 sample_count, s32 channel, std::size_t mix_offset) {
auto& in_params = voice_info.GetInParams();
const auto& in_params = voice_info.GetInParams();
const auto& wave_buffer = in_params.wave_buffer[dsp_state.wave_buffer_index];
if (wave_buffer.buffer_address == 0) {
return 0;
@@ -714,7 +714,7 @@ s32 CommandGenerator::DecodePcm16(ServerVoiceInfo& voice_info, VoiceState& dsp_s
s32 CommandGenerator::DecodeAdpcm(ServerVoiceInfo& voice_info, VoiceState& dsp_state,
s32 sample_count, s32 channel, std::size_t mix_offset) {
auto& in_params = voice_info.GetInParams();
const auto& in_params = voice_info.GetInParams();
const auto& wave_buffer = in_params.wave_buffer[dsp_state.wave_buffer_index];
if (wave_buffer.buffer_address == 0) {
return 0;
@@ -766,8 +766,8 @@ s32 CommandGenerator::DecodeAdpcm(ServerVoiceInfo& voice_info, VoiceState& dsp_s
val = std::clamp<s32>(val, -32768, 32767);
// Advance output feedback.
yn2 = yn1;
yn1 = val;
return static_cast<s16>(val);
yn1 = static_cast<s16>(val);
return yn1;
};
std::size_t buffer_offset{};
@@ -853,7 +853,7 @@ void CommandGenerator::DecodeFromWaveBuffers(ServerVoiceInfo& voice_info, s32* o
VoiceState& dsp_state, s32 channel,
s32 target_sample_rate, s32 sample_count,
s32 node_id) {
auto& in_params = voice_info.GetInParams();
const auto& in_params = voice_info.GetInParams();
if (dumping_frame) {
LOG_DEBUG(Audio,
"(DSP_TRACE) DecodeFromWaveBuffers, node_id={}, channel={}, "
@@ -867,7 +867,8 @@ void CommandGenerator::DecodeFromWaveBuffers(ServerVoiceInfo& voice_info, s32* o
static_cast<float>(in_params.sample_rate) / static_cast<float>(target_sample_rate) *
static_cast<float>(static_cast<s32>(in_params.pitch * 32768.0f)));
auto* output_base = output;
if ((dsp_state.fraction + sample_count * resample_rate) > (SCALED_MIX_BUFFER_SIZE - 4ULL)) {
if (dsp_state.fraction + sample_count * resample_rate >
static_cast<s32>(SCALED_MIX_BUFFER_SIZE - 4ULL)) {
return;
}

View File

@@ -162,17 +162,17 @@ std::vector<ARM_Interface::BacktraceEntry> ARM_Interface::GetBacktraceFromContex
}
std::map<std::string, Symbols> symbols;
for (const auto& module : modules) {
symbols.insert_or_assign(module.second, GetSymbols(module.first, memory));
for (const auto& mod : modules) {
symbols.insert_or_assign(mod.second, GetSymbols(mod.first, memory));
}
for (auto& entry : out) {
VAddr base = 0;
for (auto iter = modules.rbegin(); iter != modules.rend(); ++iter) {
const auto& module{*iter};
if (entry.original_address >= module.first) {
entry.module = module.second;
base = module.first;
const auto& mod{*iter};
if (entry.original_address >= mod.first) {
entry.mod = mod.second;
base = mod.first;
break;
}
}
@@ -180,10 +180,10 @@ std::vector<ARM_Interface::BacktraceEntry> ARM_Interface::GetBacktraceFromContex
entry.offset = entry.original_address - base;
entry.address = SEGMENT_BASE + entry.offset;
if (entry.module.empty())
entry.module = "unknown";
if (entry.mod.empty())
entry.mod = "unknown";
const auto symbol_set = symbols.find(entry.module);
const auto symbol_set = symbols.find(entry.mod);
if (symbol_set != symbols.end()) {
const auto symbol = GetSymbolName(symbol_set->second, entry.offset);
if (symbol.has_value()) {
@@ -218,17 +218,17 @@ std::vector<ARM_Interface::BacktraceEntry> ARM_Interface::GetBacktrace() const {
}
std::map<std::string, Symbols> symbols;
for (const auto& module : modules) {
symbols.insert_or_assign(module.second, GetSymbols(module.first, memory));
for (const auto& mod : modules) {
symbols.insert_or_assign(mod.second, GetSymbols(mod.first, memory));
}
for (auto& entry : out) {
VAddr base = 0;
for (auto iter = modules.rbegin(); iter != modules.rend(); ++iter) {
const auto& module{*iter};
if (entry.original_address >= module.first) {
entry.module = module.second;
base = module.first;
const auto& mod{*iter};
if (entry.original_address >= mod.first) {
entry.mod = mod.second;
base = mod.first;
break;
}
}
@@ -236,10 +236,10 @@ std::vector<ARM_Interface::BacktraceEntry> ARM_Interface::GetBacktrace() const {
entry.offset = entry.original_address - base;
entry.address = SEGMENT_BASE + entry.offset;
if (entry.module.empty())
entry.module = "unknown";
if (entry.mod.empty())
entry.mod = "unknown";
const auto symbol_set = symbols.find(entry.module);
const auto symbol_set = symbols.find(entry.mod);
if (symbol_set != symbols.end()) {
const auto symbol = GetSymbolName(symbol_set->second, entry.offset);
if (symbol.has_value()) {
@@ -262,7 +262,7 @@ void ARM_Interface::LogBacktrace() const {
const auto backtrace = GetBacktrace();
for (const auto& entry : backtrace) {
LOG_ERROR(Core_ARM, "{:20}{:016X} {:016X} {:016X} {}", entry.module, entry.address,
LOG_ERROR(Core_ARM, "{:20}{:016X} {:016X} {:016X} {}", entry.mod, entry.address,
entry.original_address, entry.offset, entry.name);
}
}

View File

@@ -162,7 +162,7 @@ public:
virtual void PrepareReschedule() = 0;
struct BacktraceEntry {
std::string module;
std::string mod;
u64 address;
u64 original_address;
u64 offset;

View File

@@ -35,8 +35,8 @@ public:
std::optional<u8> option) override;
ARM_Dynarmic_32& parent;
u32 uprw;
u32 uro;
u32 uprw = 0;
u32 uro = 0;
};
} // namespace Core

View File

@@ -178,7 +178,7 @@ struct System::Impl {
arp_manager.ResetAll();
telemetry_session = std::make_unique<Core::TelemetrySession>();
service_manager = std::make_shared<Service::SM::ServiceManager>();
service_manager = std::make_shared<Service::SM::ServiceManager>(kernel);
Service::Init(service_manager, system);
GDBStub::DeferStart();

View File

@@ -83,7 +83,7 @@ enum class Language : u8 {
Italian = 7,
Dutch = 8,
CanadianFrench = 9,
Portugese = 10,
Portuguese = 10,
Russian = 11,
Korean = 12,
Taiwanese = 13,

View File

@@ -10,7 +10,8 @@ ErrorApplet::~ErrorApplet() = default;
void DefaultErrorApplet::ShowError(ResultCode error, std::function<void()> finished) const {
LOG_CRITICAL(Service_Fatal, "Application requested error display: {:04}-{:04} (raw={:08X})",
static_cast<u32>(error.module.Value()), error.description.Value(), error.raw);
static_cast<u32>(error.error_module.Value()), error.description.Value(),
error.raw);
}
void DefaultErrorApplet::ShowErrorWithTimestamp(ResultCode error, std::chrono::seconds time,
@@ -18,7 +19,8 @@ void DefaultErrorApplet::ShowErrorWithTimestamp(ResultCode error, std::chrono::s
LOG_CRITICAL(
Service_Fatal,
"Application requested error display: {:04X}-{:04X} (raw={:08X}) with timestamp={:016X}",
static_cast<u32>(error.module.Value()), error.description.Value(), error.raw, time.count());
static_cast<u32>(error.error_module.Value()), error.description.Value(), error.raw,
time.count());
}
void DefaultErrorApplet::ShowCustomErrorText(ResultCode error, std::string main_text,
@@ -26,7 +28,8 @@ void DefaultErrorApplet::ShowCustomErrorText(ResultCode error, std::string main_
std::function<void()> finished) const {
LOG_CRITICAL(Service_Fatal,
"Application requested custom error with error_code={:04X}-{:04X} (raw={:08X})",
static_cast<u32>(error.module.Value()), error.description.Value(), error.raw);
static_cast<u32>(error.error_module.Value()), error.description.Value(),
error.raw);
LOG_CRITICAL(Service_Fatal, " Main Text: {}", main_text);
LOG_CRITICAL(Service_Fatal, " Detail Text: {}", detail_text);
}

View File

@@ -119,11 +119,11 @@ using ButtonDevice = InputDevice<bool>;
using AnalogDevice = InputDevice<std::tuple<float, float>>;
/**
* A motion device is an input device that returns a tuple of accelerometer state vector and
* gyroscope state vector.
* A motion status is an object that returns a tuple of accelerometer state vector,
* gyroscope state vector, rotation state vector and orientation state matrix.
*
* For both vectors:
* x+ is the same direction as LEFT on D-pad.
* x+ is the same direction as RIGHT on D-pad.
* y+ is normal to the touch screen, pointing outward.
* z+ is the same direction as UP on D-pad.
*
@@ -133,8 +133,22 @@ using AnalogDevice = InputDevice<std::tuple<float, float>>;
* For gyroscope state vector:
* Orientation is determined by right-hand rule.
* Units: deg/sec
*
* For rotation state vector
* Units: rotations
*
* For orientation state matrix
* x vector
* y vector
* z vector
*/
using MotionDevice = InputDevice<std::tuple<Common::Vec3<float>, Common::Vec3<float>>>;
using MotionStatus = std::tuple<Common::Vec3<float>, Common::Vec3<float>, Common::Vec3<float>,
std::array<Common::Vec3f, 3>>;
/**
* A motion device is an input device that returns a motion status object
*/
using MotionDevice = InputDevice<MotionStatus>;
/**
* A touch device is an input device that returns a tuple of two floats and a bool. The floats are

View File

@@ -189,16 +189,16 @@ std::vector<Module> modules;
} // Anonymous namespace
void RegisterModule(std::string name, VAddr beg, VAddr end, bool add_elf_ext) {
Module module;
Module mod;
if (add_elf_ext) {
Common::SplitPath(name, nullptr, &module.name, nullptr);
module.name += ".elf";
Common::SplitPath(name, nullptr, &mod.name, nullptr);
mod.name += ".elf";
} else {
module.name = std::move(name);
mod.name = std::move(name);
}
module.beg = beg;
module.end = end;
modules.push_back(std::move(module));
mod.beg = beg;
mod.end = end;
modules.push_back(std::move(mod));
}
static Kernel::Thread* FindThreadById(s64 id) {
@@ -671,10 +671,10 @@ static void HandleQuery() {
std::string buffer;
buffer += "l<?xml version=\"1.0\"?>";
buffer += "<library-list>";
for (const auto& module : modules) {
for (const auto& mod : modules) {
buffer +=
fmt::format(R"*("<library name = "{}"><segment address = "0x{:x}"/></library>)*",
module.name, module.beg);
mod.name, mod.beg);
}
buffer += "</library-list>";
SendReply(buffer.c_str());

View File

@@ -116,13 +116,13 @@ enum class ErrorModule : u32 {
union ResultCode {
u32 raw;
BitField<0, 9, ErrorModule> module;
BitField<0, 9, ErrorModule> error_module;
BitField<9, 13, u32> description;
constexpr explicit ResultCode(u32 raw) : raw(raw) {}
constexpr ResultCode(ErrorModule module_, u32 description_)
: raw(module.FormatValue(module_) | description.FormatValue(description_)) {}
: raw(error_module.FormatValue(module_) | description.FormatValue(description_)) {}
constexpr bool IsSuccess() const {
return raw == 0;

View File

@@ -807,25 +807,25 @@ void Module::Interface::TrySelectUserWithoutInteraction(Kernel::HLERequestContex
rb.PushRaw<u128>(profile_manager->GetUser(0)->uuid);
}
Module::Interface::Interface(std::shared_ptr<Module> module,
Module::Interface::Interface(std::shared_ptr<Module> interface_module,
std::shared_ptr<ProfileManager> profile_manager, Core::System& system,
const char* name)
: ServiceFramework(name), module(std::move(module)),
: ServiceFramework(name), interface_module(std::move(interface_module)),
profile_manager(std::move(profile_manager)), system(system) {}
Module::Interface::~Interface() = default;
void InstallInterfaces(Core::System& system) {
auto module = std::make_shared<Module>();
auto interface_module = std::make_shared<Module>();
auto profile_manager = std::make_shared<ProfileManager>();
std::make_shared<ACC_AA>(module, profile_manager, system)
std::make_shared<ACC_AA>(interface_module, profile_manager, system)
->InstallAsService(system.ServiceManager());
std::make_shared<ACC_SU>(module, profile_manager, system)
std::make_shared<ACC_SU>(interface_module, profile_manager, system)
->InstallAsService(system.ServiceManager());
std::make_shared<ACC_U0>(module, profile_manager, system)
std::make_shared<ACC_U0>(interface_module, profile_manager, system)
->InstallAsService(system.ServiceManager());
std::make_shared<ACC_U1>(module, profile_manager, system)
std::make_shared<ACC_U1>(interface_module, profile_manager, system)
->InstallAsService(system.ServiceManager());
}

View File

@@ -15,7 +15,7 @@ class Module final {
public:
class Interface : public ServiceFramework<Interface> {
public:
explicit Interface(std::shared_ptr<Module> module,
explicit Interface(std::shared_ptr<Module> interface_module,
std::shared_ptr<ProfileManager> profile_manager, Core::System& system,
const char* name);
~Interface() override;
@@ -57,7 +57,7 @@ public:
ApplicationInfo application_info{};
protected:
std::shared_ptr<Module> module;
std::shared_ptr<Module> interface_module;
std::shared_ptr<ProfileManager> profile_manager;
Core::System& system;
};

View File

@@ -6,9 +6,9 @@
namespace Service::Account {
ACC_AA::ACC_AA(std::shared_ptr<Module> module, std::shared_ptr<ProfileManager> profile_manager,
Core::System& system)
: Module::Interface(std::move(module), std::move(profile_manager), system, "acc:aa") {
ACC_AA::ACC_AA(std::shared_ptr<Module> interface_module,
std::shared_ptr<ProfileManager> profile_manager, Core::System& system)
: Module::Interface(std::move(interface_module), std::move(profile_manager), system, "acc:aa") {
static const FunctionInfo functions[] = {
{0, nullptr, "EnsureCacheAsync"},
{1, nullptr, "LoadCache"},

View File

@@ -10,8 +10,8 @@ namespace Service::Account {
class ACC_AA final : public Module::Interface {
public:
explicit ACC_AA(std::shared_ptr<Module> module, std::shared_ptr<ProfileManager> profile_manager,
Core::System& system);
explicit ACC_AA(std::shared_ptr<Module> interface_module,
std::shared_ptr<ProfileManager> profile_manager, Core::System& system);
~ACC_AA() override;
};

View File

@@ -6,9 +6,9 @@
namespace Service::Account {
ACC_SU::ACC_SU(std::shared_ptr<Module> module, std::shared_ptr<ProfileManager> profile_manager,
Core::System& system)
: Module::Interface(std::move(module), std::move(profile_manager), system, "acc:su") {
ACC_SU::ACC_SU(std::shared_ptr<Module> interface_module,
std::shared_ptr<ProfileManager> profile_manager, Core::System& system)
: Module::Interface(std::move(interface_module), std::move(profile_manager), system, "acc:su") {
// clang-format off
static const FunctionInfo functions[] = {
{0, &ACC_SU::GetUserCount, "GetUserCount"},

View File

@@ -10,8 +10,8 @@ namespace Service::Account {
class ACC_SU final : public Module::Interface {
public:
explicit ACC_SU(std::shared_ptr<Module> module, std::shared_ptr<ProfileManager> profile_manager,
Core::System& system);
explicit ACC_SU(std::shared_ptr<Module> interface_module,
std::shared_ptr<ProfileManager> profile_manager, Core::System& system);
~ACC_SU() override;
};

View File

@@ -6,9 +6,9 @@
namespace Service::Account {
ACC_U0::ACC_U0(std::shared_ptr<Module> module, std::shared_ptr<ProfileManager> profile_manager,
Core::System& system)
: Module::Interface(std::move(module), std::move(profile_manager), system, "acc:u0") {
ACC_U0::ACC_U0(std::shared_ptr<Module> interface_module,
std::shared_ptr<ProfileManager> profile_manager, Core::System& system)
: Module::Interface(std::move(interface_module), std::move(profile_manager), system, "acc:u0") {
// clang-format off
static const FunctionInfo functions[] = {
{0, &ACC_U0::GetUserCount, "GetUserCount"},

View File

@@ -10,8 +10,8 @@ namespace Service::Account {
class ACC_U0 final : public Module::Interface {
public:
explicit ACC_U0(std::shared_ptr<Module> module, std::shared_ptr<ProfileManager> profile_manager,
Core::System& system);
explicit ACC_U0(std::shared_ptr<Module> interface_module,
std::shared_ptr<ProfileManager> profile_manager, Core::System& system);
~ACC_U0() override;
};

View File

@@ -6,9 +6,9 @@
namespace Service::Account {
ACC_U1::ACC_U1(std::shared_ptr<Module> module, std::shared_ptr<ProfileManager> profile_manager,
Core::System& system)
: Module::Interface(std::move(module), std::move(profile_manager), system, "acc:u1") {
ACC_U1::ACC_U1(std::shared_ptr<Module> interface_module,
std::shared_ptr<ProfileManager> profile_manager, Core::System& system)
: Module::Interface(std::move(interface_module), std::move(profile_manager), system, "acc:u1") {
// clang-format off
static const FunctionInfo functions[] = {
{0, &ACC_U1::GetUserCount, "GetUserCount"},

View File

@@ -10,8 +10,8 @@ namespace Service::Account {
class ACC_U1 final : public Module::Interface {
public:
explicit ACC_U1(std::shared_ptr<Module> module, std::shared_ptr<ProfileManager> profile_manager,
Core::System& system);
explicit ACC_U1(std::shared_ptr<Module> interface_module,
std::shared_ptr<ProfileManager> profile_manager, Core::System& system);
~ACC_U1() override;
};

View File

@@ -1192,7 +1192,7 @@ IApplicationFunctions::IApplicationFunctions(Core::System& system_)
{120, nullptr, "ExecuteProgram"},
{121, nullptr, "ClearUserChannel"},
{122, nullptr, "UnpopToUserChannel"},
{123, nullptr, "GetPreviousProgramIndex"},
{123, &IApplicationFunctions::GetPreviousProgramIndex, "GetPreviousProgramIndex"},
{124, nullptr, "EnableApplicationAllThreadDumpOnCrash"},
{130, &IApplicationFunctions::GetGpuErrorDetectedSystemEvent, "GetGpuErrorDetectedSystemEvent"},
{140, &IApplicationFunctions::GetFriendInvitationStorageChannelEvent, "GetFriendInvitationStorageChannelEvent"},
@@ -1554,6 +1554,14 @@ void IApplicationFunctions::QueryApplicationPlayStatisticsByUid(Kernel::HLEReque
rb.Push<u32>(0);
}
void IApplicationFunctions::GetPreviousProgramIndex(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service_AM, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(RESULT_SUCCESS);
rb.Push<s32>(previous_program_index);
}
void IApplicationFunctions::GetGpuErrorDetectedSystemEvent(Kernel::HLERequestContext& ctx) {
LOG_WARNING(Service_AM, "(STUBBED) called");

View File

@@ -288,11 +288,13 @@ private:
void SetApplicationCopyrightVisibility(Kernel::HLERequestContext& ctx);
void QueryApplicationPlayStatistics(Kernel::HLERequestContext& ctx);
void QueryApplicationPlayStatisticsByUid(Kernel::HLERequestContext& ctx);
void GetPreviousProgramIndex(Kernel::HLERequestContext& ctx);
void GetGpuErrorDetectedSystemEvent(Kernel::HLERequestContext& ctx);
void GetFriendInvitationStorageChannelEvent(Kernel::HLERequestContext& ctx);
bool launch_popped_application_specific = false;
bool launch_popped_account_preselect = false;
s32 previous_program_index{-1};
Kernel::EventPair gpu_error_detected_event;
Kernel::EventPair friend_invitation_storage_channel_event;
Core::System& system;

View File

@@ -77,11 +77,11 @@ void CopyArgumentData(const std::vector<u8>& data, T& variable) {
ResultCode Decode64BitError(u64 error) {
const auto description = (error >> 32) & 0x1FFF;
auto module = error & 0x3FF;
if (module >= 2000)
module -= 2000;
module &= 0x1FF;
return {static_cast<ErrorModule>(module), static_cast<u32>(description)};
auto error_module = error & 0x3FF;
if (error_module >= 2000)
error_module -= 2000;
error_module &= 0x1FF;
return {static_cast<ErrorModule>(error_module), static_cast<u32>(description)};
}
} // Anonymous namespace

View File

@@ -6,9 +6,9 @@
namespace Service::BCAT {
BCAT::BCAT(Core::System& system, std::shared_ptr<Module> module,
BCAT::BCAT(Core::System& system, std::shared_ptr<Module> interface_module,
FileSystem::FileSystemController& fsc, const char* name)
: Interface(system, std::move(module), fsc, name) {
: Interface(system, std::move(interface_module), fsc, name) {
// clang-format off
static const FunctionInfo functions[] = {
{0, &BCAT::CreateBcatService, "CreateBcatService"},

View File

@@ -14,7 +14,7 @@ namespace Service::BCAT {
class BCAT final : public Module::Interface {
public:
explicit BCAT(Core::System& system, std::shared_ptr<Module> module,
explicit BCAT(Core::System& system, std::shared_ptr<Module> interface_module,
FileSystem::FileSystemController& fsc, const char* name);
~BCAT() override;
};

View File

@@ -579,9 +579,9 @@ std::unique_ptr<Backend> CreateBackendFromSettings([[maybe_unused]] Core::System
return std::make_unique<NullBackend>(std::move(getter));
}
Module::Interface::Interface(Core::System& system_, std::shared_ptr<Module> module_,
Module::Interface::Interface(Core::System& system_, std::shared_ptr<Module> interface_module,
FileSystem::FileSystemController& fsc_, const char* name)
: ServiceFramework(name), fsc{fsc_}, module{std::move(module_)},
: ServiceFramework(name), fsc{fsc_}, interface_module{std::move(interface_module)},
backend{CreateBackendFromSettings(system_,
[&fsc_](u64 tid) { return fsc_.GetBCATDirectory(tid); })},
system{system_} {}
@@ -589,14 +589,14 @@ Module::Interface::Interface(Core::System& system_, std::shared_ptr<Module> modu
Module::Interface::~Interface() = default;
void InstallInterfaces(Core::System& system) {
auto module = std::make_shared<Module>();
std::make_shared<BCAT>(system, module, system.GetFileSystemController(), "bcat:a")
auto interface_module = std::make_shared<Module>();
std::make_shared<BCAT>(system, interface_module, system.GetFileSystemController(), "bcat:a")
->InstallAsService(system.ServiceManager());
std::make_shared<BCAT>(system, module, system.GetFileSystemController(), "bcat:m")
std::make_shared<BCAT>(system, interface_module, system.GetFileSystemController(), "bcat:m")
->InstallAsService(system.ServiceManager());
std::make_shared<BCAT>(system, module, system.GetFileSystemController(), "bcat:u")
std::make_shared<BCAT>(system, interface_module, system.GetFileSystemController(), "bcat:u")
->InstallAsService(system.ServiceManager());
std::make_shared<BCAT>(system, module, system.GetFileSystemController(), "bcat:s")
std::make_shared<BCAT>(system, interface_module, system.GetFileSystemController(), "bcat:s")
->InstallAsService(system.ServiceManager());
}

View File

@@ -24,7 +24,7 @@ class Module final {
public:
class Interface : public ServiceFramework<Interface> {
public:
explicit Interface(Core::System& system_, std::shared_ptr<Module> module_,
explicit Interface(Core::System& system_, std::shared_ptr<Module> interface_module,
FileSystem::FileSystemController& fsc_, const char* name);
~Interface() override;
@@ -35,7 +35,7 @@ public:
protected:
FileSystem::FileSystemController& fsc;
std::shared_ptr<Module> module;
std::shared_ptr<Module> interface_module;
std::unique_ptr<Backend> backend;
private:

View File

@@ -20,8 +20,9 @@
namespace Service::Fatal {
Module::Interface::Interface(std::shared_ptr<Module> module, Core::System& system, const char* name)
: ServiceFramework(name), module(std::move(module)), system(system) {}
Module::Interface::Interface(std::shared_ptr<Module> interface_module, Core::System& system,
const char* name)
: ServiceFramework(name), interface_module(std::move(interface_module)), system(system) {}
Module::Interface::~Interface() = default;
@@ -75,7 +76,7 @@ static void GenerateErrorReport(Core::System& system, ResultCode error_code,
"Program entry point: 0x{:16X}\n"
"\n",
Common::g_scm_branch, Common::g_scm_desc, title_id, error_code.raw,
2000 + static_cast<u32>(error_code.module.Value()),
2000 + static_cast<u32>(error_code.error_module.Value()),
static_cast<u32>(error_code.description.Value()), info.set_flags, info.program_entry_point);
if (info.backtrace_size != 0x0) {
crash_report += "Registers:\n";
@@ -166,9 +167,9 @@ void Module::Interface::ThrowFatalWithCpuContext(Kernel::HLERequestContext& ctx)
}
void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system) {
auto module = std::make_shared<Module>();
std::make_shared<Fatal_P>(module, system)->InstallAsService(service_manager);
std::make_shared<Fatal_U>(module, system)->InstallAsService(service_manager);
auto interface_module = std::make_shared<Module>();
std::make_shared<Fatal_P>(interface_module, system)->InstallAsService(service_manager);
std::make_shared<Fatal_U>(interface_module, system)->InstallAsService(service_manager);
}
} // namespace Service::Fatal

View File

@@ -16,7 +16,8 @@ class Module final {
public:
class Interface : public ServiceFramework<Interface> {
public:
explicit Interface(std::shared_ptr<Module> module, Core::System& system, const char* name);
explicit Interface(std::shared_ptr<Module> interface_module, Core::System& system,
const char* name);
~Interface() override;
void ThrowFatal(Kernel::HLERequestContext& ctx);
@@ -24,7 +25,7 @@ public:
void ThrowFatalWithCpuContext(Kernel::HLERequestContext& ctx);
protected:
std::shared_ptr<Module> module;
std::shared_ptr<Module> interface_module;
Core::System& system;
};
};

View File

@@ -6,8 +6,8 @@
namespace Service::Fatal {
Fatal_P::Fatal_P(std::shared_ptr<Module> module, Core::System& system)
: Module::Interface(std::move(module), system, "fatal:p") {}
Fatal_P::Fatal_P(std::shared_ptr<Module> interface_module, Core::System& system)
: Module::Interface(std::move(interface_module), system, "fatal:p") {}
Fatal_P::~Fatal_P() = default;

View File

@@ -10,7 +10,7 @@ namespace Service::Fatal {
class Fatal_P final : public Module::Interface {
public:
explicit Fatal_P(std::shared_ptr<Module> module, Core::System& system);
explicit Fatal_P(std::shared_ptr<Module> interface_module, Core::System& system);
~Fatal_P() override;
};

View File

@@ -6,8 +6,8 @@
namespace Service::Fatal {
Fatal_U::Fatal_U(std::shared_ptr<Module> module, Core::System& system)
: Module::Interface(std::move(module), system, "fatal:u") {
Fatal_U::Fatal_U(std::shared_ptr<Module> interface_module, Core::System& system)
: Module::Interface(std::move(interface_module), system, "fatal:u") {
static const FunctionInfo functions[] = {
{0, &Fatal_U::ThrowFatal, "ThrowFatal"},
{1, &Fatal_U::ThrowFatalWithPolicy, "ThrowFatalWithPolicy"},

View File

@@ -10,7 +10,7 @@ namespace Service::Fatal {
class Fatal_U final : public Module::Interface {
public:
explicit Fatal_U(std::shared_ptr<Module> module, Core::System& system);
explicit Fatal_U(std::shared_ptr<Module> interface_module, Core::System& system);
~Fatal_U() override;
};

View File

@@ -281,18 +281,24 @@ void Module::Interface::CreateNotificationService(Kernel::HLERequestContext& ctx
rb.PushIpcInterface<INotificationService>(uuid, system);
}
Module::Interface::Interface(std::shared_ptr<Module> module, Core::System& system, const char* name)
: ServiceFramework(name), module(std::move(module)), system(system) {}
Module::Interface::Interface(std::shared_ptr<Module> interface_module, Core::System& system,
const char* name)
: ServiceFramework(name), interface_module(std::move(interface_module)), system(system) {}
Module::Interface::~Interface() = default;
void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system) {
auto module = std::make_shared<Module>();
std::make_shared<Friend>(module, system, "friend:a")->InstallAsService(service_manager);
std::make_shared<Friend>(module, system, "friend:m")->InstallAsService(service_manager);
std::make_shared<Friend>(module, system, "friend:s")->InstallAsService(service_manager);
std::make_shared<Friend>(module, system, "friend:u")->InstallAsService(service_manager);
std::make_shared<Friend>(module, system, "friend:v")->InstallAsService(service_manager);
auto interface_module = std::make_shared<Module>();
std::make_shared<Friend>(interface_module, system, "friend:a")
->InstallAsService(service_manager);
std::make_shared<Friend>(interface_module, system, "friend:m")
->InstallAsService(service_manager);
std::make_shared<Friend>(interface_module, system, "friend:s")
->InstallAsService(service_manager);
std::make_shared<Friend>(interface_module, system, "friend:u")
->InstallAsService(service_manager);
std::make_shared<Friend>(interface_module, system, "friend:v")
->InstallAsService(service_manager);
}
} // namespace Service::Friend

View File

@@ -16,14 +16,15 @@ class Module final {
public:
class Interface : public ServiceFramework<Interface> {
public:
explicit Interface(std::shared_ptr<Module> module, Core::System& system, const char* name);
explicit Interface(std::shared_ptr<Module> interface_module, Core::System& system,
const char* name);
~Interface() override;
void CreateFriendService(Kernel::HLERequestContext& ctx);
void CreateNotificationService(Kernel::HLERequestContext& ctx);
protected:
std::shared_ptr<Module> module;
std::shared_ptr<Module> interface_module;
Core::System& system;
};
};

View File

@@ -6,8 +6,8 @@
namespace Service::Friend {
Friend::Friend(std::shared_ptr<Module> module, Core::System& system, const char* name)
: Interface(std::move(module), system, name) {
Friend::Friend(std::shared_ptr<Module> interface_module, Core::System& system, const char* name)
: Interface(std::move(interface_module), system, name) {
static const FunctionInfo functions[] = {
{0, &Friend::CreateFriendService, "CreateFriendService"},
{1, &Friend::CreateNotificationService, "CreateNotificationService"},

View File

@@ -10,7 +10,8 @@ namespace Service::Friend {
class Friend final : public Module::Interface {
public:
explicit Friend(std::shared_ptr<Module> module, Core::System& system, const char* name);
explicit Friend(std::shared_ptr<Module> interface_module, Core::System& system,
const char* name);
~Friend() override;
};

View File

@@ -250,6 +250,9 @@ void Controller_NPad::OnLoadInputDevices() {
std::transform(players[i].analogs.begin() + Settings::NativeAnalog::STICK_HID_BEGIN,
players[i].analogs.begin() + Settings::NativeAnalog::STICK_HID_END,
sticks[i].begin(), Input::CreateDevice<Input::AnalogDevice>);
std::transform(players[i].motions.begin() + Settings::NativeMotion::MOTION_HID_BEGIN,
players[i].motions.begin() + Settings::NativeMotion::MOTION_HID_END,
motions[i].begin(), Input::CreateDevice<Input::MotionDevice>);
}
}
@@ -266,6 +269,7 @@ void Controller_NPad::RequestPadStateUpdate(u32 npad_id) {
auto& rstick_entry = npad_pad_states[controller_idx].r_stick;
const auto& button_state = buttons[controller_idx];
const auto& analog_state = sticks[controller_idx];
const auto& motion_state = motions[controller_idx];
const auto [stick_l_x_f, stick_l_y_f] =
analog_state[static_cast<std::size_t>(JoystickId::Joystick_Left)]->GetStatus();
const auto [stick_r_x_f, stick_r_y_f] =
@@ -360,6 +364,45 @@ void Controller_NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8*
continue;
}
const u32 npad_index = static_cast<u32>(i);
const std::array<SixAxisGeneric*, 6> controller_sixaxes{
&npad.sixaxis_full, &npad.sixaxis_handheld, &npad.sixaxis_dual_left,
&npad.sixaxis_dual_right, &npad.sixaxis_left, &npad.sixaxis_right,
};
for (auto* sixaxis_sensor : controller_sixaxes) {
sixaxis_sensor->common.entry_count = 16;
sixaxis_sensor->common.total_entry_count = 17;
const auto& last_entry =
sixaxis_sensor->sixaxis[sixaxis_sensor->common.last_entry_index];
sixaxis_sensor->common.timestamp = core_timing.GetCPUTicks();
sixaxis_sensor->common.last_entry_index =
(sixaxis_sensor->common.last_entry_index + 1) % 17;
auto& cur_entry = sixaxis_sensor->sixaxis[sixaxis_sensor->common.last_entry_index];
cur_entry.timestamp = last_entry.timestamp + 1;
cur_entry.timestamp2 = cur_entry.timestamp;
}
// Try to read sixaxis sensor states
std::array<MotionDevice, 2> motion_devices;
if (sixaxis_sensors_enabled && Settings::values.motion_enabled) {
sixaxis_at_rest = true;
for (std::size_t e = 0; e < motion_devices.size(); ++e) {
const auto& device = motions[i][e];
if (device) {
std::tie(motion_devices[e].accel, motion_devices[e].gyro,
motion_devices[e].rotation, motion_devices[e].orientation) =
device->GetStatus();
sixaxis_at_rest = sixaxis_at_rest && motion_devices[e].gyro.Length2() < 0.0001f;
}
}
}
RequestPadStateUpdate(npad_index);
auto& pad_state = npad_pad_states[npad_index];
@@ -377,6 +420,18 @@ void Controller_NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8*
libnx_entry.connection_status.raw = 0;
libnx_entry.connection_status.IsConnected.Assign(1);
auto& full_sixaxis_entry =
npad.sixaxis_full.sixaxis[npad.sixaxis_full.common.last_entry_index];
auto& handheld_sixaxis_entry =
npad.sixaxis_handheld.sixaxis[npad.sixaxis_handheld.common.last_entry_index];
auto& dual_left_sixaxis_entry =
npad.sixaxis_dual_left.sixaxis[npad.sixaxis_dual_left.common.last_entry_index];
auto& dual_right_sixaxis_entry =
npad.sixaxis_dual_right.sixaxis[npad.sixaxis_dual_right.common.last_entry_index];
auto& left_sixaxis_entry =
npad.sixaxis_left.sixaxis[npad.sixaxis_left.common.last_entry_index];
auto& right_sixaxis_entry =
npad.sixaxis_right.sixaxis[npad.sixaxis_right.common.last_entry_index];
switch (controller_type) {
case NPadControllerType::None:
@@ -391,6 +446,13 @@ void Controller_NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8*
main_controller.pad.r_stick = pad_state.r_stick;
libnx_entry.connection_status.IsWired.Assign(1);
if (sixaxis_sensors_enabled && motions[i][0]) {
full_sixaxis_entry.accel = motion_devices[0].accel;
full_sixaxis_entry.gyro = motion_devices[0].gyro;
full_sixaxis_entry.rotation = motion_devices[0].rotation;
full_sixaxis_entry.orientation = motion_devices[0].orientation;
}
break;
case NPadControllerType::Handheld:
handheld_entry.connection_status.raw = 0;
@@ -409,6 +471,13 @@ void Controller_NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8*
libnx_entry.connection_status.IsRightJoyConnected.Assign(1);
libnx_entry.connection_status.IsLeftJoyWired.Assign(1);
libnx_entry.connection_status.IsRightJoyWired.Assign(1);
if (sixaxis_sensors_enabled && motions[i][0]) {
handheld_sixaxis_entry.accel = motion_devices[0].accel;
handheld_sixaxis_entry.gyro = motion_devices[0].gyro;
handheld_sixaxis_entry.rotation = motion_devices[0].rotation;
handheld_sixaxis_entry.orientation = motion_devices[0].orientation;
}
break;
case NPadControllerType::JoyDual:
dual_entry.connection_status.raw = 0;
@@ -421,6 +490,21 @@ void Controller_NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8*
libnx_entry.connection_status.IsLeftJoyConnected.Assign(1);
libnx_entry.connection_status.IsRightJoyConnected.Assign(1);
if (sixaxis_sensors_enabled && motions[i][0]) {
// Set motion for the left joycon
dual_left_sixaxis_entry.accel = motion_devices[0].accel;
dual_left_sixaxis_entry.gyro = motion_devices[0].gyro;
dual_left_sixaxis_entry.rotation = motion_devices[0].rotation;
dual_left_sixaxis_entry.orientation = motion_devices[0].orientation;
}
if (sixaxis_sensors_enabled && motions[i][1]) {
// Set motion for the right joycon
dual_right_sixaxis_entry.accel = motion_devices[1].accel;
dual_right_sixaxis_entry.gyro = motion_devices[1].gyro;
dual_right_sixaxis_entry.rotation = motion_devices[1].rotation;
dual_right_sixaxis_entry.orientation = motion_devices[1].orientation;
}
break;
case NPadControllerType::JoyLeft:
left_entry.connection_status.raw = 0;
@@ -431,6 +515,13 @@ void Controller_NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8*
left_entry.pad.r_stick = pad_state.r_stick;
libnx_entry.connection_status.IsLeftJoyConnected.Assign(1);
if (sixaxis_sensors_enabled && motions[i][0]) {
left_sixaxis_entry.accel = motion_devices[0].accel;
left_sixaxis_entry.gyro = motion_devices[0].gyro;
left_sixaxis_entry.rotation = motion_devices[0].rotation;
left_sixaxis_entry.orientation = motion_devices[0].orientation;
}
break;
case NPadControllerType::JoyRight:
right_entry.connection_status.raw = 0;
@@ -441,6 +532,13 @@ void Controller_NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8*
right_entry.pad.r_stick = pad_state.r_stick;
libnx_entry.connection_status.IsRightJoyConnected.Assign(1);
if (sixaxis_sensors_enabled && motions[i][1]) {
right_sixaxis_entry.accel = motion_devices[1].accel;
right_sixaxis_entry.gyro = motion_devices[1].gyro;
right_sixaxis_entry.rotation = motion_devices[1].rotation;
right_sixaxis_entry.orientation = motion_devices[1].orientation;
}
break;
case NPadControllerType::Pokeball:
pokeball_entry.connection_status.raw = 0;
@@ -582,6 +680,14 @@ Controller_NPad::GyroscopeZeroDriftMode Controller_NPad::GetGyroscopeZeroDriftMo
return gyroscope_zero_drift_mode;
}
bool Controller_NPad::IsSixAxisSensorAtRest() const {
return sixaxis_at_rest;
}
void Controller_NPad::SetSixAxisEnabled(bool six_axis_status) {
sixaxis_sensors_enabled = six_axis_status;
}
void Controller_NPad::MergeSingleJoyAsDualJoy(u32 npad_id_1, u32 npad_id_2) {
const auto npad_index_1 = NPadIdToIndex(npad_id_1);
const auto npad_index_2 = NPadIdToIndex(npad_id_2);

View File

@@ -130,6 +130,8 @@ public:
void SetGyroscopeZeroDriftMode(GyroscopeZeroDriftMode drift_mode);
GyroscopeZeroDriftMode GetGyroscopeZeroDriftMode() const;
bool IsSixAxisSensorAtRest() const;
void SetSixAxisEnabled(bool six_axis_status);
LedPattern GetLedPattern(u32 npad_id);
void SetVibrationEnabled(bool can_vibrate);
bool IsVibrationEnabled() const;
@@ -252,6 +254,24 @@ private:
};
static_assert(sizeof(NPadGeneric) == 0x350, "NPadGeneric is an invalid size");
struct SixAxisStates {
s64_le timestamp{};
INSERT_PADDING_WORDS(2);
s64_le timestamp2{};
Common::Vec3f accel{};
Common::Vec3f gyro{};
Common::Vec3f rotation{};
std::array<Common::Vec3f, 3> orientation{};
s64_le always_one{1};
};
static_assert(sizeof(SixAxisStates) == 0x68, "SixAxisStates is an invalid size");
struct SixAxisGeneric {
CommonHeader common{};
std::array<SixAxisStates, 17> sixaxis{};
};
static_assert(sizeof(SixAxisGeneric) == 0x708, "SixAxisGeneric is an invalid size");
enum class ColorReadError : u32_le {
ReadOk = 0,
ColorDoesntExist = 1,
@@ -281,6 +301,13 @@ private:
};
};
struct MotionDevice {
Common::Vec3f accel;
Common::Vec3f gyro;
Common::Vec3f rotation;
std::array<Common::Vec3f, 3> orientation;
};
struct NPadEntry {
NPadType joy_styles;
NPadAssignments pad_assignment;
@@ -300,9 +327,12 @@ private:
NPadGeneric pokeball_states;
NPadGeneric libnx; // TODO(ogniK): Find out what this actually is, libnx seems to only be
// relying on this for the time being
INSERT_PADDING_BYTES(
0x708 *
6); // TODO(ogniK): SixAxis states, require more information before implementation
SixAxisGeneric sixaxis_full;
SixAxisGeneric sixaxis_handheld;
SixAxisGeneric sixaxis_dual_left;
SixAxisGeneric sixaxis_dual_right;
SixAxisGeneric sixaxis_left;
SixAxisGeneric sixaxis_right;
NPadDevice device_type;
NPadProperties properties;
INSERT_PADDING_WORDS(1);
@@ -325,14 +355,18 @@ private:
NPadType style{};
std::array<NPadEntry, 10> shared_memory_entries{};
std::array<
using ButtonArray = std::array<
std::array<std::unique_ptr<Input::ButtonDevice>, Settings::NativeButton::NUM_BUTTONS_HID>,
10>
buttons;
std::array<
10>;
using StickArray = std::array<
std::array<std::unique_ptr<Input::AnalogDevice>, Settings::NativeAnalog::NUM_STICKS_HID>,
10>
sticks;
10>;
using MotionArray = std::array<
std::array<std::unique_ptr<Input::MotionDevice>, Settings::NativeMotion::NUM_MOTION_HID>,
10>;
ButtonArray buttons;
StickArray sticks;
MotionArray motions;
std::vector<u32> supported_npad_id_types{};
NpadHoldType hold_type{NpadHoldType::Vertical};
// Each controller should have their own styleset changed event
@@ -341,6 +375,8 @@ private:
std::array<ControllerHolder, 10> connected_controllers{};
GyroscopeZeroDriftMode gyroscope_zero_drift_mode{GyroscopeZeroDriftMode::Standard};
bool can_controllers_vibrate{true};
bool sixaxis_sensors_enabled{true};
bool sixaxis_at_rest{true};
std::array<ControllerPad, 10> npad_pad_states{};
bool is_in_lr_assignment_mode{false};
Core::System& system;

View File

@@ -40,7 +40,7 @@ namespace Service::HID {
// Updating period for each HID device.
// HID is polled every 15ms, this value was derived from
// https://github.com/dekuNukem/Nintendo_Switch_Reverse_Engineering#joy-con-status-data-packet
constexpr auto pad_update_ns = std::chrono::nanoseconds{15 * 1000 * 1000}; // (15ms, 66.6Hz)
constexpr auto pad_update_ns = std::chrono::nanoseconds{1000 * 1000}; // (1ms, 1000Hz)
constexpr std::size_t SHARED_MEMORY_SIZE = 0x40000;
IAppletResource::IAppletResource(Core::System& system)
@@ -164,8 +164,8 @@ Hid::Hid(Core::System& system) : ServiceFramework("hid"), system(system) {
{56, nullptr, "ActivateJoyXpad"},
{58, nullptr, "GetJoyXpadLifoHandle"},
{59, nullptr, "GetJoyXpadIds"},
{60, nullptr, "ActivateSixAxisSensor"},
{61, nullptr, "DeactivateSixAxisSensor"},
{60, &Hid::ActivateSixAxisSensor, "ActivateSixAxisSensor"},
{61, &Hid::DeactivateSixAxisSensor, "DeactivateSixAxisSensor"},
{62, nullptr, "GetSixAxisSensorLifoHandle"},
{63, nullptr, "ActivateJoySixAxisSensor"},
{64, nullptr, "DeactivateJoySixAxisSensor"},
@@ -329,6 +329,31 @@ void Hid::GetXpadIDs(Kernel::HLERequestContext& ctx) {
rb.Push(0);
}
void Hid::ActivateSixAxisSensor(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto handle{rp.Pop<u32>()};
const auto applet_resource_user_id{rp.Pop<u64>()};
applet_resource->GetController<Controller_NPad>(HidController::NPad).SetSixAxisEnabled(true);
LOG_DEBUG(Service_HID, "called, handle={}, applet_resource_user_id={}", handle,
applet_resource_user_id);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
}
void Hid::DeactivateSixAxisSensor(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto handle{rp.Pop<u32>()};
const auto applet_resource_user_id{rp.Pop<u64>()};
applet_resource->GetController<Controller_NPad>(HidController::NPad).SetSixAxisEnabled(false);
LOG_DEBUG(Service_HID, "called, handle={}, applet_resource_user_id={}", handle,
applet_resource_user_id);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(RESULT_SUCCESS);
}
void Hid::ActivateDebugPad(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto applet_resource_user_id{rp.Pop<u64>()};
@@ -484,13 +509,13 @@ void Hid::IsSixAxisSensorAtRest(Kernel::HLERequestContext& ctx) {
const auto handle{rp.Pop<u32>()};
const auto applet_resource_user_id{rp.Pop<u64>()};
LOG_WARNING(Service_HID, "(STUBBED) called, handle={}, applet_resource_user_id={}", handle,
applet_resource_user_id);
LOG_DEBUG(Service_HID, "called, handle={}, applet_resource_user_id={}", handle,
applet_resource_user_id);
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(RESULT_SUCCESS);
// TODO (Hexagon12): Properly implement reading gyroscope values from controllers.
rb.Push(true);
rb.Push(applet_resource->GetController<Controller_NPad>(HidController::NPad)
.IsSixAxisSensorAtRest());
}
void Hid::SetSupportedNpadStyleSet(Kernel::HLERequestContext& ctx) {

View File

@@ -86,6 +86,8 @@ private:
void CreateAppletResource(Kernel::HLERequestContext& ctx);
void ActivateXpad(Kernel::HLERequestContext& ctx);
void GetXpadIDs(Kernel::HLERequestContext& ctx);
void ActivateSixAxisSensor(Kernel::HLERequestContext& ctx);
void DeactivateSixAxisSensor(Kernel::HLERequestContext& ctx);
void ActivateDebugPad(Kernel::HLERequestContext& ctx);
void ActivateTouchScreen(Kernel::HLERequestContext& ctx);
void ActivateMouse(Kernel::HLERequestContext& ctx);

View File

@@ -2,6 +2,7 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include <array>
#include <atomic>
#include "common/logging/log.h"
@@ -20,8 +21,9 @@ namespace ErrCodes {
constexpr ResultCode ERR_NO_APPLICATION_AREA(ErrorModule::NFP, 152);
} // namespace ErrCodes
Module::Interface::Interface(std::shared_ptr<Module> module, Core::System& system, const char* name)
: ServiceFramework(name), module(std::move(module)), system(system) {
Module::Interface::Interface(std::shared_ptr<Module> interface_module, Core::System& system,
const char* name)
: ServiceFramework(name), interface_module(std::move(interface_module)), system(system) {
auto& kernel = system.Kernel();
nfc_tag_load = Kernel::WritableEvent::CreateEventPair(kernel, "IUser:NFCTagDetected");
}
@@ -72,10 +74,10 @@ private:
std::array<u8, 10> uuid;
u8 uuid_length; // TODO(ogniK): Figure out if this is actual the uuid length or does it
// mean something else
INSERT_PADDING_BYTES(0x15);
std::array<u8, 0x15> padding_1;
u32_le protocol;
u32_le tag_type;
INSERT_PADDING_BYTES(0x2c);
std::array<u8, 0x2c> padding_2;
};
static_assert(sizeof(TagInfo) == 0x54, "TagInfo is an invalid size");
@@ -213,13 +215,15 @@ private:
LOG_DEBUG(Service_NFP, "called");
IPC::ResponseBuilder rb{ctx, 2};
auto amiibo = nfp_interface.GetAmiiboBuffer();
TagInfo tag_info{};
tag_info.uuid = amiibo.uuid;
tag_info.uuid_length = static_cast<u8>(tag_info.uuid.size());
tag_info.protocol = 1; // TODO(ogniK): Figure out actual values
tag_info.tag_type = 2;
const auto& amiibo = nfp_interface.GetAmiiboBuffer();
const TagInfo tag_info{
.uuid = amiibo.uuid,
.uuid_length = static_cast<u8>(tag_info.uuid.size()),
.padding_1 = {},
.protocol = 1, // TODO(ogniK): Figure out actual values
.tag_type = 2,
.padding_2 = {},
};
ctx.WriteBuffer(tag_info);
rb.Push(RESULT_SUCCESS);
}
@@ -236,7 +240,7 @@ private:
LOG_DEBUG(Service_NFP, "called");
IPC::ResponseBuilder rb{ctx, 2};
auto amiibo = nfp_interface.GetAmiiboBuffer();
const auto& amiibo = nfp_interface.GetAmiiboBuffer();
ctx.WriteBuffer(amiibo.model_info);
rb.Push(RESULT_SUCCESS);
}
@@ -351,8 +355,8 @@ const Module::Interface::AmiiboFile& Module::Interface::GetAmiiboBuffer() const
}
void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system) {
auto module = std::make_shared<Module>();
std::make_shared<NFP_User>(module, system)->InstallAsService(service_manager);
auto interface_module = std::make_shared<Module>();
std::make_shared<NFP_User>(interface_module, system)->InstallAsService(service_manager);
}
} // namespace Service::NFP

View File

@@ -16,7 +16,8 @@ class Module final {
public:
class Interface : public ServiceFramework<Interface> {
public:
explicit Interface(std::shared_ptr<Module> module, Core::System& system, const char* name);
explicit Interface(std::shared_ptr<Module> interface_module, Core::System& system,
const char* name);
~Interface() override;
struct ModelInfo {
@@ -42,7 +43,7 @@ public:
AmiiboFile amiibo{};
protected:
std::shared_ptr<Module> module;
std::shared_ptr<Module> interface_module;
Core::System& system;
};
};

View File

@@ -6,8 +6,8 @@
namespace Service::NFP {
NFP_User::NFP_User(std::shared_ptr<Module> module, Core::System& system)
: Module::Interface(std::move(module), system, "nfp:user") {
NFP_User::NFP_User(std::shared_ptr<Module> interface_module, Core::System& system)
: Module::Interface(std::move(interface_module), system, "nfp:user") {
static const FunctionInfo functions[] = {
{0, &NFP_User::CreateUserInterface, "CreateUserInterface"},
};

View File

@@ -10,7 +10,7 @@ namespace Service::NFP {
class NFP_User final : public Module::Interface {
public:
explicit NFP_User(std::shared_ptr<Module> module, Core::System& system);
explicit NFP_User(std::shared_ptr<Module> interface_module, Core::System& system);
~NFP_User() override;
};

View File

@@ -148,17 +148,17 @@ void Module::Interface::CreateServiceWithoutInitialize(Kernel::HLERequestContext
rb.PushIpcInterface<IParentalControlService>();
}
Module::Interface::Interface(std::shared_ptr<Module> module, const char* name)
: ServiceFramework(name), module(std::move(module)) {}
Module::Interface::Interface(std::shared_ptr<Module> interface_module, const char* name)
: ServiceFramework(name), interface_module(std::move(interface_module)) {}
Module::Interface::~Interface() = default;
void InstallInterfaces(SM::ServiceManager& service_manager) {
auto module = std::make_shared<Module>();
std::make_shared<PCTL>(module, "pctl")->InstallAsService(service_manager);
std::make_shared<PCTL>(module, "pctl:a")->InstallAsService(service_manager);
std::make_shared<PCTL>(module, "pctl:r")->InstallAsService(service_manager);
std::make_shared<PCTL>(module, "pctl:s")->InstallAsService(service_manager);
auto interface_module = std::make_shared<Module>();
std::make_shared<PCTL>(interface_module, "pctl")->InstallAsService(service_manager);
std::make_shared<PCTL>(interface_module, "pctl:a")->InstallAsService(service_manager);
std::make_shared<PCTL>(interface_module, "pctl:r")->InstallAsService(service_manager);
std::make_shared<PCTL>(interface_module, "pctl:s")->InstallAsService(service_manager);
}
} // namespace Service::PCTL

View File

@@ -12,14 +12,14 @@ class Module final {
public:
class Interface : public ServiceFramework<Interface> {
public:
explicit Interface(std::shared_ptr<Module> module, const char* name);
explicit Interface(std::shared_ptr<Module> interface_module, const char* name);
~Interface() override;
void CreateService(Kernel::HLERequestContext& ctx);
void CreateServiceWithoutInitialize(Kernel::HLERequestContext& ctx);
protected:
std::shared_ptr<Module> module;
std::shared_ptr<Module> interface_module;
};
};

View File

@@ -6,8 +6,8 @@
namespace Service::PCTL {
PCTL::PCTL(std::shared_ptr<Module> module, const char* name)
: Module::Interface(std::move(module), name) {
PCTL::PCTL(std::shared_ptr<Module> interface_module, const char* name)
: Module::Interface(std::move(interface_module), name) {
static const FunctionInfo functions[] = {
{0, &PCTL::CreateService, "CreateService"},
{1, &PCTL::CreateServiceWithoutInitialize, "CreateServiceWithoutInitialize"},

View File

@@ -10,7 +10,7 @@ namespace Service::PCTL {
class PCTL final : public Module::Interface {
public:
explicit PCTL(std::shared_ptr<Module> module, const char* name);
explicit PCTL(std::shared_ptr<Module> interface_module, const char* name);
~PCTL() override;
};

View File

@@ -72,25 +72,6 @@
namespace Service {
/**
* Creates a function string for logging, complete with the name (or header code, depending
* on what's passed in) the port name, and all the cmd_buff arguments.
*/
[[maybe_unused]] static std::string MakeFunctionString(std::string_view name,
std::string_view port_name,
const u32* cmd_buff) {
// Number of params == bits 0-5 + bits 6-11
int num_params = (cmd_buff[0] & 0x3F) + ((cmd_buff[0] >> 6) & 0x3F);
std::string function_string = fmt::format("function '{}': port={}", name, port_name);
for (int i = 1; i <= num_params; ++i) {
function_string += fmt::format(", cmd_buff[{}]=0x{:X}", i, cmd_buff[i]);
}
return function_string;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
ServiceFrameworkBase::ServiceFrameworkBase(const char* service_name, u32 max_sessions,
InvokerFn* handler_invoker)
: service_name(service_name), max_sessions(max_sessions), handler_invoker(handler_invoker) {}
@@ -189,9 +170,6 @@ ResultCode ServiceFrameworkBase::HandleSyncRequest(Kernel::HLERequestContext& co
return RESULT_SUCCESS;
}
////////////////////////////////////////////////////////////////////////////////////////////////////
// Module interface
/// Initialize ServiceManager
void Init(std::shared_ptr<SM::ServiceManager>& sm, Core::System& system) {
// NVFlinger needs to be accessed by several services like Vi and AppletOE so we instantiate it

View File

@@ -19,7 +19,7 @@ constexpr ResultCode ERR_ALREADY_REGISTERED(ErrorModule::SM, 4);
constexpr ResultCode ERR_INVALID_NAME(ErrorModule::SM, 6);
constexpr ResultCode ERR_SERVICE_NOT_REGISTERED(ErrorModule::SM, 7);
ServiceManager::ServiceManager() = default;
ServiceManager::ServiceManager(Kernel::KernelCore& kernel_) : kernel{kernel_} {}
ServiceManager::~ServiceManager() = default;
void ServiceManager::InvokeControlRequest(Kernel::HLERequestContext& context) {
@@ -27,11 +27,11 @@ void ServiceManager::InvokeControlRequest(Kernel::HLERequestContext& context) {
}
static ResultCode ValidateServiceName(const std::string& name) {
if (name.size() <= 0 || name.size() > 8) {
if (name.empty() || name.size() > 8) {
LOG_ERROR(Service_SM, "Invalid service name! service={}", name);
return ERR_INVALID_NAME;
}
if (name.find('\0') != std::string::npos) {
if (name.rfind('\0') != std::string::npos) {
LOG_ERROR(Service_SM, "A non null terminated service was passed");
return ERR_INVALID_NAME;
}
@@ -48,8 +48,8 @@ void ServiceManager::InstallInterfaces(std::shared_ptr<ServiceManager> self,
self->controller_interface = std::make_unique<Controller>();
}
ResultVal<std::shared_ptr<Kernel::ServerPort>> ServiceManager::RegisterService(
std::string name, unsigned int max_sessions) {
ResultVal<std::shared_ptr<Kernel::ServerPort>> ServiceManager::RegisterService(std::string name,
u32 max_sessions) {
CASCADE_CODE(ValidateServiceName(name));
@@ -58,7 +58,6 @@ ResultVal<std::shared_ptr<Kernel::ServerPort>> ServiceManager::RegisterService(
return ERR_ALREADY_REGISTERED;
}
auto& kernel = Core::System::GetInstance().Kernel();
auto [server_port, client_port] =
Kernel::ServerPort::CreatePortPair(kernel, max_sessions, name);

View File

@@ -48,11 +48,11 @@ class ServiceManager {
public:
static void InstallInterfaces(std::shared_ptr<ServiceManager> self, Kernel::KernelCore& kernel);
ServiceManager();
explicit ServiceManager(Kernel::KernelCore& kernel_);
~ServiceManager();
ResultVal<std::shared_ptr<Kernel::ServerPort>> RegisterService(std::string name,
unsigned int max_sessions);
u32 max_sessions);
ResultCode UnregisterService(const std::string& name);
ResultVal<std::shared_ptr<Kernel::ClientPort>> GetServicePort(const std::string& name);
ResultVal<std::shared_ptr<Kernel::ClientSession>> ConnectToService(const std::string& name);
@@ -79,6 +79,9 @@ private:
/// Map of registered services, retrieved using GetServicePort or ConnectToService.
std::unordered_map<std::string, std::shared_ptr<Kernel::ClientPort>> registered_services;
/// Kernel context
Kernel::KernelCore& kernel;
};
} // namespace Service::SM

View File

@@ -6,7 +6,8 @@
namespace Service::SPL {
CSRNG::CSRNG(std::shared_ptr<Module> module) : Module::Interface(std::move(module), "csrng") {
CSRNG::CSRNG(std::shared_ptr<Module> interface_module)
: Module::Interface(std::move(interface_module), "csrng") {
static const FunctionInfo functions[] = {
{0, &CSRNG::GetRandomBytes, "GetRandomBytes"},
};

View File

@@ -10,7 +10,7 @@ namespace Service::SPL {
class CSRNG final : public Module::Interface {
public:
explicit CSRNG(std::shared_ptr<Module> module);
explicit CSRNG(std::shared_ptr<Module> interface_module);
~CSRNG() override;
};

View File

@@ -17,8 +17,8 @@
namespace Service::SPL {
Module::Interface::Interface(std::shared_ptr<Module> module, const char* name)
: ServiceFramework(name), module(std::move(module)),
Module::Interface::Interface(std::shared_ptr<Module> interface_module, const char* name)
: ServiceFramework(name), interface_module(std::move(interface_module)),
rng(Settings::values.rng_seed.GetValue().value_or(std::time(nullptr))) {}
Module::Interface::~Interface() = default;
@@ -39,9 +39,9 @@ void Module::Interface::GetRandomBytes(Kernel::HLERequestContext& ctx) {
}
void InstallInterfaces(SM::ServiceManager& service_manager) {
auto module = std::make_shared<Module>();
std::make_shared<CSRNG>(module)->InstallAsService(service_manager);
std::make_shared<SPL>(module)->InstallAsService(service_manager);
auto interface_module = std::make_shared<Module>();
std::make_shared<CSRNG>(interface_module)->InstallAsService(service_manager);
std::make_shared<SPL>(interface_module)->InstallAsService(service_manager);
}
} // namespace Service::SPL

View File

@@ -13,13 +13,13 @@ class Module final {
public:
class Interface : public ServiceFramework<Interface> {
public:
explicit Interface(std::shared_ptr<Module> module, const char* name);
explicit Interface(std::shared_ptr<Module> interface_module, const char* name);
~Interface() override;
void GetRandomBytes(Kernel::HLERequestContext& ctx);
protected:
std::shared_ptr<Module> module;
std::shared_ptr<Module> interface_module;
private:
std::mt19937 rng;

View File

@@ -6,7 +6,8 @@
namespace Service::SPL {
SPL::SPL(std::shared_ptr<Module> module) : Module::Interface(std::move(module), "spl:") {
SPL::SPL(std::shared_ptr<Module> interface_module)
: Module::Interface(std::move(interface_module), "spl:") {
static const FunctionInfo functions[] = {
{0, nullptr, "GetConfig"},
{1, nullptr, "ModularExponentiate"},

View File

@@ -6,8 +6,8 @@
namespace Service::Time {
Time::Time(std::shared_ptr<Module> module, Core::System& system, const char* name)
: Module::Interface(std::move(module), system, name) {
Time::Time(std::shared_ptr<Module> interface_module, Core::System& system, const char* name)
: Module::Interface(std::move(interface_module), system, name) {
// clang-format off
static const FunctionInfo functions[] = {
{0, &Time::GetStandardUserSystemClock, "GetStandardUserSystemClock"},

View File

@@ -125,7 +125,7 @@ ResultCode Module::Interface::GetClockSnapshotFromSystemClockContextInternal(
Kernel::Thread* thread, Clock::SystemClockContext user_context,
Clock::SystemClockContext network_context, u8 type, Clock::ClockSnapshot& clock_snapshot) {
auto& time_manager{module->GetTimeManager()};
auto& time_manager{interface_module->GetTimeManager()};
clock_snapshot.is_automatic_correction_enabled =
time_manager.GetStandardUserSystemClockCore().IsAutomaticCorrectionEnabled();
@@ -182,45 +182,46 @@ void Module::Interface::GetStandardUserSystemClock(Kernel::HLERequestContext& ct
LOG_DEBUG(Service_Time, "called");
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<ISystemClock>(module->GetTimeManager().GetStandardUserSystemClockCore(),
system);
rb.PushIpcInterface<ISystemClock>(
interface_module->GetTimeManager().GetStandardUserSystemClockCore(), system);
}
void Module::Interface::GetStandardNetworkSystemClock(Kernel::HLERequestContext& ctx) {
LOG_DEBUG(Service_Time, "called");
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<ISystemClock>(module->GetTimeManager().GetStandardNetworkSystemClockCore(),
system);
rb.PushIpcInterface<ISystemClock>(
interface_module->GetTimeManager().GetStandardNetworkSystemClockCore(), system);
}
void Module::Interface::GetStandardSteadyClock(Kernel::HLERequestContext& ctx) {
LOG_DEBUG(Service_Time, "called");
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<ISteadyClock>(module->GetTimeManager().GetStandardSteadyClockCore(),
system);
rb.PushIpcInterface<ISteadyClock>(
interface_module->GetTimeManager().GetStandardSteadyClockCore(), system);
}
void Module::Interface::GetTimeZoneService(Kernel::HLERequestContext& ctx) {
LOG_DEBUG(Service_Time, "called");
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<ITimeZoneService>(module->GetTimeManager().GetTimeZoneContentManager());
rb.PushIpcInterface<ITimeZoneService>(
interface_module->GetTimeManager().GetTimeZoneContentManager());
}
void Module::Interface::GetStandardLocalSystemClock(Kernel::HLERequestContext& ctx) {
LOG_DEBUG(Service_Time, "called");
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(RESULT_SUCCESS);
rb.PushIpcInterface<ISystemClock>(module->GetTimeManager().GetStandardLocalSystemClockCore(),
system);
rb.PushIpcInterface<ISystemClock>(
interface_module->GetTimeManager().GetStandardLocalSystemClockCore(), system);
}
void Module::Interface::IsStandardNetworkSystemClockAccuracySufficient(
Kernel::HLERequestContext& ctx) {
LOG_DEBUG(Service_Time, "called");
auto& clock_core{module->GetTimeManager().GetStandardNetworkSystemClockCore()};
auto& clock_core{interface_module->GetTimeManager().GetStandardNetworkSystemClockCore()};
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(RESULT_SUCCESS);
rb.Push<u32>(clock_core.IsStandardNetworkSystemClockAccuracySufficient(system));
@@ -229,7 +230,7 @@ void Module::Interface::IsStandardNetworkSystemClockAccuracySufficient(
void Module::Interface::CalculateMonotonicSystemClockBaseTimePoint(Kernel::HLERequestContext& ctx) {
LOG_DEBUG(Service_Time, "called");
auto& steady_clock_core{module->GetTimeManager().GetStandardSteadyClockCore()};
auto& steady_clock_core{interface_module->GetTimeManager().GetStandardSteadyClockCore()};
if (!steady_clock_core.IsInitialized()) {
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ERROR_UNINITIALIZED_CLOCK);
@@ -262,7 +263,7 @@ void Module::Interface::GetClockSnapshot(Kernel::HLERequestContext& ctx) {
Clock::SystemClockContext user_context{};
if (const ResultCode result{
module->GetTimeManager().GetStandardUserSystemClockCore().GetClockContext(
interface_module->GetTimeManager().GetStandardUserSystemClockCore().GetClockContext(
system, user_context)};
result.IsError()) {
IPC::ResponseBuilder rb{ctx, 2};
@@ -271,7 +272,7 @@ void Module::Interface::GetClockSnapshot(Kernel::HLERequestContext& ctx) {
}
Clock::SystemClockContext network_context{};
if (const ResultCode result{
module->GetTimeManager().GetStandardNetworkSystemClockCore().GetClockContext(
interface_module->GetTimeManager().GetStandardNetworkSystemClockCore().GetClockContext(
system, network_context)};
result.IsError()) {
IPC::ResponseBuilder rb{ctx, 2};
@@ -372,19 +373,24 @@ void Module::Interface::GetSharedMemoryNativeHandle(Kernel::HLERequestContext& c
LOG_DEBUG(Service_Time, "called");
IPC::ResponseBuilder rb{ctx, 2, 1};
rb.Push(RESULT_SUCCESS);
rb.PushCopyObjects(module->GetTimeManager().GetSharedMemory().GetSharedMemoryHolder());
rb.PushCopyObjects(
interface_module->GetTimeManager().GetSharedMemory().GetSharedMemoryHolder());
}
Module::Interface::Interface(std::shared_ptr<Module> module, Core::System& system, const char* name)
: ServiceFramework(name), module{std::move(module)}, system{system} {}
Module::Interface::Interface(std::shared_ptr<Module> interface_module, Core::System& system,
const char* name)
: ServiceFramework(name), interface_module{std::move(interface_module)}, system{system} {}
Module::Interface::~Interface() = default;
void InstallInterfaces(Core::System& system) {
auto module{std::make_shared<Module>(system)};
std::make_shared<Time>(module, system, "time:a")->InstallAsService(system.ServiceManager());
std::make_shared<Time>(module, system, "time:s")->InstallAsService(system.ServiceManager());
std::make_shared<Time>(module, system, "time:u")->InstallAsService(system.ServiceManager());
auto interface_module{std::make_shared<Module>(system)};
std::make_shared<Time>(interface_module, system, "time:a")
->InstallAsService(system.ServiceManager());
std::make_shared<Time>(interface_module, system, "time:s")
->InstallAsService(system.ServiceManager());
std::make_shared<Time>(interface_module, system, "time:u")
->InstallAsService(system.ServiceManager());
}
} // namespace Service::Time

View File

@@ -20,7 +20,8 @@ public:
class Interface : public ServiceFramework<Interface> {
public:
explicit Interface(std::shared_ptr<Module> module, Core::System& system, const char* name);
explicit Interface(std::shared_ptr<Module> interface_module, Core::System& system,
const char* name);
~Interface() override;
void GetStandardUserSystemClock(Kernel::HLERequestContext& ctx);
@@ -43,7 +44,7 @@ public:
Clock::ClockSnapshot& cloc_snapshot);
protected:
std::shared_ptr<Module> module;
std::shared_ptr<Module> interface_module;
Core::System& system;
};

View File

@@ -135,13 +135,13 @@ AppLoader_DeconstructedRomDirectory::LoadResult AppLoader_DeconstructedRomDirect
// Use the NSO module loader to figure out the code layout
std::size_t code_size{};
for (const auto& module : static_modules) {
const FileSys::VirtualFile module_file{dir->GetFile(module)};
for (const auto& mod : static_modules) {
const FileSys::VirtualFile module_file{dir->GetFile(mod)};
if (!module_file) {
continue;
}
const bool should_pass_arguments = std::strcmp(module, "rtld") == 0;
const bool should_pass_arguments = std::strcmp(mod, "rtld") == 0;
const auto tentative_next_load_addr = AppLoader_NSO::LoadModule(
process, system, *module_file, code_size, should_pass_arguments, false);
if (!tentative_next_load_addr) {
@@ -161,14 +161,14 @@ AppLoader_DeconstructedRomDirectory::LoadResult AppLoader_DeconstructedRomDirect
const VAddr base_address{process.PageTable().GetCodeRegionStart()};
VAddr next_load_addr{base_address};
const FileSys::PatchManager pm{metadata.GetTitleID()};
for (const auto& module : static_modules) {
const FileSys::VirtualFile module_file{dir->GetFile(module)};
for (const auto& mod : static_modules) {
const FileSys::VirtualFile module_file{dir->GetFile(mod)};
if (!module_file) {
continue;
}
const VAddr load_addr{next_load_addr};
const bool should_pass_arguments = std::strcmp(module, "rtld") == 0;
const bool should_pass_arguments = std::strcmp(mod, "rtld") == 0;
const auto tentative_next_load_addr = AppLoader_NSO::LoadModule(
process, system, *module_file, load_addr, should_pass_arguments, true, pm);
if (!tentative_next_load_addr) {
@@ -176,10 +176,10 @@ AppLoader_DeconstructedRomDirectory::LoadResult AppLoader_DeconstructedRomDirect
}
next_load_addr = *tentative_next_load_addr;
modules.insert_or_assign(load_addr, module);
LOG_DEBUG(Loader, "loaded module {} @ 0x{:X}", module, load_addr);
modules.insert_or_assign(load_addr, mod);
LOG_DEBUG(Loader, "loaded module {} @ 0x{:X}", mod, load_addr);
// Register module with GDBStub
GDBStub::RegisterModule(module, load_addr, next_load_addr - 1, false);
GDBStub::RegisterModule(mod, load_addr, next_load_addr - 1, false);
}
// Find the RomFS by searching for a ".romfs" file in this directory

View File

@@ -69,7 +69,7 @@ json GetReportCommonData(u64 title_id, ResultCode result, const std::string& tim
auto out = json{
{"title_id", fmt::format("{:016X}", title_id)},
{"result_raw", fmt::format("{:08X}", result.raw)},
{"result_module", fmt::format("{:08X}", static_cast<u32>(result.module.Value()))},
{"result_module", fmt::format("{:08X}", static_cast<u32>(result.error_module.Value()))},
{"result_description", fmt::format("{:08X}", result.description.Value())},
{"timestamp", timestamp},
};
@@ -127,7 +127,7 @@ json GetBacktraceData(Core::System& system) {
const auto& backtrace{system.CurrentArmInterface().GetBacktrace()};
for (const auto& entry : backtrace) {
out.push_back({
{"module", entry.module},
{"module", entry.mod},
{"address", fmt::format("{:016X}", entry.address)},
{"original_address", fmt::format("{:016X}", entry.original_address)},
{"offset", fmt::format("{:016X}", entry.offset)},

View File

@@ -152,6 +152,7 @@ struct Values {
bool vibration_enabled;
bool motion_enabled;
std::string motion_device;
std::string touch_device;
TouchscreenInput touchscreen;

View File

@@ -4,7 +4,16 @@
#include <chrono>
#include <thread>
#ifdef _MSC_VER
#pragma warning(push)
#pragma warning(disable : 4200) // nonstandard extension used : zero-sized array in struct/union
#endif
#include <libusb.h>
#ifdef _MSC_VER
#pragma warning(pop)
#endif
#include "common/logging/log.h"
#include "input_common/gcadapter/gc_adapter.h"

View File

@@ -12,6 +12,7 @@
#include "input_common/main.h"
#include "input_common/motion_emu.h"
#include "input_common/touch_from_button.h"
#include "input_common/udp/client.h"
#include "input_common/udp/udp.h"
#ifdef HAVE_SDL2
#include "input_common/sdl/sdl.h"
@@ -40,7 +41,11 @@ struct InputSubsystem::Impl {
sdl = SDL::Init();
#endif
udp = CemuhookUDP::Init();
udp = std::make_shared<InputCommon::CemuhookUDP::Client>();
udpmotion = std::make_shared<UDPMotionFactory>(udp);
Input::RegisterFactory<Input::MotionDevice>("cemuhookudp", udpmotion);
udptouch = std::make_shared<UDPTouchFactory>(udp);
Input::RegisterFactory<Input::TouchDevice>("cemuhookudp", udptouch);
}
void Shutdown() {
@@ -53,12 +58,17 @@ struct InputSubsystem::Impl {
#ifdef HAVE_SDL2
sdl.reset();
#endif
udp.reset();
Input::UnregisterFactory<Input::ButtonDevice>("gcpad");
Input::UnregisterFactory<Input::AnalogDevice>("gcpad");
gcbuttons.reset();
gcanalog.reset();
Input::UnregisterFactory<Input::MotionDevice>("cemuhookudp");
Input::UnregisterFactory<Input::TouchDevice>("cemuhookudp");
udpmotion.reset();
udptouch.reset();
}
[[nodiscard]] std::vector<Common::ParamPackage> GetInputDevices() const {
@@ -109,14 +119,28 @@ struct InputSubsystem::Impl {
return {};
}
[[nodiscard]] MotionMapping GetMotionMappingForDevice(
const Common::ParamPackage& params) const {
if (!params.Has("class") || params.Get("class", "") == "any") {
return {};
}
if (params.Get("class", "") == "cemuhookudp") {
// TODO return the correct motion device
return {};
}
return {};
}
std::shared_ptr<Keyboard> keyboard;
std::shared_ptr<MotionEmu> motion_emu;
#ifdef HAVE_SDL2
std::unique_ptr<SDL::State> sdl;
#endif
std::unique_ptr<CemuhookUDP::State> udp;
std::shared_ptr<GCButtonFactory> gcbuttons;
std::shared_ptr<GCAnalogFactory> gcanalog;
std::shared_ptr<UDPMotionFactory> udpmotion;
std::shared_ptr<UDPTouchFactory> udptouch;
std::shared_ptr<CemuhookUDP::Client> udp;
};
InputSubsystem::InputSubsystem() : impl{std::make_unique<Impl>()} {}
@@ -175,6 +199,22 @@ const GCButtonFactory* InputSubsystem::GetGCButtons() const {
return impl->gcbuttons.get();
}
UDPMotionFactory* InputSubsystem::GetUDPMotions() {
return impl->udpmotion.get();
}
const UDPMotionFactory* InputSubsystem::GetUDPMotions() const {
return impl->udpmotion.get();
}
UDPTouchFactory* InputSubsystem::GetUDPTouch() {
return impl->udptouch.get();
}
const UDPTouchFactory* InputSubsystem::GetUDPTouch() const {
return impl->udptouch.get();
}
void InputSubsystem::ReloadInputDevices() {
if (!impl->udp) {
return;

View File

@@ -21,10 +21,14 @@ namespace Settings::NativeButton {
enum Values : int;
}
namespace Settings::NativeMotion {
enum Values : int;
}
namespace InputCommon {
namespace Polling {
enum class DeviceType { Button, AnalogPreferred };
enum class DeviceType { Button, AnalogPreferred, Motion };
/**
* A class that can be used to get inputs from an input device like controllers without having to
@@ -50,6 +54,8 @@ public:
class GCAnalogFactory;
class GCButtonFactory;
class UDPMotionFactory;
class UDPTouchFactory;
class Keyboard;
class MotionEmu;
@@ -59,6 +65,7 @@ class MotionEmu;
*/
using AnalogMapping = std::unordered_map<Settings::NativeAnalog::Values, Common::ParamPackage>;
using ButtonMapping = std::unordered_map<Settings::NativeButton::Values, Common::ParamPackage>;
using MotionMapping = std::unordered_map<Settings::NativeMotion::Values, Common::ParamPackage>;
class InputSubsystem {
public:
@@ -103,6 +110,9 @@ public:
/// Retrieves the button mappings for the given device.
[[nodiscard]] ButtonMapping GetButtonMappingForDevice(const Common::ParamPackage& device) const;
/// Retrieves the motion mappings for the given device.
[[nodiscard]] MotionMapping GetMotionMappingForDevice(const Common::ParamPackage& device) const;
/// Retrieves the underlying GameCube analog handler.
[[nodiscard]] GCAnalogFactory* GetGCAnalogs();
@@ -115,6 +125,18 @@ public:
/// Retrieves the underlying GameCube button handler.
[[nodiscard]] const GCButtonFactory* GetGCButtons() const;
/// Retrieves the underlying udp motion handler.
[[nodiscard]] UDPMotionFactory* GetUDPMotions();
/// Retrieves the underlying udp motion handler.
[[nodiscard]] const UDPMotionFactory* GetUDPMotions() const;
/// Retrieves the underlying udp touch handler.
[[nodiscard]] UDPTouchFactory* GetUDPTouch();
/// Retrieves the underlying udp touch handler.
[[nodiscard]] const UDPTouchFactory* GetUDPTouch() const;
/// Reloads the input devices
void ReloadInputDevices();

View File

@@ -56,7 +56,7 @@ public:
is_tilting = false;
}
std::tuple<Common::Vec3<float>, Common::Vec3<float>> GetStatus() {
Input::MotionStatus GetStatus() {
std::lock_guard guard{status_mutex};
return status;
}
@@ -76,7 +76,7 @@ private:
Common::Event shutdown_event;
std::tuple<Common::Vec3<float>, Common::Vec3<float>> status;
Input::MotionStatus status;
std::mutex status_mutex;
// Note: always keep the thread declaration at the end so that other objects are initialized
@@ -113,10 +113,19 @@ private:
gravity = QuaternionRotate(inv_q, gravity);
angular_rate = QuaternionRotate(inv_q, angular_rate);
// TODO: Calculate the correct rotation vector and orientation matrix
const auto matrix4x4 = q.ToMatrix();
const auto rotation = Common::MakeVec(0.0f, 0.0f, 0.0f);
const std::array orientation{
Common::Vec3f(matrix4x4[0], matrix4x4[1], -matrix4x4[2]),
Common::Vec3f(matrix4x4[4], matrix4x4[5], -matrix4x4[6]),
Common::Vec3f(-matrix4x4[8], -matrix4x4[9], matrix4x4[10]),
};
// Update the sensor state
{
std::lock_guard guard{status_mutex};
status = std::make_tuple(gravity, angular_rate);
status = std::make_tuple(gravity, angular_rate, rotation, orientation);
}
}
}
@@ -131,7 +140,7 @@ public:
device = std::make_shared<MotionEmuDevice>(update_millisecond, sensitivity);
}
std::tuple<Common::Vec3<float>, Common::Vec3<float>> GetStatus() const override {
Input::MotionStatus GetStatus() const override {
return device->GetStatus();
}

View File

@@ -14,6 +14,13 @@ const std::array<const char*, NumButtons> mapping = {{
}};
}
namespace NativeMotion {
const std::array<const char*, NumMotions> mapping = {{
"motionleft",
"motionright",
}};
}
namespace NativeAnalog {
const std::array<const char*, NumAnalogs> mapping = {{
"lstick",

View File

@@ -66,6 +66,21 @@ constexpr int NUM_STICKS_HID = NumAnalogs;
extern const std::array<const char*, NumAnalogs> mapping;
} // namespace NativeAnalog
namespace NativeMotion {
enum Values : int {
MOTIONLEFT,
MOTIONRIGHT,
NumMotions,
};
constexpr int MOTION_HID_BEGIN = MOTIONLEFT;
constexpr int MOTION_HID_END = NumMotions;
constexpr int NUM_MOTION_HID = NumMotions;
extern const std::array<const char*, NumMotions> mapping;
} // namespace NativeMotion
namespace NativeMouseButton {
enum Values {
Left,
@@ -292,6 +307,7 @@ constexpr int NUM_KEYBOARD_MODS_HID = NumKeyboardMods;
using ButtonsRaw = std::array<std::string, NativeButton::NumButtons>;
using AnalogsRaw = std::array<std::string, NativeAnalog::NumAnalogs>;
using MotionRaw = std::array<std::string, NativeMotion::NumMotions>;
using MouseButtonsRaw = std::array<std::string, NativeMouseButton::NumMouseButtons>;
using KeyboardKeysRaw = std::array<std::string, NativeKeyboard::NumKeyboardKeys>;
using KeyboardModsRaw = std::array<std::string, NativeKeyboard::NumKeyboardMods>;
@@ -314,6 +330,7 @@ struct PlayerInput {
ControllerType controller_type;
ButtonsRaw buttons;
AnalogsRaw analogs;
MotionRaw motions;
std::string lstick_mod;
std::string rstick_mod;

View File

@@ -2,14 +2,13 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include <algorithm>
#include <array>
#include <chrono>
#include <cstring>
#include <functional>
#include <thread>
#include <boost/asio.hpp>
#include "common/logging/log.h"
#include "core/settings.h"
#include "input_common/udp/client.h"
#include "input_common/udp/protocol.h"
@@ -131,21 +130,59 @@ static void SocketLoop(Socket* socket) {
socket->Loop();
}
Client::Client(std::shared_ptr<DeviceStatus> status, const std::string& host, u16 port,
u8 pad_index, u32 client_id)
: status(std::move(status)) {
StartCommunication(host, port, pad_index, client_id);
Client::Client() {
LOG_INFO(Input, "Udp Initialization started");
for (std::size_t client = 0; client < clients.size(); client++) {
u8 pad = client % 4;
StartCommunication(client, Settings::values.udp_input_address,
Settings::values.udp_input_port, pad, 24872);
// Set motion parameters
// SetGyroThreshold value should be dependent on GyroscopeZeroDriftMode
// Real HW values are unknown, 0.0001 is an approximate to Standard
clients[client].motion.SetGyroThreshold(0.0001f);
}
}
Client::~Client() {
socket->Stop();
thread.join();
Reset();
}
std::vector<Common::ParamPackage> Client::GetInputDevices() const {
std::vector<Common::ParamPackage> devices;
for (std::size_t client = 0; client < clients.size(); client++) {
if (!DeviceConnected(client)) {
continue;
}
std::string name = fmt::format("UDP Controller {}", client);
devices.emplace_back(Common::ParamPackage{
{"class", "cemuhookudp"},
{"display", std::move(name)},
{"port", std::to_string(client)},
});
}
return devices;
}
bool Client::DeviceConnected(std::size_t pad) const {
// Use last timestamp to detect if the socket has stopped sending data
const auto now = std::chrono::system_clock::now();
u64 time_difference =
std::chrono::duration_cast<std::chrono::milliseconds>(now - clients[pad].last_motion_update)
.count();
return time_difference < 1000 && clients[pad].active == 1;
}
void Client::ReloadUDPClient() {
for (std::size_t client = 0; client < clients.size(); client++) {
ReloadSocket(Settings::values.udp_input_address, Settings::values.udp_input_port, client);
}
}
void Client::ReloadSocket(const std::string& host, u16 port, u8 pad_index, u32 client_id) {
socket->Stop();
thread.join();
StartCommunication(host, port, pad_index, client_id);
// client number must be determined from host / port and pad index
std::size_t client = pad_index;
clients[client].socket->Stop();
clients[client].thread.join();
StartCommunication(client, host, port, pad_index, client_id);
}
void Client::OnVersion(Response::Version data) {
@@ -157,23 +194,39 @@ void Client::OnPortInfo(Response::PortInfo data) {
}
void Client::OnPadData(Response::PadData data) {
// client number must be determined from host / port and pad index
std::size_t client = data.info.id;
LOG_TRACE(Input, "PadData packet received");
if (data.packet_counter <= packet_sequence) {
if (data.packet_counter == clients[client].packet_sequence) {
LOG_WARNING(
Input,
"PadData packet dropped because its stale info. Current count: {} Packet count: {}",
packet_sequence, data.packet_counter);
clients[client].packet_sequence, data.packet_counter);
return;
}
packet_sequence = data.packet_counter;
// TODO: Check how the Switch handles motions and how the CemuhookUDP motion
// directions correspond to the ones of the Switch
Common::Vec3f accel = Common::MakeVec<float>(data.accel.x, data.accel.y, data.accel.z);
Common::Vec3f gyro = Common::MakeVec<float>(data.gyro.pitch, data.gyro.yaw, data.gyro.roll);
{
std::lock_guard guard(status->update_mutex);
clients[client].active = data.info.is_pad_active;
clients[client].packet_sequence = data.packet_counter;
const auto now = std::chrono::system_clock::now();
u64 time_difference = std::chrono::duration_cast<std::chrono::microseconds>(
now - clients[client].last_motion_update)
.count();
clients[client].last_motion_update = now;
Common::Vec3f raw_gyroscope = {data.gyro.pitch, data.gyro.roll, -data.gyro.yaw};
clients[client].motion.SetAcceleration({data.accel.x, -data.accel.z, data.accel.y});
// Gyroscope values are not it the correct scale from better joy.
// Dividing by 312 allows us to make one full turn = 1 turn
// This must be a configurable valued called sensitivity
clients[client].motion.SetGyroscope(raw_gyroscope / 312.0f);
clients[client].motion.UpdateRotation(time_difference);
clients[client].motion.UpdateOrientation(time_difference);
Common::Vec3f gyroscope = clients[client].motion.GetGyroscope();
Common::Vec3f accelerometer = clients[client].motion.GetAcceleration();
Common::Vec3f rotation = clients[client].motion.GetRotations();
std::array<Common::Vec3f, 3> orientation = clients[client].motion.GetOrientation();
status->motion_status = {accel, gyro};
{
std::lock_guard guard(clients[client].status.update_mutex);
clients[client].status.motion_status = {accelerometer, gyroscope, rotation, orientation};
// TODO: add a setting for "click" touch. Click touch refers to a device that differentiates
// between a simple "tap" and a hard press that causes the touch screen to click.
@@ -182,11 +235,11 @@ void Client::OnPadData(Response::PadData data) {
float x = 0;
float y = 0;
if (is_active && status->touch_calibration) {
const u16 min_x = status->touch_calibration->min_x;
const u16 max_x = status->touch_calibration->max_x;
const u16 min_y = status->touch_calibration->min_y;
const u16 max_y = status->touch_calibration->max_y;
if (is_active && clients[client].status.touch_calibration) {
const u16 min_x = clients[client].status.touch_calibration->min_x;
const u16 max_x = clients[client].status.touch_calibration->max_x;
const u16 min_y = clients[client].status.touch_calibration->min_y;
const u16 max_y = clients[client].status.touch_calibration->max_y;
x = (std::clamp(static_cast<u16>(data.touch_1.x), min_x, max_x) - min_x) /
static_cast<float>(max_x - min_x);
@@ -194,17 +247,80 @@ void Client::OnPadData(Response::PadData data) {
static_cast<float>(max_y - min_y);
}
status->touch_status = {x, y, is_active};
clients[client].status.touch_status = {x, y, is_active};
if (configuring) {
UpdateYuzuSettings(client, accelerometer, gyroscope, is_active);
}
}
}
void Client::StartCommunication(const std::string& host, u16 port, u8 pad_index, u32 client_id) {
void Client::StartCommunication(std::size_t client, const std::string& host, u16 port, u8 pad_index,
u32 client_id) {
SocketCallback callback{[this](Response::Version version) { OnVersion(version); },
[this](Response::PortInfo info) { OnPortInfo(info); },
[this](Response::PadData data) { OnPadData(data); }};
LOG_INFO(Input, "Starting communication with UDP input server on {}:{}", host, port);
socket = std::make_unique<Socket>(host, port, pad_index, client_id, callback);
thread = std::thread{SocketLoop, this->socket.get()};
clients[client].socket = std::make_unique<Socket>(host, port, pad_index, client_id, callback);
clients[client].thread = std::thread{SocketLoop, clients[client].socket.get()};
}
void Client::Reset() {
for (std::size_t client = 0; client < clients.size(); client++) {
clients[client].socket->Stop();
clients[client].thread.join();
}
}
void Client::UpdateYuzuSettings(std::size_t client, const Common::Vec3<float>& acc,
const Common::Vec3<float>& gyro, bool touch) {
UDPPadStatus pad;
if (touch) {
pad.touch = PadTouch::Click;
pad_queue[client].Push(pad);
}
for (size_t i = 0; i < 3; ++i) {
if (gyro[i] > 6.0f || gyro[i] < -6.0f) {
pad.motion = static_cast<PadMotion>(i);
pad.motion_value = gyro[i];
pad_queue[client].Push(pad);
}
if (acc[i] > 2.0f || acc[i] < -2.0f) {
pad.motion = static_cast<PadMotion>(i + 3);
pad.motion_value = acc[i];
pad_queue[client].Push(pad);
}
}
}
void Client::BeginConfiguration() {
for (auto& pq : pad_queue) {
pq.Clear();
}
configuring = true;
}
void Client::EndConfiguration() {
for (auto& pq : pad_queue) {
pq.Clear();
}
configuring = false;
}
DeviceStatus& Client::GetPadState(std::size_t pad) {
return clients[pad].status;
}
const DeviceStatus& Client::GetPadState(std::size_t pad) const {
return clients[pad].status;
}
std::array<Common::SPSCQueue<UDPPadStatus>, 4>& Client::GetPadQueue() {
return pad_queue;
}
const std::array<Common::SPSCQueue<UDPPadStatus>, 4>& Client::GetPadQueue() const {
return pad_queue;
}
void TestCommunication(const std::string& host, u16 port, u8 pad_index, u32 client_id,

View File

@@ -12,8 +12,12 @@
#include <thread>
#include <tuple>
#include "common/common_types.h"
#include "common/param_package.h"
#include "common/thread.h"
#include "common/threadsafe_queue.h"
#include "common/vector_math.h"
#include "core/frontend/input.h"
#include "input_common/motion_input.h"
namespace InputCommon::CemuhookUDP {
@@ -28,9 +32,30 @@ struct PortInfo;
struct Version;
} // namespace Response
enum class PadMotion {
GyroX,
GyroY,
GyroZ,
AccX,
AccY,
AccZ,
Undefined,
};
enum class PadTouch {
Click,
Undefined,
};
struct UDPPadStatus {
PadTouch touch{PadTouch::Undefined};
PadMotion motion{PadMotion::Undefined};
f32 motion_value{0.0f};
};
struct DeviceStatus {
std::mutex update_mutex;
std::tuple<Common::Vec3<float>, Common::Vec3<float>> motion_status;
Input::MotionStatus motion_status;
std::tuple<float, float, bool> touch_status;
// calibration data for scaling the device's touch area to 3ds
@@ -45,22 +70,58 @@ struct DeviceStatus {
class Client {
public:
explicit Client(std::shared_ptr<DeviceStatus> status, const std::string& host = DEFAULT_ADDR,
u16 port = DEFAULT_PORT, u8 pad_index = 0, u32 client_id = 24872);
// Initialize the UDP client capture and read sequence
Client();
// Close and release the client
~Client();
// Used for polling
void BeginConfiguration();
void EndConfiguration();
std::vector<Common::ParamPackage> GetInputDevices() const;
bool DeviceConnected(std::size_t pad) const;
void ReloadUDPClient();
void ReloadSocket(const std::string& host = "127.0.0.1", u16 port = 26760, u8 pad_index = 0,
u32 client_id = 24872);
std::array<Common::SPSCQueue<UDPPadStatus>, 4>& GetPadQueue();
const std::array<Common::SPSCQueue<UDPPadStatus>, 4>& GetPadQueue() const;
DeviceStatus& GetPadState(std::size_t pad);
const DeviceStatus& GetPadState(std::size_t pad) const;
private:
struct ClientData {
std::unique_ptr<Socket> socket;
DeviceStatus status;
std::thread thread;
u64 packet_sequence = 0;
u8 active;
// Realtime values
// motion is initalized with PID values for drift correction on joycons
InputCommon::MotionInput motion{0.3f, 0.005f, 0.0f};
std::chrono::time_point<std::chrono::system_clock> last_motion_update;
};
// For shutting down, clear all data, join all threads, release usb
void Reset();
void OnVersion(Response::Version);
void OnPortInfo(Response::PortInfo);
void OnPadData(Response::PadData);
void StartCommunication(const std::string& host, u16 port, u8 pad_index, u32 client_id);
void StartCommunication(std::size_t client, const std::string& host, u16 port, u8 pad_index,
u32 client_id);
void UpdateYuzuSettings(std::size_t client, const Common::Vec3<float>& acc,
const Common::Vec3<float>& gyro, bool touch);
std::unique_ptr<Socket> socket;
std::shared_ptr<DeviceStatus> status;
std::thread thread;
u64 packet_sequence = 0;
bool configuring = false;
std::array<ClientData, 4> clients;
std::array<Common::SPSCQueue<UDPPadStatus>, 4> pad_queue;
};
/// An async job allowing configuration of the touchpad calibration.

View File

@@ -1,105 +1,144 @@
// Copyright 2018 Citra Emulator Project
// Copyright 2020 yuzu Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include <atomic>
#include <list>
#include <mutex>
#include <optional>
#include <tuple>
#include "common/param_package.h"
#include "core/frontend/input.h"
#include "core/settings.h"
#include <utility>
#include "common/assert.h"
#include "common/threadsafe_queue.h"
#include "input_common/udp/client.h"
#include "input_common/udp/udp.h"
namespace InputCommon::CemuhookUDP {
namespace InputCommon {
class UDPTouchDevice final : public Input::TouchDevice {
class UDPMotion final : public Input::MotionDevice {
public:
explicit UDPTouchDevice(std::shared_ptr<DeviceStatus> status_) : status(std::move(status_)) {}
std::tuple<float, float, bool> GetStatus() const override {
std::lock_guard guard(status->update_mutex);
return status->touch_status;
UDPMotion(std::string ip_, int port_, int pad_, CemuhookUDP::Client* client_)
: ip(ip_), port(port_), pad(pad_), client(client_) {}
Input::MotionStatus GetStatus() const override {
return client->GetPadState(pad).motion_status;
}
private:
std::shared_ptr<DeviceStatus> status;
const std::string ip;
const int port;
const int pad;
CemuhookUDP::Client* client;
mutable std::mutex mutex;
};
class UDPMotionDevice final : public Input::MotionDevice {
public:
explicit UDPMotionDevice(std::shared_ptr<DeviceStatus> status_) : status(std::move(status_)) {}
std::tuple<Common::Vec3<float>, Common::Vec3<float>> GetStatus() const override {
std::lock_guard guard(status->update_mutex);
return status->motion_status;
}
/// A motion device factory that creates motion devices from JC Adapter
UDPMotionFactory::UDPMotionFactory(std::shared_ptr<CemuhookUDP::Client> client_)
: client(std::move(client_)) {}
private:
std::shared_ptr<DeviceStatus> status;
};
/**
* Creates motion device
* @param params contains parameters for creating the device:
* - "port": the nth jcpad on the adapter
*/
std::unique_ptr<Input::MotionDevice> UDPMotionFactory::Create(const Common::ParamPackage& params) {
const std::string ip = params.Get("ip", "127.0.0.1");
const int port = params.Get("port", 26760);
const int pad = params.Get("pad_index", 0);
class UDPTouchFactory final : public Input::Factory<Input::TouchDevice> {
public:
explicit UDPTouchFactory(std::shared_ptr<DeviceStatus> status_) : status(std::move(status_)) {}
return std::make_unique<UDPMotion>(ip, port, pad, client.get());
}
std::unique_ptr<Input::TouchDevice> Create(const Common::ParamPackage& params) override {
{
std::lock_guard guard(status->update_mutex);
status->touch_calibration = DeviceStatus::CalibrationData{};
// These default values work well for DS4 but probably not other touch inputs
status->touch_calibration->min_x = params.Get("min_x", 100);
status->touch_calibration->min_y = params.Get("min_y", 50);
status->touch_calibration->max_x = params.Get("max_x", 1800);
status->touch_calibration->max_y = params.Get("max_y", 850);
void UDPMotionFactory::BeginConfiguration() {
polling = true;
client->BeginConfiguration();
}
void UDPMotionFactory::EndConfiguration() {
polling = false;
client->EndConfiguration();
}
Common::ParamPackage UDPMotionFactory::GetNextInput() {
Common::ParamPackage params;
CemuhookUDP::UDPPadStatus pad;
auto& queue = client->GetPadQueue();
for (std::size_t pad_number = 0; pad_number < queue.size(); ++pad_number) {
while (queue[pad_number].Pop(pad)) {
if (pad.motion == CemuhookUDP::PadMotion::Undefined || std::abs(pad.motion_value) < 1) {
continue;
}
params.Set("engine", "cemuhookudp");
params.Set("ip", "127.0.0.1");
params.Set("port", 26760);
params.Set("pad_index", static_cast<int>(pad_number));
params.Set("motion", static_cast<u16>(pad.motion));
return params;
}
return std::make_unique<UDPTouchDevice>(status);
}
return params;
}
private:
std::shared_ptr<DeviceStatus> status;
};
class UDPMotionFactory final : public Input::Factory<Input::MotionDevice> {
class UDPTouch final : public Input::TouchDevice {
public:
explicit UDPMotionFactory(std::shared_ptr<DeviceStatus> status_) : status(std::move(status_)) {}
UDPTouch(std::string ip_, int port_, int pad_, CemuhookUDP::Client* client_)
: ip(std::move(ip_)), port(port_), pad(pad_), client(client_) {}
std::unique_ptr<Input::MotionDevice> Create(const Common::ParamPackage& params) override {
return std::make_unique<UDPMotionDevice>(status);
std::tuple<float, float, bool> GetStatus() const override {
return client->GetPadState(pad).touch_status;
}
private:
std::shared_ptr<DeviceStatus> status;
const std::string ip;
const int port;
const int pad;
CemuhookUDP::Client* client;
mutable std::mutex mutex;
};
State::State() {
auto status = std::make_shared<DeviceStatus>();
client =
std::make_unique<Client>(status, Settings::values.udp_input_address,
Settings::values.udp_input_port, Settings::values.udp_pad_index);
/// A motion device factory that creates motion devices from JC Adapter
UDPTouchFactory::UDPTouchFactory(std::shared_ptr<CemuhookUDP::Client> client_)
: client(std::move(client_)) {}
motion_factory = std::make_shared<UDPMotionFactory>(status);
touch_factory = std::make_shared<UDPTouchFactory>(status);
/**
* Creates motion device
* @param params contains parameters for creating the device:
* - "port": the nth jcpad on the adapter
*/
std::unique_ptr<Input::TouchDevice> UDPTouchFactory::Create(const Common::ParamPackage& params) {
const std::string ip = params.Get("ip", "127.0.0.1");
const int port = params.Get("port", 26760);
const int pad = params.Get("pad_index", 0);
Input::RegisterFactory<Input::MotionDevice>("cemuhookudp", motion_factory);
Input::RegisterFactory<Input::TouchDevice>("cemuhookudp", touch_factory);
return std::make_unique<UDPTouch>(ip, port, pad, client.get());
}
State::~State() {
Input::UnregisterFactory<Input::TouchDevice>("cemuhookudp");
Input::UnregisterFactory<Input::MotionDevice>("cemuhookudp");
void UDPTouchFactory::BeginConfiguration() {
polling = true;
client->BeginConfiguration();
}
std::vector<Common::ParamPackage> State::GetInputDevices() const {
// TODO support binding udp devices
return {};
void UDPTouchFactory::EndConfiguration() {
polling = false;
client->EndConfiguration();
}
void State::ReloadUDPClient() {
client->ReloadSocket(Settings::values.udp_input_address, Settings::values.udp_input_port,
Settings::values.udp_pad_index);
Common::ParamPackage UDPTouchFactory::GetNextInput() {
Common::ParamPackage params;
CemuhookUDP::UDPPadStatus pad;
auto& queue = client->GetPadQueue();
for (std::size_t pad_number = 0; pad_number < queue.size(); ++pad_number) {
while (queue[pad_number].Pop(pad)) {
if (pad.touch == CemuhookUDP::PadTouch::Undefined) {
continue;
}
params.Set("engine", "cemuhookudp");
params.Set("ip", "127.0.0.1");
params.Set("port", 26760);
params.Set("pad_index", static_cast<int>(pad_number));
params.Set("touch", static_cast<u16>(pad.touch));
return params;
}
}
return params;
}
std::unique_ptr<State> Init() {
return std::make_unique<State>();
}
} // namespace InputCommon::CemuhookUDP
} // namespace InputCommon

View File

@@ -1,32 +1,57 @@
// Copyright 2018 Citra Emulator Project
// Copyright 2020 yuzu Emulator Project
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include <memory>
#include <vector>
#include "common/param_package.h"
#include "core/frontend/input.h"
#include "input_common/udp/client.h"
namespace InputCommon::CemuhookUDP {
namespace InputCommon {
class Client;
class UDPMotionFactory;
class UDPTouchFactory;
class State {
/// A motion device factory that creates motion devices from udp clients
class UDPMotionFactory final : public Input::Factory<Input::MotionDevice> {
public:
State();
~State();
void ReloadUDPClient();
std::vector<Common::ParamPackage> GetInputDevices() const;
explicit UDPMotionFactory(std::shared_ptr<CemuhookUDP::Client> client_);
std::unique_ptr<Input::MotionDevice> Create(const Common::ParamPackage& params) override;
Common::ParamPackage GetNextInput();
/// For device input configuration/polling
void BeginConfiguration();
void EndConfiguration();
bool IsPolling() const {
return polling;
}
private:
std::unique_ptr<Client> client;
std::shared_ptr<UDPMotionFactory> motion_factory;
std::shared_ptr<UDPTouchFactory> touch_factory;
std::shared_ptr<CemuhookUDP::Client> client;
bool polling = false;
};
std::unique_ptr<State> Init();
/// A touch device factory that creates touch devices from udp clients
class UDPTouchFactory final : public Input::Factory<Input::TouchDevice> {
public:
explicit UDPTouchFactory(std::shared_ptr<CemuhookUDP::Client> client_);
} // namespace InputCommon::CemuhookUDP
std::unique_ptr<Input::TouchDevice> Create(const Common::ParamPackage& params) override;
Common::ParamPackage GetNextInput();
/// For device input configuration/polling
void BeginConfiguration();
void EndConfiguration();
bool IsPolling() const {
return polling;
}
private:
std::shared_ptr<CemuhookUDP::Client> client;
bool polling = false;
};
} // namespace InputCommon

View File

@@ -269,5 +269,5 @@ endif()
if (MSVC)
target_compile_options(video_core PRIVATE /we4267)
else()
target_compile_options(video_core PRIVATE -Werror=conversion -Wno-error=sign-conversion)
target_compile_options(video_core PRIVATE -Werror=conversion -Wno-error=sign-conversion -Werror=switch)
endif()

View File

@@ -87,12 +87,12 @@ void Fermi2D::HandleSurfaceCopy() {
const Common::Rectangle<u32> src_rect{src_blit_x1, src_blit_y1, src_blit_x2, src_blit_y2};
const Common::Rectangle<u32> dst_rect{regs.blit_dst_x, regs.blit_dst_y, dst_blit_x2,
dst_blit_y2};
Config copy_config;
copy_config.operation = regs.operation;
copy_config.filter = regs.blit_control.filter;
copy_config.src_rect = src_rect;
copy_config.dst_rect = dst_rect;
const Config copy_config{
.operation = regs.operation,
.filter = regs.blit_control.filter,
.src_rect = src_rect,
.dst_rect = dst_rect,
};
if (!rasterizer->AccelerateSurfaceCopy(regs.src, regs.dst, copy_config)) {
UNIMPLEMENTED();
}

View File

@@ -145,8 +145,8 @@ public:
} regs{};
struct Config {
Operation operation;
Filter filter;
Operation operation{};
Filter filter{};
Common::Rectangle<u32> src_rect;
Common::Rectangle<u32> dst_rect;
};

View File

@@ -1443,8 +1443,10 @@ private:
return expr + ", vec2(0.0), vec2(0.0))";
case TextureType::TextureCube:
return expr + ", vec3(0.0), vec3(0.0))";
default:
UNREACHABLE();
break;
}
UNREACHABLE();
}
for (const auto& variant : extras) {

View File

@@ -47,6 +47,8 @@ inline GLenum VertexFormat(Maxwell::VertexAttribute attrib) {
return GL_UNSIGNED_INT;
case Maxwell::VertexAttribute::Size::Size_10_10_10_2:
return GL_UNSIGNED_INT_2_10_10_10_REV;
default:
break;
}
break;
case Maxwell::VertexAttribute::Type::SignedNorm:
@@ -70,6 +72,8 @@ inline GLenum VertexFormat(Maxwell::VertexAttribute attrib) {
return GL_INT;
case Maxwell::VertexAttribute::Size::Size_10_10_10_2:
return GL_INT_2_10_10_10_REV;
default:
break;
}
break;
case Maxwell::VertexAttribute::Type::Float:
@@ -84,6 +88,8 @@ inline GLenum VertexFormat(Maxwell::VertexAttribute attrib) {
case Maxwell::VertexAttribute::Size::Size_32_32_32:
case Maxwell::VertexAttribute::Size::Size_32_32_32_32:
return GL_FLOAT;
default:
break;
}
break;
}

View File

@@ -78,9 +78,10 @@ VkSamplerAddressMode WrapMode(const VKDevice& device, Tegra::Texture::WrapMode w
case Tegra::Texture::WrapMode::MirrorOnceBorder:
UNIMPLEMENTED();
return VK_SAMPLER_ADDRESS_MODE_MIRROR_CLAMP_TO_EDGE;
default:
UNIMPLEMENTED_MSG("Unimplemented wrap mode={}", static_cast<u32>(wrap_mode));
return {};
}
UNIMPLEMENTED_MSG("Unimplemented wrap mode={}", static_cast<u32>(wrap_mode));
return {};
}
VkCompareOp DepthCompareFunction(Tegra::Texture::DepthCompareFunc depth_compare_func) {
@@ -298,9 +299,10 @@ VkPrimitiveTopology PrimitiveTopology([[maybe_unused]] const VKDevice& device,
return VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
case Maxwell::PrimitiveTopology::Patches:
return VK_PRIMITIVE_TOPOLOGY_PATCH_LIST;
default:
UNIMPLEMENTED_MSG("Unimplemented topology={}", static_cast<u32>(topology));
return {};
}
UNIMPLEMENTED_MSG("Unimplemented topology={}", static_cast<u32>(topology));
return {};
}
VkFormat VertexFormat(Maxwell::VertexAttribute::Type type, Maxwell::VertexAttribute::Size size) {
@@ -325,6 +327,8 @@ VkFormat VertexFormat(Maxwell::VertexAttribute::Type type, Maxwell::VertexAttrib
return VK_FORMAT_R16G16B16A16_UNORM;
case Maxwell::VertexAttribute::Size::Size_10_10_10_2:
return VK_FORMAT_A2B10G10R10_UNORM_PACK32;
default:
break;
}
break;
case Maxwell::VertexAttribute::Type::SignedNorm:
@@ -347,6 +351,8 @@ VkFormat VertexFormat(Maxwell::VertexAttribute::Type type, Maxwell::VertexAttrib
return VK_FORMAT_R16G16B16A16_SNORM;
case Maxwell::VertexAttribute::Size::Size_10_10_10_2:
return VK_FORMAT_A2B10G10R10_SNORM_PACK32;
default:
break;
}
break;
case Maxwell::VertexAttribute::Type::UnsignedScaled:
@@ -369,6 +375,8 @@ VkFormat VertexFormat(Maxwell::VertexAttribute::Type type, Maxwell::VertexAttrib
return VK_FORMAT_R16G16B16A16_USCALED;
case Maxwell::VertexAttribute::Size::Size_10_10_10_2:
return VK_FORMAT_A2B10G10R10_USCALED_PACK32;
default:
break;
}
break;
case Maxwell::VertexAttribute::Type::SignedScaled:
@@ -391,6 +399,8 @@ VkFormat VertexFormat(Maxwell::VertexAttribute::Type type, Maxwell::VertexAttrib
return VK_FORMAT_R16G16B16A16_SSCALED;
case Maxwell::VertexAttribute::Size::Size_10_10_10_2:
return VK_FORMAT_A2B10G10R10_SSCALED_PACK32;
default:
break;
}
break;
case Maxwell::VertexAttribute::Type::UnsignedInt:
@@ -421,6 +431,8 @@ VkFormat VertexFormat(Maxwell::VertexAttribute::Type type, Maxwell::VertexAttrib
return VK_FORMAT_R32G32B32A32_UINT;
case Maxwell::VertexAttribute::Size::Size_10_10_10_2:
return VK_FORMAT_A2B10G10R10_UINT_PACK32;
default:
break;
}
break;
case Maxwell::VertexAttribute::Type::SignedInt:
@@ -451,6 +463,8 @@ VkFormat VertexFormat(Maxwell::VertexAttribute::Type type, Maxwell::VertexAttrib
return VK_FORMAT_R32G32B32A32_SINT;
case Maxwell::VertexAttribute::Size::Size_10_10_10_2:
return VK_FORMAT_A2B10G10R10_SINT_PACK32;
default:
break;
}
break;
case Maxwell::VertexAttribute::Type::Float:
@@ -471,6 +485,8 @@ VkFormat VertexFormat(Maxwell::VertexAttribute::Type type, Maxwell::VertexAttrib
return VK_FORMAT_R32G32B32_SFLOAT;
case Maxwell::VertexAttribute::Size::Size_32_32_32_32:
return VK_FORMAT_R32G32B32A32_SFLOAT;
default:
break;
}
break;
}

View File

@@ -529,7 +529,7 @@ void VKBlitScreen::CreateGraphicsPipeline() {
.pNext = nullptr,
.flags = 0,
.stage = VK_SHADER_STAGE_VERTEX_BIT,
.module = *vertex_shader,
.vkModule = *vertex_shader,
.pName = "main",
.pSpecializationInfo = nullptr,
},
@@ -538,7 +538,7 @@ void VKBlitScreen::CreateGraphicsPipeline() {
.pNext = nullptr,
.flags = 0,
.stage = VK_SHADER_STAGE_FRAGMENT_BIT,
.module = *fragment_shader,
.vkModule = *fragment_shader,
.pName = "main",
.pSpecializationInfo = nullptr,
},

View File

@@ -418,7 +418,7 @@ VKComputePass::VKComputePass(const VKDevice& device, VKDescriptorPool& descripto
auto code_copy = std::make_unique<u32[]>(code_size / sizeof(u32) + 1);
std::memcpy(code_copy.get(), code, code_size);
module = device.GetLogical().CreateShaderModule({
shader_module = device.GetLogical().CreateShaderModule({
.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO,
.pNext = nullptr,
.flags = 0,
@@ -436,7 +436,7 @@ VKComputePass::VKComputePass(const VKDevice& device, VKDescriptorPool& descripto
.pNext = nullptr,
.flags = 0,
.stage = VK_SHADER_STAGE_COMPUTE_BIT,
.module = *module,
.vkModule = *shader_module,
.pName = "main",
.pSpecializationInfo = nullptr,
},

View File

@@ -40,7 +40,7 @@ protected:
private:
vk::DescriptorSetLayout descriptor_set_layout;
std::optional<DescriptorAllocator> descriptor_allocator;
vk::ShaderModule module;
vk::ShaderModule shader_module;
};
class QuadArrayPass final : public VKComputePass {

View File

@@ -128,7 +128,7 @@ vk::Pipeline VKComputePipeline::CreatePipeline() const {
.pNext = nullptr,
.flags = 0,
.stage = VK_SHADER_STAGE_COMPUTE_BIT,
.module = *shader_module,
.vkModule = *shader_module,
.pName = "main",
.pSpecializationInfo = nullptr,
},

View File

@@ -262,6 +262,22 @@ const char* ToString(VkResult result) noexcept {
return "VK_ERROR_INVALID_DEVICE_ADDRESS_EXT";
case VkResult::VK_ERROR_FULL_SCREEN_EXCLUSIVE_MODE_LOST_EXT:
return "VK_ERROR_FULL_SCREEN_EXCLUSIVE_MODE_LOST_EXT";
case VkResult::VK_ERROR_UNKNOWN:
return "VK_ERROR_UNKNOWN";
case VkResult::VK_ERROR_INCOMPATIBLE_VERSION_KHR:
return "VK_ERROR_INCOMPATIBLE_VERSION_KHR";
case VkResult::VK_THREAD_IDLE_KHR:
return "VK_THREAD_IDLE_KHR";
case VkResult::VK_THREAD_DONE_KHR:
return "VK_THREAD_DONE_KHR";
case VkResult::VK_OPERATION_DEFERRED_KHR:
return "VK_OPERATION_DEFERRED_KHR";
case VkResult::VK_OPERATION_NOT_DEFERRED_KHR:
return "VK_OPERATION_NOT_DEFERRED_KHR";
case VkResult::VK_PIPELINE_COMPILE_REQUIRED_EXT:
return "VK_PIPELINE_COMPILE_REQUIRED_EXT";
case VkResult::VK_RESULT_MAX_ENUM:
return "VK_RESULT_MAX_ENUM";
}
return "Unknown";
}

View File

@@ -14,7 +14,12 @@
#include <vector>
#define VK_NO_PROTOTYPES
// As "module" is defined in various structs as members in the vulkan library, this would be a
// specification breaking change. To combat this, we rename the use of "module" to vkModule since
// we're targeting C++20
#define module vkModule
#include <vulkan/vulkan.h>
#undef module
#include "common/common_types.h"

View File

@@ -53,6 +53,9 @@ u32 ShaderIR::DecodeArithmeticHalf(NodeBlock& bb, u32 pc) {
absolute_a = ((instr.value >> 44) & 1) != 0;
absolute_b = ((instr.value >> 54) & 1) != 0;
break;
default:
UNREACHABLE();
break;
}
Node op_a = UnpackHalfFloat(GetRegister(instr.gpr8), instr.alu_half.type_a);

View File

@@ -119,6 +119,8 @@ ComponentType GetComponentType(Tegra::Engines::SamplerDescriptor descriptor,
return descriptor.r_type;
}
break;
default:
break;
}
UNIMPLEMENTED_MSG("Texture format not implemented={}", format);
return ComponentType::FLOAT;
@@ -220,9 +222,10 @@ u32 GetComponentSize(TextureFormat format, std::size_t component) {
return (component == 0 || component == 1) ? 8 : 0;
case TextureFormat::G4R4:
return (component == 0 || component == 1) ? 4 : 0;
default:
UNIMPLEMENTED_MSG("Texture format not implemented={}", format);
return 0;
}
UNIMPLEMENTED_MSG("Texture format not implemented={}", format);
return 0;
}
std::size_t GetImageComponentMask(TextureFormat format) {
@@ -257,9 +260,10 @@ std::size_t GetImageComponentMask(TextureFormat format) {
case TextureFormat::R8:
case TextureFormat::R1:
return std::size_t{R};
default:
UNIMPLEMENTED_MSG("Texture format not implemented={}", format);
return std::size_t{R | G | B | A};
}
UNIMPLEMENTED_MSG("Texture format not implemented={}", format);
return std::size_t{R | G | B | A};
}
std::size_t GetImageTypeNumCoordinates(Tegra::Shader::ImageType image_type) {
@@ -463,7 +467,10 @@ u32 ShaderIR::DecodeImage(NodeBlock& bb, u32 pc) {
return OperationCode::AtomicImageXor;
case Tegra::Shader::ImageAtomicOperation::Exch:
return OperationCode::AtomicImageExchange;
default:
break;
}
break;
default:
break;
}

View File

@@ -763,7 +763,7 @@ Node4 ShaderIR::GetTld4Code(Instruction instr, TextureType texture_type, bool de
Node4 ShaderIR::GetTldCode(Tegra::Shader::Instruction instr) {
const auto texture_type{instr.tld.texture_type};
const bool is_array{instr.tld.is_array};
const bool is_array{instr.tld.is_array != 0};
const bool lod_enabled{instr.tld.GetTextureProcessMode() == TextureProcessMode::LL};
const std::size_t coord_count{GetCoordCount(texture_type)};

View File

@@ -21,7 +21,7 @@ void QtErrorDisplay::ShowError(ResultCode error, std::function<void()> finished)
emit MainWindowDisplayError(
tr("An error has occured.\nPlease try again or contact the developer of the "
"software.\n\nError Code: %1-%2 (0x%3)")
.arg(static_cast<u32>(error.module.Value()) + 2000, 4, 10, QChar::fromLatin1('0'))
.arg(static_cast<u32>(error.error_module.Value()) + 2000, 4, 10, QChar::fromLatin1('0'))
.arg(error.description, 4, 10, QChar::fromLatin1('0'))
.arg(error.raw, 8, 16, QChar::fromLatin1('0')));
}
@@ -36,7 +36,7 @@ void QtErrorDisplay::ShowErrorWithTimestamp(ResultCode error, std::chrono::secon
"developer of the software.\n\nError Code: %3-%4 (0x%5)")
.arg(date_time.toString(QStringLiteral("dddd, MMMM d, yyyy")))
.arg(date_time.toString(QStringLiteral("h:mm:ss A")))
.arg(static_cast<u32>(error.module.Value()) + 2000, 4, 10, QChar::fromLatin1('0'))
.arg(static_cast<u32>(error.error_module.Value()) + 2000, 4, 10, QChar::fromLatin1('0'))
.arg(error.description, 4, 10, QChar::fromLatin1('0'))
.arg(error.raw, 8, 16, QChar::fromLatin1('0')));
}
@@ -47,7 +47,7 @@ void QtErrorDisplay::ShowCustomErrorText(ResultCode error, std::string dialog_te
this->callback = std::move(finished);
emit MainWindowDisplayError(
tr("An error has occured.\nError Code: %1-%2 (0x%3)\n\n%4\n\n%5")
.arg(static_cast<u32>(error.module.Value()) + 2000, 4, 10, QChar::fromLatin1('0'))
.arg(static_cast<u32>(error.error_module.Value()) + 2000, 4, 10, QChar::fromLatin1('0'))
.arg(error.description, 4, 10, QChar::fromLatin1('0'))
.arg(error.raw, 8, 16, QChar::fromLatin1('0'))
.arg(QString::fromStdString(dialog_text))

View File

@@ -36,6 +36,11 @@ const std::array<int, Settings::NativeButton::NumButtons> Config::default_button
Qt::Key_H, Qt::Key_G, Qt::Key_D, Qt::Key_C, Qt::Key_B, Qt::Key_V,
};
const std::array<int, Settings::NativeMotion::NumMotions> Config::default_motions = {
Qt::Key_7,
Qt::Key_8,
};
const std::array<std::array<int, 4>, Settings::NativeAnalog::NumAnalogs> Config::default_analogs{{
{
Qt::Key_Up,
@@ -284,6 +289,22 @@ void Config::ReadPlayerValues() {
}
}
for (int i = 0; i < Settings::NativeMotion::NumMotions; ++i) {
const std::string default_param =
InputCommon::GenerateKeyboardParam(default_motions[i]);
auto& player_motions = player.motions[i];
player_motions = qt_config
->value(QStringLiteral("player_%1_").arg(p) +
QString::fromUtf8(Settings::NativeMotion::mapping[i]),
QString::fromStdString(default_param))
.toString()
.toStdString();
if (player_motions.empty()) {
player_motions = default_param;
}
}
for (int i = 0; i < Settings::NativeAnalog::NumAnalogs; ++i) {
const std::string default_param = InputCommon::GenerateAnalogParamFromKeys(
default_analogs[i][0], default_analogs[i][1], default_analogs[i][2],
@@ -424,6 +445,7 @@ void Config::ReadControlValues() {
Settings::values.vibration_enabled =
ReadSetting(QStringLiteral("vibration_enabled"), true).toBool();
Settings::values.motion_enabled = ReadSetting(QStringLiteral("motion_enabled"), true).toBool();
Settings::values.use_docked_mode =
ReadSetting(QStringLiteral("use_docked_mode"), false).toBool();
@@ -922,6 +944,14 @@ void Config::SavePlayerValues() {
QString::fromStdString(player.buttons[i]),
QString::fromStdString(default_param));
}
for (int i = 0; i < Settings::NativeMotion::NumMotions; ++i) {
const std::string default_param =
InputCommon::GenerateKeyboardParam(default_motions[i]);
WriteSetting(QStringLiteral("player_%1_").arg(p) +
QString::fromStdString(Settings::NativeMotion::mapping[i]),
QString::fromStdString(player.motions[i]),
QString::fromStdString(default_param));
}
for (int i = 0; i < Settings::NativeAnalog::NumAnalogs; ++i) {
const std::string default_param = InputCommon::GenerateAnalogParamFromKeys(
default_analogs[i][0], default_analogs[i][1], default_analogs[i][2],
@@ -1062,6 +1092,7 @@ void Config::SaveControlValues() {
SaveMotionTouchValues();
WriteSetting(QStringLiteral("vibration_enabled"), Settings::values.vibration_enabled, true);
WriteSetting(QStringLiteral("motion_enabled"), Settings::values.motion_enabled, true);
WriteSetting(QStringLiteral("motion_device"),
QString::fromStdString(Settings::values.motion_device),
QStringLiteral("engine:motion_emu,update_period:100,sensitivity:0.01"));

View File

@@ -23,6 +23,7 @@ public:
void Save();
static const std::array<int, Settings::NativeButton::NumButtons> default_buttons;
static const std::array<int, Settings::NativeMotion::NumMotions> default_motions;
static const std::array<std::array<int, 4>, Settings::NativeAnalog::NumAnalogs> default_analogs;
static const std::array<int, 2> default_stick_mod;
static const std::array<int, Settings::NativeMouseButton::NumMouseButtons>

View File

@@ -146,6 +146,10 @@ void ConfigureInput::Initialize(InputCommon::InputSubsystem* input_subsystem,
CallConfigureDialog<ConfigureMotionTouch>(*this, input_subsystem);
});
connect(ui->motionButton, &QPushButton::clicked, [this, input_subsystem] {
CallConfigureDialog<ConfigureMotionTouch>(*this, input_subsystem);
});
connect(ui->buttonClearAll, &QPushButton::clicked, [this] { ClearAll(); });
connect(ui->buttonRestoreDefaults, &QPushButton::clicked, [this] { RestoreDefaults(); });
@@ -172,6 +176,7 @@ void ConfigureInput::ApplyConfiguration() {
OnDockedModeChanged(pre_docked_mode, Settings::values.use_docked_mode);
Settings::values.vibration_enabled = ui->vibrationGroup->isChecked();
Settings::values.motion_enabled = ui->motionGroup->isChecked();
}
void ConfigureInput::changeEvent(QEvent* event) {
@@ -191,6 +196,7 @@ void ConfigureInput::LoadConfiguration() {
UpdateDockedState(Settings::values.players[8].connected);
ui->vibrationGroup->setChecked(Settings::values.vibration_enabled);
ui->motionGroup->setChecked(Settings::values.motion_enabled);
}
void ConfigureInput::LoadPlayerControllerIndices() {
@@ -217,6 +223,7 @@ void ConfigureInput::RestoreDefaults() {
ui->radioDocked->setChecked(true);
ui->radioUndocked->setChecked(false);
ui->vibrationGroup->setChecked(true);
ui->motionGroup->setChecked(true);
}
void ConfigureInput::UpdateDockedState(bool is_handheld) {

View File

@@ -18,6 +18,7 @@
#include "core/hle/service/sm/sm.h"
#include "input_common/gcadapter/gc_poller.h"
#include "input_common/main.h"
#include "input_common/udp/udp.h"
#include "ui_configure_input_player.h"
#include "yuzu/configuration/config.h"
#include "yuzu/configuration/configure_input_player.h"
@@ -149,6 +150,14 @@ QString ButtonToText(const Common::ParamPackage& param) {
return GetKeyName(param.Get("code", 0));
}
if (param.Get("engine", "") == "cemuhookudp") {
if (param.Has("pad_index")) {
const QString motion_str = QString::fromStdString(param.Get("pad_index", ""));
return QObject::tr("Motion %1").arg(motion_str);
}
return GetKeyName(param.Get("code", 0));
}
if (param.Get("engine", "") == "sdl") {
if (param.Has("hat")) {
const QString hat_str = QString::fromStdString(param.Get("hat", ""));
@@ -247,6 +256,11 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i
ui->buttonSL, ui->buttonSR, ui->buttonHome, ui->buttonScreenshot,
};
mod_buttons = {
ui->buttonLStickMod,
ui->buttonRStickMod,
};
analog_map_buttons = {{
{
ui->buttonLStickUp,
@@ -262,6 +276,11 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i
},
}};
motion_map = {
ui->buttonMotionLeft,
ui->buttonMotionRight,
};
analog_map_deadzone_label = {ui->labelLStickDeadzone, ui->labelRStickDeadzone};
analog_map_deadzone_slider = {ui->sliderLStickDeadzone, ui->sliderRStickDeadzone};
analog_map_modifier_groupbox = {ui->buttonLStickModGroup, ui->buttonRStickModGroup};
@@ -271,7 +290,7 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i
analog_map_range_spinbox = {ui->spinboxLStickRange, ui->spinboxRStickRange};
const auto ConfigureButtonClick = [&](QPushButton* button, Common::ParamPackage* param,
int default_val) {
int default_val, InputCommon::Polling::DeviceType type) {
connect(button, &QPushButton::clicked, [=, this] {
HandleClick(
button,
@@ -291,22 +310,56 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i
}
*param = std::move(params);
},
InputCommon::Polling::DeviceType::Button);
type);
});
};
for (int button_id = 0; button_id < Settings::NativeButton::NumButtons; ++button_id) {
auto* const button = button_map[button_id];
if (button == nullptr) {
continue;
}
ConfigureButtonClick(button_map[button_id], &buttons_param[button_id],
Config::default_buttons[button_id]);
Config::default_buttons[button_id],
InputCommon::Polling::DeviceType::Button);
button->setContextMenuPolicy(Qt::CustomContextMenu);
connect(button, &QPushButton::customContextMenuRequested,
[=, this](const QPoint& menu_location) {
QMenu context_menu;
context_menu.addAction(tr("Clear"), [&] {
buttons_param[button_id].Clear();
button_map[button_id]->setText(tr("[not set]"));
});
context_menu.exec(button_map[button_id]->mapToGlobal(menu_location));
});
}
// Handle clicks for the modifier buttons as well.
ConfigureButtonClick(ui->buttonLStickMod, &lstick_mod, Config::default_stick_mod[0]);
ConfigureButtonClick(ui->buttonRStickMod, &rstick_mod, Config::default_stick_mod[1]);
for (int motion_id = 0; motion_id < Settings::NativeMotion::NumMotions; ++motion_id) {
auto* const button = motion_map[motion_id];
if (button == nullptr) {
continue;
}
ConfigureButtonClick(motion_map[motion_id], &motions_param[motion_id],
Config::default_motions[motion_id],
InputCommon::Polling::DeviceType::Motion);
button->setContextMenuPolicy(Qt::CustomContextMenu);
connect(button, &QPushButton::customContextMenuRequested,
[=, this](const QPoint& menu_location) {
QMenu context_menu;
context_menu.addAction(tr("Clear"), [&] {
motions_param[motion_id].Clear();
motion_map[motion_id]->setText(tr("[not set]"));
});
context_menu.exec(motion_map[motion_id]->mapToGlobal(menu_location));
});
}
for (int analog_id = 0; analog_id < Settings::NativeAnalog::NumAnalogs; ++analog_id) {
for (int sub_button_id = 0; sub_button_id < ANALOG_SUB_BUTTONS_NUM; ++sub_button_id) {
@@ -325,8 +378,38 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i
},
InputCommon::Polling::DeviceType::AnalogPreferred);
});
analog_button->setContextMenuPolicy(Qt::CustomContextMenu);
connect(analog_button, &QPushButton::customContextMenuRequested,
[=, this](const QPoint& menu_location) {
QMenu context_menu;
context_menu.addAction(tr("Clear"), [&] {
analogs_param[analog_id].Clear();
analog_map_buttons[analog_id][sub_button_id]->setText(tr("[not set]"));
});
context_menu.exec(analog_map_buttons[analog_id][sub_button_id]->mapToGlobal(
menu_location));
});
}
// Handle clicks for the modifier buttons as well.
ConfigureButtonClick(mod_buttons[analog_id], &stick_mod_param[analog_id],
Config::default_stick_mod[analog_id],
InputCommon::Polling::DeviceType::Button);
mod_buttons[analog_id]->setContextMenuPolicy(Qt::CustomContextMenu);
connect(mod_buttons[analog_id], &QPushButton::customContextMenuRequested,
[=, this](const QPoint& menu_location) {
QMenu context_menu;
context_menu.addAction(tr("Clear"), [&] {
stick_mod_param[analog_id].Clear();
mod_buttons[analog_id]->setText(tr("[not set]"));
});
context_menu.exec(mod_buttons[analog_id]->mapToGlobal(menu_location));
});
connect(analog_map_range_spinbox[analog_id], qOverload<int>(&QSpinBox::valueChanged),
[=, this] {
const auto spinbox_value = analog_map_range_spinbox[analog_id]->value();
@@ -385,9 +468,11 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i
UpdateControllerIcon();
UpdateControllerAvailableButtons();
UpdateMotionButtons();
connect(ui->comboControllerType, qOverload<int>(&QComboBox::currentIndexChanged), [this](int) {
UpdateControllerIcon();
UpdateControllerAvailableButtons();
UpdateMotionButtons();
});
connect(ui->comboDevices, qOverload<int>(&QComboBox::currentIndexChanged), this,
@@ -417,6 +502,13 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i
return;
}
}
if (input_subsystem->GetUDPMotions()->IsPolling()) {
params = input_subsystem->GetUDPMotions()->GetNextInput();
if (params.Has("engine")) {
SetPollingResult(params, false);
return;
}
}
for (auto& poller : device_pollers) {
params = poller->GetNextInput();
if (params.Has("engine")) {
@@ -448,6 +540,10 @@ void ConfigureInputPlayer::ApplyConfiguration() {
return;
}
auto& motions = player.motions;
std::transform(motions_param.begin(), motions_param.end(), motions.begin(),
[](const Common::ParamPackage& param) { return param.Serialize(); });
player.controller_type =
static_cast<Settings::ControllerType>(ui->comboControllerType->currentIndex());
player.connected = ui->groupConnectedController->isChecked();
@@ -501,6 +597,8 @@ void ConfigureInputPlayer::LoadConfiguration() {
[](const std::string& str) { return Common::ParamPackage(str); });
std::transform(player.analogs.begin(), player.analogs.end(), analogs_param.begin(),
[](const std::string& str) { return Common::ParamPackage(str); });
std::transform(player.motions.begin(), player.motions.end(), motions_param.begin(),
[](const std::string& str) { return Common::ParamPackage(str); });
}
UpdateUI();
@@ -530,20 +628,23 @@ void ConfigureInputPlayer::RestoreDefaults() {
InputCommon::GenerateKeyboardParam(Config::default_buttons[button_id])};
}
// Reset Modifier Buttons
lstick_mod =
Common::ParamPackage(InputCommon::GenerateKeyboardParam(Config::default_stick_mod[0]));
rstick_mod =
Common::ParamPackage(InputCommon::GenerateKeyboardParam(Config::default_stick_mod[1]));
// Reset Analogs
// Reset Analogs and Modifier Buttons
for (int analog_id = 0; analog_id < Settings::NativeAnalog::NumAnalogs; ++analog_id) {
for (int sub_button_id = 0; sub_button_id < ANALOG_SUB_BUTTONS_NUM; ++sub_button_id) {
Common::ParamPackage params{InputCommon::GenerateKeyboardParam(
Config::default_analogs[analog_id][sub_button_id])};
SetAnalogParam(params, analogs_param[analog_id], analog_sub_buttons[sub_button_id]);
}
stick_mod_param[analog_id] = Common::ParamPackage(
InputCommon::GenerateKeyboardParam(Config::default_stick_mod[analog_id]));
}
for (int motion_id = 0; motion_id < Settings::NativeMotion::NumMotions; ++motion_id) {
motions_param[motion_id] = Common::ParamPackage{
InputCommon::GenerateKeyboardParam(Config::default_motions[motion_id])};
}
UpdateUI();
UpdateInputDevices();
ui->comboControllerType->setCurrentIndex(0);
@@ -552,25 +653,33 @@ void ConfigureInputPlayer::RestoreDefaults() {
void ConfigureInputPlayer::ClearAll() {
for (int button_id = 0; button_id < Settings::NativeButton::NumButtons; ++button_id) {
const auto* const button = button_map[button_id];
if (button == nullptr || !button->isEnabled()) {
if (button == nullptr) {
continue;
}
buttons_param[button_id].Clear();
}
lstick_mod.Clear();
rstick_mod.Clear();
for (int analog_id = 0; analog_id < Settings::NativeAnalog::NumAnalogs; ++analog_id) {
for (int sub_button_id = 0; sub_button_id < ANALOG_SUB_BUTTONS_NUM; ++sub_button_id) {
const auto* const analog_button = analog_map_buttons[analog_id][sub_button_id];
if (analog_button == nullptr || !analog_button->isEnabled()) {
if (analog_button == nullptr) {
continue;
}
analogs_param[analog_id].Clear();
}
stick_mod_param[analog_id].Clear();
}
for (int motion_id = 0; motion_id < Settings::NativeMotion::NumMotions; ++motion_id) {
const auto* const motion_button = motion_map[motion_id];
if (motion_button == nullptr) {
continue;
}
motions_param[motion_id].Clear();
}
UpdateUI();
@@ -582,8 +691,9 @@ void ConfigureInputPlayer::UpdateUI() {
button_map[button]->setText(ButtonToText(buttons_param[button]));
}
ui->buttonLStickMod->setText(ButtonToText(lstick_mod));
ui->buttonRStickMod->setText(ButtonToText(rstick_mod));
for (int motion_id = 0; motion_id < Settings::NativeMotion::NumMotions; ++motion_id) {
motion_map[motion_id]->setText(ButtonToText(motions_param[motion_id]));
}
for (int analog_id = 0; analog_id < Settings::NativeAnalog::NumAnalogs; ++analog_id) {
for (int sub_button_id = 0; sub_button_id < ANALOG_SUB_BUTTONS_NUM; ++sub_button_id) {
@@ -597,6 +707,8 @@ void ConfigureInputPlayer::UpdateUI() {
AnalogToText(analogs_param[analog_id], analog_sub_buttons[sub_button_id]));
}
mod_buttons[analog_id]->setText(ButtonToText(stick_mod_param[analog_id]));
const auto deadzone_label = analog_map_deadzone_label[analog_id];
const auto deadzone_slider = analog_map_deadzone_slider[analog_id];
const auto modifier_groupbox = analog_map_modifier_groupbox[analog_id];
@@ -659,7 +771,11 @@ void ConfigureInputPlayer::UpdateMappingWithDefaults() {
void ConfigureInputPlayer::HandleClick(
QPushButton* button, std::function<void(const Common::ParamPackage&)> new_input_setter,
InputCommon::Polling::DeviceType type) {
button->setText(tr("[waiting]"));
if (button == ui->buttonMotionLeft || button == ui->buttonMotionRight) {
button->setText(tr("Shake!"));
} else {
button->setText(tr("[waiting]"));
}
button->setFocus();
// The first two input devices are always Any and Keyboard/Mouse. If the user filtered to a
@@ -683,6 +799,10 @@ void ConfigureInputPlayer::HandleClick(
input_subsystem->GetGCAnalogs()->BeginConfiguration();
}
if (type == InputCommon::Polling::DeviceType::Motion) {
input_subsystem->GetUDPMotions()->BeginConfiguration();
}
timeout_timer->start(2500); // Cancel after 2.5 seconds
poll_timer->start(50); // Check for new inputs every 50ms
}
@@ -700,6 +820,8 @@ void ConfigureInputPlayer::SetPollingResult(const Common::ParamPackage& params,
input_subsystem->GetGCButtons()->EndConfiguration();
input_subsystem->GetGCAnalogs()->EndConfiguration();
input_subsystem->GetUDPMotions()->EndConfiguration();
if (!abort) {
(*input_setter)(params);
}
@@ -832,6 +954,37 @@ void ConfigureInputPlayer::UpdateControllerAvailableButtons() {
}
}
void ConfigureInputPlayer::UpdateMotionButtons() {
if (debug) {
// Motion isn't used with the debug controller, hide both groupboxes.
ui->buttonMotionLeftGroup->hide();
ui->buttonMotionRightGroup->hide();
return;
}
// Show/hide the "Motion 1/2" groupboxes depending on the currently selected controller.
switch (GetControllerTypeFromIndex(ui->comboControllerType->currentIndex())) {
case Settings::ControllerType::ProController:
case Settings::ControllerType::LeftJoycon:
case Settings::ControllerType::Handheld:
// Show "Motion 1" and hide "Motion 2".
ui->buttonMotionLeftGroup->show();
ui->buttonMotionRightGroup->hide();
break;
case Settings::ControllerType::RightJoycon:
// Show "Motion 2" and hide "Motion 1".
ui->buttonMotionLeftGroup->hide();
ui->buttonMotionRightGroup->show();
break;
case Settings::ControllerType::DualJoyconDetached:
default:
// Show both "Motion 1/2".
ui->buttonMotionLeftGroup->show();
ui->buttonMotionRightGroup->show();
break;
}
}
void ConfigureInputPlayer::showEvent(QShowEvent* event) {
if (bottom_row == nullptr) {
return;

View File

@@ -107,6 +107,9 @@ private:
/// Hides and disables controller settings based on the current controller type.
void UpdateControllerAvailableButtons();
/// Shows or hides motion groupboxes based on the current controller type.
void UpdateMotionButtons();
/// Gets the default controller mapping for this device and auto configures the input to match.
void UpdateMappingWithDefaults();
@@ -128,14 +131,17 @@ private:
std::array<Common::ParamPackage, Settings::NativeButton::NumButtons> buttons_param;
std::array<Common::ParamPackage, Settings::NativeAnalog::NumAnalogs> analogs_param;
std::array<Common::ParamPackage, Settings::NativeAnalog::NumAnalogs> stick_mod_param;
std::array<Common::ParamPackage, Settings::NativeMotion::NumMotions> motions_param;
static constexpr int ANALOG_SUB_BUTTONS_NUM = 4;
/// Each button input is represented by a QPushButton.
std::array<QPushButton*, Settings::NativeButton::NumButtons> button_map;
/// Each motion input is represented by a QPushButton.
std::array<QPushButton*, Settings::NativeMotion::NumMotions> motion_map;
/// Extra buttons for the modifiers.
Common::ParamPackage lstick_mod;
Common::ParamPackage rstick_mod;
std::array<QPushButton*, Settings::NativeAnalog::NumAnalogs> mod_buttons;
/// A group of four QPushButtons represent one analog input. The buttons each represent up,
/// down, left, right, respectively.

View File

@@ -1983,6 +1983,9 @@
<property name="spacing">
<number>3</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<item>
<spacer name="horizontalSpacerMiscButtons1">
<property name="orientation">
@@ -1990,12 +1993,110 @@
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>0</height>
<width>20</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QGroupBox" name="buttonMotionLeftGroup">
<property name="title">
<string>Motion 1</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
<layout class="QVBoxLayout" name="buttonDpadLeftVerticalLayout_2">
<property name="spacing">
<number>3</number>
</property>
<property name="leftMargin">
<number>3</number>
</property>
<property name="topMargin">
<number>3</number>
</property>
<property name="rightMargin">
<number>3</number>
</property>
<property name="bottomMargin">
<number>3</number>
</property>
<item>
<widget class="QPushButton" name="buttonMotionLeft">
<property name="minimumSize">
<size>
<width>57</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>55</width>
<height>16777215</height>
</size>
</property>
<property name="styleSheet">
<string notr="true">min-width: 55px;</string>
</property>
<property name="text">
<string>Left</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="buttonMotionRightGroup">
<property name="title">
<string>Motion 2</string>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
<layout class="QVBoxLayout" name="buttonDpadRightVerticalLayout_2">
<property name="spacing">
<number>3</number>
</property>
<property name="leftMargin">
<number>3</number>
</property>
<property name="topMargin">
<number>3</number>
</property>
<property name="rightMargin">
<number>3</number>
</property>
<property name="bottomMargin">
<number>3</number>
</property>
<item>
<widget class="QPushButton" name="buttonMotionRight">
<property name="minimumSize">
<size>
<width>57</width>
<height>0</height>
</size>
</property>
<property name="maximumSize">
<size>
<width>55</width>
<height>16777215</height>
</size>
</property>
<property name="styleSheet">
<string notr="true">min-width: 55px;</string>
</property>
<property name="text">
<string>Right</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<spacer name="horizontalSpacerMiscButtons4">
<property name="orientation">
@@ -2003,8 +2104,8 @@
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>0</height>
<width>20</width>
<height>20</height>
</size>
</property>
</spacer>

View File

@@ -162,7 +162,7 @@ std::vector<std::unique_ptr<WaitTreeItem>> WaitTreeCallstack::GetChildren() cons
thread.GetContext64());
for (auto& entry : backtrace) {
std::string s = fmt::format("{:20}{:016X} {:016X} {:016X} {}", entry.module, entry.address,
std::string s = fmt::format("{:20}{:016X} {:016X} {:016X} {}", entry.mod, entry.address,
entry.original_address, entry.offset, entry.name);
list.push_back(std::make_unique<WaitTreeText>(QString::fromStdString(s)));
}

View File

@@ -290,6 +290,8 @@ void Config::ReadValues() {
Settings::values.vibration_enabled =
sdl2_config->GetBoolean("ControlsGeneral", "vibration_enabled", true);
Settings::values.motion_enabled =
sdl2_config->GetBoolean("ControlsGeneral", "motion_enabled", true);
Settings::values.touchscreen.enabled =
sdl2_config->GetBoolean("ControlsGeneral", "touch_enabled", true);
Settings::values.touchscreen.device =

View File

@@ -76,6 +76,7 @@ void Config::ReadValues() {
}
Settings::values.vibration_enabled = true;
Settings::values.motion_enabled = true;
Settings::values.touchscreen.enabled = "";
Settings::values.touchscreen.device = "";
Settings::values.touchscreen.finger = 0;