early-access version 2201

This commit is contained in:
pineappleEA 2021-11-15 02:13:48 +01:00
parent ecea1de808
commit e7e23d3a10
88 changed files with 4284 additions and 4864 deletions

View file

@ -1,7 +1,7 @@
yuzu emulator early access yuzu emulator early access
============= =============
This is the source code for early-access 2200. This is the source code for early-access 2201.
## Legal Notice ## Legal Notice

View file

@ -73,6 +73,7 @@ add_library(common STATIC
hex_util.h hex_util.h
host_memory.cpp host_memory.cpp
host_memory.h host_memory.h
input.h
intrusive_red_black_tree.h intrusive_red_black_tree.h
literals.h literals.h
logging/backend.cpp logging/backend.cpp

View file

@ -6,7 +6,6 @@
#include <algorithm> #include <algorithm>
#include <array> #include <array>
#include <atomic>
#include <map> #include <map>
#include <optional> #include <optional>
#include <string> #include <string>
@ -560,25 +559,18 @@ struct Values {
Setting<bool> enable_accurate_vibrations{false, "enable_accurate_vibrations"}; Setting<bool> enable_accurate_vibrations{false, "enable_accurate_vibrations"};
Setting<bool> motion_enabled{true, "motion_enabled"}; Setting<bool> motion_enabled{true, "motion_enabled"};
BasicSetting<std::string> motion_device{"engine:motion_emu,update_period:100,sensitivity:0.01",
"motion_device"};
BasicSetting<std::string> udp_input_servers{"127.0.0.1:26760", "udp_input_servers"}; BasicSetting<std::string> udp_input_servers{"127.0.0.1:26760", "udp_input_servers"};
BasicSetting<bool> pause_tas_on_load{true, "pause_tas_on_load"}; BasicSetting<bool> pause_tas_on_load{true, "pause_tas_on_load"};
BasicSetting<bool> tas_enable{false, "tas_enable"}; BasicSetting<bool> tas_enable{false, "tas_enable"};
BasicSetting<bool> tas_loop{false, "tas_loop"}; BasicSetting<bool> tas_loop{false, "tas_loop"};
BasicSetting<bool> tas_swap_controllers{true, "tas_swap_controllers"};
BasicSetting<bool> mouse_panning{false, "mouse_panning"}; BasicSetting<bool> mouse_panning{false, "mouse_panning"};
BasicRangedSetting<u8> mouse_panning_sensitivity{10, 1, 100, "mouse_panning_sensitivity"}; BasicRangedSetting<u8> mouse_panning_sensitivity{10, 1, 100, "mouse_panning_sensitivity"};
BasicSetting<bool> mouse_enabled{false, "mouse_enabled"}; BasicSetting<bool> mouse_enabled{false, "mouse_enabled"};
std::string mouse_device;
MouseButtonsRaw mouse_buttons;
BasicSetting<bool> emulate_analog_keyboard{false, "emulate_analog_keyboard"}; BasicSetting<bool> emulate_analog_keyboard{false, "emulate_analog_keyboard"};
BasicSetting<bool> keyboard_enabled{false, "keyboard_enabled"}; BasicSetting<bool> keyboard_enabled{false, "keyboard_enabled"};
KeyboardKeysRaw keyboard_keys;
KeyboardModsRaw keyboard_mods;
BasicSetting<bool> debug_pad_enabled{false, "debug_pad_enabled"}; BasicSetting<bool> debug_pad_enabled{false, "debug_pad_enabled"};
ButtonsRaw debug_pad_buttons; ButtonsRaw debug_pad_buttons;
@ -586,14 +578,11 @@ struct Values {
TouchscreenInput touchscreen; TouchscreenInput touchscreen;
BasicSetting<bool> use_touch_from_button{false, "use_touch_from_button"};
BasicSetting<std::string> touch_device{"min_x:100,min_y:50,max_x:1800,max_y:850", BasicSetting<std::string> touch_device{"min_x:100,min_y:50,max_x:1800,max_y:850",
"touch_device"}; "touch_device"};
BasicSetting<int> touch_from_button_map_index{0, "touch_from_button_map"}; BasicSetting<int> touch_from_button_map_index{0, "touch_from_button_map"};
std::vector<TouchFromButtonMap> touch_from_button_maps; std::vector<TouchFromButtonMap> touch_from_button_maps;
std::atomic_bool is_device_reload_pending{true};
// Data Storage // Data Storage
BasicSetting<bool> use_virtual_sd{true, "use_virtual_sd"}; BasicSetting<bool> use_virtual_sd{true, "use_virtual_sd"};
BasicSetting<bool> gamecard_inserted{false, "gamecard_inserted"}; BasicSetting<bool> gamecard_inserted{false, "gamecard_inserted"};

View file

@ -62,11 +62,22 @@ enum Values : int {
constexpr int STICK_HID_BEGIN = LStick; constexpr int STICK_HID_BEGIN = LStick;
constexpr int STICK_HID_END = NumAnalogs; constexpr int STICK_HID_END = NumAnalogs;
constexpr int NUM_STICKS_HID = NumAnalogs;
extern const std::array<const char*, NumAnalogs> mapping; extern const std::array<const char*, NumAnalogs> mapping;
} // namespace NativeAnalog } // namespace NativeAnalog
namespace NativeTrigger {
enum Values : int {
LTrigger,
RTrigger,
NumTriggers,
};
constexpr int TRIGGER_HID_BEGIN = LTrigger;
constexpr int TRIGGER_HID_END = NumTriggers;
} // namespace NativeTrigger
namespace NativeVibration { namespace NativeVibration {
enum Values : int { enum Values : int {
LeftVibrationDevice, LeftVibrationDevice,
@ -115,10 +126,20 @@ constexpr int NUM_MOUSE_HID = NumMouseButtons;
extern const std::array<const char*, NumMouseButtons> mapping; extern const std::array<const char*, NumMouseButtons> mapping;
} // namespace NativeMouseButton } // namespace NativeMouseButton
namespace NativeMouseWheel {
enum Values {
X,
Y,
NumMouseWheels,
};
extern const std::array<const char*, NumMouseWheels> mapping;
} // namespace NativeMouseWheel
namespace NativeKeyboard { namespace NativeKeyboard {
enum Keys { enum Keys {
None, None,
Error,
A = 4, A = 4,
B, B,
@ -156,22 +177,22 @@ enum Keys {
N8, N8,
N9, N9,
N0, N0,
Enter, Return,
Escape, Escape,
Backspace, Backspace,
Tab, Tab,
Space, Space,
Minus, Minus,
Equal, Plus,
LeftBrace, OpenBracket,
RightBrace, CloseBracket,
Backslash, Pipe,
Tilde, Tilde,
Semicolon, Semicolon,
Apostrophe, Quote,
Grave, Backquote,
Comma, Comma,
Dot, Period,
Slash, Slash,
CapsLockKey, CapsLockKey,
@ -188,7 +209,7 @@ enum Keys {
F11, F11,
F12, F12,
SystemRequest, PrintScreen,
ScrollLockKey, ScrollLockKey,
Pause, Pause,
Insert, Insert,
@ -257,8 +278,18 @@ enum Keys {
ScrollLockActive, ScrollLockActive,
KPComma, KPComma,
KPLeftParenthesis, Ro = 0x87,
KPRightParenthesis, KatakanaHiragana,
Yen,
Henkan,
Muhenkan,
NumPadCommaPc98,
HangulEnglish = 0x90,
Hanja,
KatakanaKey,
HiraganaKey,
ZenkakuHankaku,
LeftControlKey = 0xE0, LeftControlKey = 0xE0,
LeftShiftKey, LeftShiftKey,
@ -307,6 +338,8 @@ enum Modifiers {
CapsLock, CapsLock,
ScrollLock, ScrollLock,
NumLock, NumLock,
Katakana,
Hiragana,
NumKeyboardMods, NumKeyboardMods,
}; };
@ -326,10 +359,6 @@ using ButtonsRaw = std::array<std::string, NativeButton::NumButtons>;
using MotionsRaw = std::array<std::string, NativeMotion::NumMotions>; using MotionsRaw = std::array<std::string, NativeMotion::NumMotions>;
using VibrationsRaw = std::array<std::string, NativeVibration::NumVibrations>; using VibrationsRaw = std::array<std::string, NativeVibration::NumVibrations>;
using MouseButtonsRaw = std::array<std::string, NativeMouseButton::NumMouseButtons>;
using KeyboardKeysRaw = std::array<std::string, NativeKeyboard::NumKeyboardKeys>;
using KeyboardModsRaw = std::array<std::string, NativeKeyboard::NumKeyboardMods>;
constexpr u32 JOYCON_BODY_NEON_RED = 0xFF3C28; constexpr u32 JOYCON_BODY_NEON_RED = 0xFF3C28;
constexpr u32 JOYCON_BUTTONS_NEON_RED = 0x1E0A0A; constexpr u32 JOYCON_BUTTONS_NEON_RED = 0x1E0A0A;
constexpr u32 JOYCON_BODY_NEON_BLUE = 0x0AB9E6; constexpr u32 JOYCON_BODY_NEON_BLUE = 0x0AB9E6;

View file

@ -132,11 +132,23 @@ add_library(core STATIC
frontend/emu_window.h frontend/emu_window.h
frontend/framebuffer_layout.cpp frontend/framebuffer_layout.cpp
frontend/framebuffer_layout.h frontend/framebuffer_layout.h
frontend/input_interpreter.cpp
frontend/input_interpreter.h
frontend/input.h
hardware_interrupt_manager.cpp hardware_interrupt_manager.cpp
hardware_interrupt_manager.h hardware_interrupt_manager.h
hid/emulated_console.cpp
hid/emulated_console.h
hid/emulated_controller.cpp
hid/emulated_controller.h
hid/emulated_devices.cpp
hid/emulated_devices.h
hid/hid_core.cpp
hid/hid_core.h
hid/hid_types.h
hid/input_converter.cpp
hid/input_converter.h
hid/input_interpreter.cpp
hid/input_interpreter.h
hid/motion_input.cpp
hid/motion_input.h
hle/api_version.h hle/api_version.h
hle/ipc.h hle/ipc.h
hle/ipc_helpers.h hle/ipc_helpers.h
@ -402,6 +414,7 @@ add_library(core STATIC
hle/service/hid/hid.h hle/service/hid/hid.h
hle/service/hid/irs.cpp hle/service/hid/irs.cpp
hle/service/hid/irs.h hle/service/hid/irs.h
hle/service/hid/ring_lifo.h
hle/service/hid/xcd.cpp hle/service/hid/xcd.cpp
hle/service/hid/xcd.h hle/service/hid/xcd.h
hle/service/hid/errors.h hle/service/hid/errors.h

View file

@ -27,6 +27,7 @@
#include "core/file_sys/vfs_concat.h" #include "core/file_sys/vfs_concat.h"
#include "core/file_sys/vfs_real.h" #include "core/file_sys/vfs_real.h"
#include "core/hardware_interrupt_manager.h" #include "core/hardware_interrupt_manager.h"
#include "core/hid/hid_core.h"
#include "core/hle/kernel/k_process.h" #include "core/hle/kernel/k_process.h"
#include "core/hle/kernel/k_scheduler.h" #include "core/hle/kernel/k_scheduler.h"
#include "core/hle/kernel/kernel.h" #include "core/hle/kernel/kernel.h"
@ -126,7 +127,7 @@ FileSys::VirtualFile GetGameFileFromPath(const FileSys::VirtualFilesystem& vfs,
struct System::Impl { struct System::Impl {
explicit Impl(System& system) explicit Impl(System& system)
: kernel{system}, fs_controller{system}, memory{system}, : kernel{system}, fs_controller{system}, memory{system}, hid_core{},
cpu_manager{system}, reporter{system}, applet_manager{system}, time_manager{system} {} cpu_manager{system}, reporter{system}, applet_manager{system}, time_manager{system} {}
SystemResultStatus Run() { SystemResultStatus Run() {
@ -391,6 +392,7 @@ struct System::Impl {
std::unique_ptr<Hardware::InterruptManager> interrupt_manager; std::unique_ptr<Hardware::InterruptManager> interrupt_manager;
std::unique_ptr<Core::DeviceMemory> device_memory; std::unique_ptr<Core::DeviceMemory> device_memory;
Core::Memory::Memory memory; Core::Memory::Memory memory;
Core::HID::HIDCore hid_core;
CpuManager cpu_manager; CpuManager cpu_manager;
std::atomic_bool is_powered_on{}; std::atomic_bool is_powered_on{};
bool exit_lock = false; bool exit_lock = false;
@ -615,6 +617,14 @@ const Kernel::KernelCore& System::Kernel() const {
return impl->kernel; return impl->kernel;
} }
HID::HIDCore& System::HIDCore() {
return impl->hid_core;
}
const HID::HIDCore& System::HIDCore() const {
return impl->hid_core;
}
Timing::CoreTiming& System::CoreTiming() { Timing::CoreTiming& System::CoreTiming() {
return impl->core_timing; return impl->core_timing;
} }
@ -825,8 +835,6 @@ void System::ApplySettings() {
if (IsPoweredOn()) { if (IsPoweredOn()) {
Renderer().RefreshBaseSettings(); Renderer().RefreshBaseSettings();
} }
Service::HID::ReloadInputDevices();
} }
} // namespace Core } // namespace Core

View file

@ -89,6 +89,10 @@ namespace Core::Hardware {
class InterruptManager; class InterruptManager;
} }
namespace Core::HID {
class HIDCore;
}
namespace Core { namespace Core {
class ARM_Interface; class ARM_Interface;
@ -285,6 +289,12 @@ public:
/// Provides a constant reference to the kernel instance. /// Provides a constant reference to the kernel instance.
[[nodiscard]] const Kernel::KernelCore& Kernel() const; [[nodiscard]] const Kernel::KernelCore& Kernel() const;
/// Gets a mutable reference to the HID interface.
[[nodiscard]] HID::HIDCore& HIDCore();
/// Gets an immutable reference to the HID interface.
[[nodiscard]] const HID::HIDCore& HIDCore() const;
/// Provides a reference to the internal PerfStats instance. /// Provides a reference to the internal PerfStats instance.
[[nodiscard]] Core::PerfStats& GetPerfStats(); [[nodiscard]] Core::PerfStats& GetPerfStats();

View file

@ -5,16 +5,15 @@
#include "common/assert.h" #include "common/assert.h"
#include "common/logging/log.h" #include "common/logging/log.h"
#include "core/frontend/applets/controller.h" #include "core/frontend/applets/controller.h"
#include "core/hle/service/hid/controllers/npad.h" #include "core/hid/emulated_controller.h"
#include "core/hle/service/hid/hid.h" #include "core/hid/hid_core.h"
#include "core/hle/service/sm/sm.h" #include "core/hid/hid_types.h"
namespace Core::Frontend { namespace Core::Frontend {
ControllerApplet::~ControllerApplet() = default; ControllerApplet::~ControllerApplet() = default;
DefaultControllerApplet::DefaultControllerApplet(Service::SM::ServiceManager& service_manager_) DefaultControllerApplet::DefaultControllerApplet(HID::HIDCore& hid_core_) : hid_core{hid_core_} {}
: service_manager{service_manager_} {}
DefaultControllerApplet::~DefaultControllerApplet() = default; DefaultControllerApplet::~DefaultControllerApplet() = default;
@ -22,24 +21,20 @@ void DefaultControllerApplet::ReconfigureControllers(std::function<void()> callb
const ControllerParameters& parameters) const { const ControllerParameters& parameters) const {
LOG_INFO(Service_HID, "called, deducing the best configuration based on the given parameters!"); LOG_INFO(Service_HID, "called, deducing the best configuration based on the given parameters!");
auto& npad =
service_manager.GetService<Service::HID::Hid>("hid")
->GetAppletResource()
->GetController<Service::HID::Controller_NPad>(Service::HID::HidController::NPad);
auto& players = Settings::values.players.GetValue();
const std::size_t min_supported_players = const std::size_t min_supported_players =
parameters.enable_single_mode ? 1 : parameters.min_players; parameters.enable_single_mode ? 1 : parameters.min_players;
// Disconnect Handheld first. // Disconnect Handheld first.
npad.DisconnectNpadAtIndex(8); auto* handheld = hid_core.GetEmulatedController(Core::HID::NpadIdType::Handheld);
handheld->Disconnect();
// Deduce the best configuration based on the input parameters. // Deduce the best configuration based on the input parameters.
for (std::size_t index = 0; index < players.size() - 2; ++index) { for (std::size_t index = 0; index < hid_core.available_controllers - 2; ++index) {
auto* controller = hid_core.GetEmulatedControllerByIndex(index);
// First, disconnect all controllers regardless of the value of keep_controllers_connected. // First, disconnect all controllers regardless of the value of keep_controllers_connected.
// This makes it easy to connect the desired controllers. // This makes it easy to connect the desired controllers.
npad.DisconnectNpadAtIndex(index); controller->Disconnect();
// Only connect the minimum number of required players. // Only connect the minimum number of required players.
if (index >= min_supported_players) { if (index >= min_supported_players) {
@ -49,27 +44,27 @@ void DefaultControllerApplet::ReconfigureControllers(std::function<void()> callb
// Connect controllers based on the following priority list from highest to lowest priority: // Connect controllers based on the following priority list from highest to lowest priority:
// Pro Controller -> Dual Joycons -> Left Joycon/Right Joycon -> Handheld // Pro Controller -> Dual Joycons -> Left Joycon/Right Joycon -> Handheld
if (parameters.allow_pro_controller) { if (parameters.allow_pro_controller) {
npad.AddNewControllerAt( controller->SetNpadStyleIndex(Core::HID::NpadStyleIndex::ProController);
npad.MapSettingsTypeToNPad(Settings::ControllerType::ProController), index); controller->Connect();
} else if (parameters.allow_dual_joycons) { } else if (parameters.allow_dual_joycons) {
npad.AddNewControllerAt( controller->SetNpadStyleIndex(Core::HID::NpadStyleIndex::JoyconDual);
npad.MapSettingsTypeToNPad(Settings::ControllerType::DualJoyconDetached), index); controller->Connect();
} else if (parameters.allow_left_joycon && parameters.allow_right_joycon) { } else if (parameters.allow_left_joycon && parameters.allow_right_joycon) {
// Assign left joycons to even player indices and right joycons to odd player indices. // Assign left joycons to even player indices and right joycons to odd player indices.
// We do this since Captain Toad Treasure Tracker expects a left joycon for Player 1 and // We do this since Captain Toad Treasure Tracker expects a left joycon for Player 1 and
// a right Joycon for Player 2 in 2 Player Assist mode. // a right Joycon for Player 2 in 2 Player Assist mode.
if (index % 2 == 0) { if (index % 2 == 0) {
npad.AddNewControllerAt( controller->SetNpadStyleIndex(Core::HID::NpadStyleIndex::JoyconLeft);
npad.MapSettingsTypeToNPad(Settings::ControllerType::LeftJoycon), index); controller->Connect();
} else { } else {
npad.AddNewControllerAt( controller->SetNpadStyleIndex(Core::HID::NpadStyleIndex::JoyconRight);
npad.MapSettingsTypeToNPad(Settings::ControllerType::RightJoycon), index); controller->Connect();
} }
} else if (index == 0 && parameters.enable_single_mode && parameters.allow_handheld && } else if (index == 0 && parameters.enable_single_mode && parameters.allow_handheld &&
!Settings::values.use_docked_mode.GetValue()) { !Settings::values.use_docked_mode.GetValue()) {
// We should *never* reach here under any normal circumstances. // We should *never* reach here under any normal circumstances.
npad.AddNewControllerAt(npad.MapSettingsTypeToNPad(Settings::ControllerType::Handheld), controller->SetNpadStyleIndex(Core::HID::NpadStyleIndex::Handheld);
index); controller->Connect();
} else { } else {
UNREACHABLE_MSG("Unable to add a new controller based on the given parameters!"); UNREACHABLE_MSG("Unable to add a new controller based on the given parameters!");
} }

View file

@ -8,8 +8,8 @@
#include "common/common_types.h" #include "common/common_types.h"
namespace Service::SM { namespace Core::HID {
class ServiceManager; class HIDCore;
} }
namespace Core::Frontend { namespace Core::Frontend {
@ -44,14 +44,14 @@ public:
class DefaultControllerApplet final : public ControllerApplet { class DefaultControllerApplet final : public ControllerApplet {
public: public:
explicit DefaultControllerApplet(Service::SM::ServiceManager& service_manager_); explicit DefaultControllerApplet(HID::HIDCore& hid_core_);
~DefaultControllerApplet() override; ~DefaultControllerApplet() override;
void ReconfigureControllers(std::function<void()> callback, void ReconfigureControllers(std::function<void()> callback,
const ControllerParameters& parameters) const override; const ControllerParameters& parameters) const override;
private: private:
Service::SM::ServiceManager& service_manager; HID::HIDCore& hid_core;
}; };
} // namespace Core::Frontend } // namespace Core::Frontend

View file

@ -3,66 +3,31 @@
// Refer to the license.txt file included. // Refer to the license.txt file included.
#include <mutex> #include <mutex>
#include "common/settings.h"
#include "core/frontend/emu_window.h" #include "core/frontend/emu_window.h"
#include "core/frontend/input.h"
namespace Core::Frontend { namespace Core::Frontend {
GraphicsContext::~GraphicsContext() = default; GraphicsContext::~GraphicsContext() = default;
class EmuWindow::TouchState : public Input::Factory<Input::TouchDevice>,
public std::enable_shared_from_this<TouchState> {
public:
std::unique_ptr<Input::TouchDevice> Create(const Common::ParamPackage&) override {
return std::make_unique<Device>(shared_from_this());
}
std::mutex mutex;
Input::TouchStatus status;
private:
class Device : public Input::TouchDevice {
public:
explicit Device(std::weak_ptr<TouchState>&& touch_state_) : touch_state(touch_state_) {}
Input::TouchStatus GetStatus() const override {
if (auto state = touch_state.lock()) {
std::lock_guard guard{state->mutex};
return state->status;
}
return {};
}
private:
std::weak_ptr<TouchState> touch_state;
};
};
EmuWindow::EmuWindow() { EmuWindow::EmuWindow() {
// TODO: Find a better place to set this. // TODO: Find a better place to set this.
config.min_client_area_size = config.min_client_area_size =
std::make_pair(Layout::MinimumSize::Width, Layout::MinimumSize::Height); std::make_pair(Layout::MinimumSize::Width, Layout::MinimumSize::Height);
active_config = config; active_config = config;
touch_state = std::make_shared<TouchState>();
Input::RegisterFactory<Input::TouchDevice>("emu_window", touch_state);
} }
EmuWindow::~EmuWindow() { EmuWindow::~EmuWindow() {}
Input::UnregisterFactory<Input::TouchDevice>("emu_window");
}
/** std::pair<f32, f32> EmuWindow::MapToTouchScreen(u32 framebuffer_x, u32 framebuffer_y) const {
* Check if the given x/y coordinates are within the touchpad specified by the framebuffer layout std::tie(framebuffer_x, framebuffer_y) = ClipToTouchScreen(framebuffer_x, framebuffer_y);
* @param layout FramebufferLayout object describing the framebuffer size and screen positions const float x =
* @param framebuffer_x Framebuffer x-coordinate to check static_cast<float>(framebuffer_x - framebuffer_layout.screen.left) /
* @param framebuffer_y Framebuffer y-coordinate to check static_cast<float>(framebuffer_layout.screen.right - framebuffer_layout.screen.left);
* @return True if the coordinates are within the touchpad, otherwise false const float y =
*/ static_cast<float>(framebuffer_y - framebuffer_layout.screen.top) /
static bool IsWithinTouchscreen(const Layout::FramebufferLayout& layout, u32 framebuffer_x, static_cast<float>(framebuffer_layout.screen.bottom - framebuffer_layout.screen.top);
u32 framebuffer_y) {
return (framebuffer_y >= layout.screen.top && framebuffer_y < layout.screen.bottom && return std::make_pair(x, y);
framebuffer_x >= layout.screen.left && framebuffer_x < layout.screen.right);
} }
std::pair<u32, u32> EmuWindow::ClipToTouchScreen(u32 new_x, u32 new_y) const { std::pair<u32, u32> EmuWindow::ClipToTouchScreen(u32 new_x, u32 new_y) const {
@ -75,49 +40,6 @@ std::pair<u32, u32> EmuWindow::ClipToTouchScreen(u32 new_x, u32 new_y) const {
return std::make_pair(new_x, new_y); return std::make_pair(new_x, new_y);
} }
void EmuWindow::TouchPressed(u32 framebuffer_x, u32 framebuffer_y, size_t id) {
if (!IsWithinTouchscreen(framebuffer_layout, framebuffer_x, framebuffer_y)) {
return;
}
if (id >= touch_state->status.size()) {
return;
}
std::lock_guard guard{touch_state->mutex};
const float x =
static_cast<float>(framebuffer_x - framebuffer_layout.screen.left) /
static_cast<float>(framebuffer_layout.screen.right - framebuffer_layout.screen.left);
const float y =
static_cast<float>(framebuffer_y - framebuffer_layout.screen.top) /
static_cast<float>(framebuffer_layout.screen.bottom - framebuffer_layout.screen.top);
touch_state->status[id] = std::make_tuple(x, y, true);
}
void EmuWindow::TouchReleased(size_t id) {
if (id >= touch_state->status.size()) {
return;
}
std::lock_guard guard{touch_state->mutex};
touch_state->status[id] = std::make_tuple(0.0f, 0.0f, false);
}
void EmuWindow::TouchMoved(u32 framebuffer_x, u32 framebuffer_y, size_t id) {
if (id >= touch_state->status.size()) {
return;
}
if (!std::get<2>(touch_state->status[id])) {
return;
}
if (!IsWithinTouchscreen(framebuffer_layout, framebuffer_x, framebuffer_y)) {
std::tie(framebuffer_x, framebuffer_y) = ClipToTouchScreen(framebuffer_x, framebuffer_y);
}
TouchPressed(framebuffer_x, framebuffer_y, id);
}
void EmuWindow::UpdateCurrentFramebufferLayout(u32 width, u32 height) { void EmuWindow::UpdateCurrentFramebufferLayout(u32 width, u32 height) {
NotifyFramebufferLayoutChanged(Layout::DefaultFrameLayout(width, height)); NotifyFramebufferLayoutChanged(Layout::DefaultFrameLayout(width, height));
} }

View file

@ -112,28 +112,6 @@ public:
/// Returns if window is shown (not minimized) /// Returns if window is shown (not minimized)
virtual bool IsShown() const = 0; virtual bool IsShown() const = 0;
/**
* Signal that a touch pressed event has occurred (e.g. mouse click pressed)
* @param framebuffer_x Framebuffer x-coordinate that was pressed
* @param framebuffer_y Framebuffer y-coordinate that was pressed
* @param id Touch event ID
*/
void TouchPressed(u32 framebuffer_x, u32 framebuffer_y, size_t id);
/**
* Signal that a touch released event has occurred (e.g. mouse click released)
* @param id Touch event ID
*/
void TouchReleased(size_t id);
/**
* Signal that a touch movement event has occurred (e.g. mouse was moved over the emu window)
* @param framebuffer_x Framebuffer x-coordinate
* @param framebuffer_y Framebuffer y-coordinate
* @param id Touch event ID
*/
void TouchMoved(u32 framebuffer_x, u32 framebuffer_y, size_t id);
/** /**
* Returns currently active configuration. * Returns currently active configuration.
* @note Accesses to the returned object need not be consistent because it may be modified in * @note Accesses to the returned object need not be consistent because it may be modified in
@ -212,6 +190,11 @@ protected:
client_area_height = size.second; client_area_height = size.second;
} }
/**
* Converts a screen postion into the equivalent touchscreen position.
*/
std::pair<f32, f32> MapToTouchScreen(u32 framebuffer_x, u32 framebuffer_y) const;
WindowSystemInfo window_info; WindowSystemInfo window_info;
private: private:
@ -237,9 +220,6 @@ private:
WindowConfig config; ///< Internal configuration (changes pending for being applied in WindowConfig config; ///< Internal configuration (changes pending for being applied in
/// ProcessConfigurationChanges) /// ProcessConfigurationChanges)
WindowConfig active_config; ///< Internal active configuration WindowConfig active_config; ///< Internal active configuration
class TouchState;
std::shared_ptr<TouchState> touch_state;
}; };
} // namespace Core::Frontend } // namespace Core::Frontend

View file

@ -24,7 +24,10 @@ void EmulatedConsole::SetTouchParams() {
std::size_t index = 0; std::size_t index = 0;
// Hardcode mouse, touchscreen and cemuhook parameters // Hardcode mouse, touchscreen and cemuhook parameters
if (!Settings::values.mouse_enabled) {
// We can't use mouse as touch if native mouse is enabled
touch_params[index++] = Common::ParamPackage{"engine:mouse,axis_x:10,axis_y:11,button:0"}; touch_params[index++] = Common::ParamPackage{"engine:mouse,axis_x:10,axis_y:11,button:0"};
}
touch_params[index++] = Common::ParamPackage{"engine:touch,axis_x:0,axis_y:1,button:0"}; touch_params[index++] = Common::ParamPackage{"engine:touch,axis_x:0,axis_y:1,button:0"};
touch_params[index++] = Common::ParamPackage{"engine:touch,axis_x:2,axis_y:3,button:1"}; touch_params[index++] = Common::ParamPackage{"engine:touch,axis_x:2,axis_y:3,button:1"};
touch_params[index++] = Common::ParamPackage{"engine:cemuhookudp,axis_x:0,axis_y:1,button:0"}; touch_params[index++] = Common::ParamPackage{"engine:cemuhookudp,axis_x:0,axis_y:1,button:0"};
@ -36,6 +39,9 @@ void EmulatedConsole::SetTouchParams() {
// Map the rest of the fingers from touch from button configuration // Map the rest of the fingers from touch from button configuration
for (const auto& config_entry : touch_buttons) { for (const auto& config_entry : touch_buttons) {
if (index >= touch_params.size()) {
continue;
}
Common::ParamPackage params{config_entry}; Common::ParamPackage params{config_entry};
Common::ParamPackage touch_button_params; Common::ParamPackage touch_button_params;
const int x = params.Get("x", 0); const int x = params.Get("x", 0);
@ -49,9 +55,6 @@ void EmulatedConsole::SetTouchParams() {
touch_button_params.Set("touch_id", static_cast<int>(index)); touch_button_params.Set("touch_id", static_cast<int>(index));
touch_params[index] = touch_button_params; touch_params[index] = touch_button_params;
index++; index++;
if (index >= touch_params.size()) {
return;
}
} }
} }

View file

@ -15,27 +15,56 @@ EmulatedDevices::EmulatedDevices() = default;
EmulatedDevices::~EmulatedDevices() = default; EmulatedDevices::~EmulatedDevices() = default;
void EmulatedDevices::ReloadFromSettings() { void EmulatedDevices::ReloadFromSettings() {
const auto& mouse = Settings::values.mouse_buttons;
for (std::size_t index = 0; index < mouse.size(); ++index) {
mouse_button_params[index] = Common::ParamPackage(mouse[index]);
}
ReloadInput(); ReloadInput();
} }
void EmulatedDevices::ReloadInput() { void EmulatedDevices::ReloadInput() {
std::transform(mouse_button_params.begin() + Settings::NativeMouseButton::MOUSE_HID_BEGIN, // If you load any device here add the equivalent to the UnloadInput() function
mouse_button_params.begin() + Settings::NativeMouseButton::MOUSE_HID_END, std::size_t key_index = 0;
mouse_button_devices.begin(), for (auto& mouse_device : mouse_button_devices) {
Common::Input::CreateDevice<Common::Input::InputDevice>); Common::ParamPackage mouse_params;
mouse_params.Set("engine", "mouse");
mouse_params.Set("button", static_cast<int>(key_index));
mouse_device = Common::Input::CreateDevice<Common::Input::InputDevice>(mouse_params);
key_index++;
}
std::transform(Settings::values.keyboard_keys.begin(), Settings::values.keyboard_keys.end(), mouse_stick_device = Common::Input::CreateDeviceFromString<Common::Input::InputDevice>(
keyboard_devices.begin(), "engine:mouse,axis_x:0,axis_y:1");
Common::Input::CreateDeviceFromString<Common::Input::InputDevice>);
std::transform(Settings::values.keyboard_mods.begin(), Settings::values.keyboard_mods.end(), // First two axis are reserved for mouse position
keyboard_modifier_devices.begin(), key_index = 2;
Common::Input::CreateDeviceFromString<Common::Input::InputDevice>); for (auto& mouse_device : mouse_analog_devices) {
Common::ParamPackage mouse_params;
mouse_params.Set("engine", "mouse");
mouse_params.Set("axis", static_cast<int>(key_index));
mouse_device = Common::Input::CreateDevice<Common::Input::InputDevice>(mouse_params);
key_index++;
}
key_index = 0;
for (auto& keyboard_device : keyboard_devices) {
// Keyboard keys are only mapped on port 1, pad 0
Common::ParamPackage keyboard_params;
keyboard_params.Set("engine", "keyboard");
keyboard_params.Set("button", static_cast<int>(key_index));
keyboard_params.Set("port", 1);
keyboard_params.Set("pad", 0);
keyboard_device = Common::Input::CreateDevice<Common::Input::InputDevice>(keyboard_params);
key_index++;
}
key_index = 0;
for (auto& keyboard_device : keyboard_modifier_devices) {
// Keyboard moddifiers are only mapped on port 1, pad 1
Common::ParamPackage keyboard_params;
keyboard_params.Set("engine", "keyboard");
keyboard_params.Set("button", static_cast<int>(key_index));
keyboard_params.Set("port", 1);
keyboard_params.Set("pad", 1);
keyboard_device = Common::Input::CreateDevice<Common::Input::InputDevice>(keyboard_params);
key_index++;
}
for (std::size_t index = 0; index < mouse_button_devices.size(); ++index) { for (std::size_t index = 0; index < mouse_button_devices.size(); ++index) {
if (!mouse_button_devices[index]) { if (!mouse_button_devices[index]) {
@ -48,6 +77,23 @@ void EmulatedDevices::ReloadInput() {
mouse_button_devices[index]->SetCallback(button_callback); mouse_button_devices[index]->SetCallback(button_callback);
} }
for (std::size_t index = 0; index < mouse_analog_devices.size(); ++index) {
if (!mouse_analog_devices[index]) {
continue;
}
Common::Input::InputCallback button_callback{
[this, index](Common::Input::CallbackStatus callback) {
SetMouseAnalog(callback, index);
}};
mouse_analog_devices[index]->SetCallback(button_callback);
}
if (mouse_stick_device) {
Common::Input::InputCallback button_callback{
[this](Common::Input::CallbackStatus callback) { SetMouseStick(callback); }};
mouse_stick_device->SetCallback(button_callback);
}
for (std::size_t index = 0; index < keyboard_devices.size(); ++index) { for (std::size_t index = 0; index < keyboard_devices.size(); ++index) {
if (!keyboard_devices[index]) { if (!keyboard_devices[index]) {
continue; continue;
@ -75,6 +121,10 @@ void EmulatedDevices::UnloadInput() {
for (auto& button : mouse_button_devices) { for (auto& button : mouse_button_devices) {
button.reset(); button.reset();
} }
for (auto& analog : mouse_analog_devices) {
analog.reset();
}
mouse_stick_device.reset();
for (auto& button : keyboard_devices) { for (auto& button : keyboard_devices) {
button.reset(); button.reset();
} }
@ -100,12 +150,6 @@ void EmulatedDevices::SaveCurrentConfig() {
if (!is_configuring) { if (!is_configuring) {
return; return;
} }
auto& mouse = Settings::values.mouse_buttons;
for (std::size_t index = 0; index < mouse.size(); ++index) {
mouse[index] = mouse_button_params[index].Serialize();
}
} }
void EmulatedDevices::RestoreConfig() { void EmulatedDevices::RestoreConfig() {
@ -115,21 +159,6 @@ void EmulatedDevices::RestoreConfig() {
ReloadFromSettings(); ReloadFromSettings();
} }
Common::ParamPackage EmulatedDevices::GetMouseButtonParam(std::size_t index) const {
if (index >= mouse_button_params.size()) {
return {};
}
return mouse_button_params[index];
}
void EmulatedDevices::SetMouseButtonParam(std::size_t index, Common::ParamPackage param) {
if (index >= mouse_button_params.size()) {
return;
}
mouse_button_params[index] = param;
ReloadInput();
}
void EmulatedDevices::SetKeyboardButton(Common::Input::CallbackStatus callback, std::size_t index) { void EmulatedDevices::SetKeyboardButton(Common::Input::CallbackStatus callback, std::size_t index) {
if (index >= device_status.keyboard_values.size()) { if (index >= device_status.keyboard_values.size()) {
return; return;
@ -318,6 +347,52 @@ void EmulatedDevices::SetMouseButton(Common::Input::CallbackStatus callback, std
TriggerOnChange(DeviceTriggerType::Mouse); TriggerOnChange(DeviceTriggerType::Mouse);
} }
void EmulatedDevices::SetMouseAnalog(Common::Input::CallbackStatus callback, std::size_t index) {
if (index >= device_status.mouse_analog_values.size()) {
return;
}
std::lock_guard lock{mutex};
const auto analog_value = TransformToAnalog(callback);
device_status.mouse_analog_values[index] = analog_value;
if (is_configuring) {
device_status.mouse_position_state = {};
TriggerOnChange(DeviceTriggerType::Mouse);
return;
}
LOG_ERROR(Input, "{}", analog_value.value);
switch (index) {
case Settings::NativeMouseWheel::X:
device_status.mouse_wheel_state.x = static_cast<s32>(analog_value.value);
break;
case Settings::NativeMouseWheel::Y:
device_status.mouse_wheel_state.y = static_cast<s32>(analog_value.value);
break;
}
TriggerOnChange(DeviceTriggerType::Mouse);
}
void EmulatedDevices::SetMouseStick(Common::Input::CallbackStatus callback) {
std::lock_guard lock{mutex};
const auto stick_value = TransformToStick(callback);
device_status.mouse_stick_value = stick_value;
if (is_configuring) {
device_status.mouse_position_state = {};
TriggerOnChange(DeviceTriggerType::Mouse);
return;
}
device_status.mouse_position_state.x = stick_value.x.value;
device_status.mouse_position_state.y = stick_value.y.value;
TriggerOnChange(DeviceTriggerType::Mouse);
}
KeyboardValues EmulatedDevices::GetKeyboardValues() const { KeyboardValues EmulatedDevices::GetKeyboardValues() const {
return device_status.keyboard_values; return device_status.keyboard_values;
} }
@ -346,6 +421,10 @@ MousePosition EmulatedDevices::GetMousePosition() const {
return device_status.mouse_position_state; return device_status.mouse_position_state;
} }
AnalogStickState EmulatedDevices::GetMouseDeltaWheel() const {
return device_status.mouse_wheel_state;
}
void EmulatedDevices::TriggerOnChange(DeviceTriggerType type) { void EmulatedDevices::TriggerOnChange(DeviceTriggerType type) {
for (const auto& poller_pair : callback_list) { for (const auto& poller_pair : callback_list) {
const InterfaceUpdateCallback& poller = poller_pair.second; const InterfaceUpdateCallback& poller = poller_pair.second;

View file

@ -17,13 +17,15 @@
#include "core/hid/hid_types.h" #include "core/hid/hid_types.h"
namespace Core::HID { namespace Core::HID {
using KeyboardDevices = std::array<std::unique_ptr<Common::Input::InputDevice>, using KeyboardDevices = std::array<std::unique_ptr<Common::Input::InputDevice>,
Settings::NativeKeyboard::NumKeyboardKeys>; Settings::NativeKeyboard::NumKeyboardKeys>;
using KeyboardModifierDevices = std::array<std::unique_ptr<Common::Input::InputDevice>, using KeyboardModifierDevices = std::array<std::unique_ptr<Common::Input::InputDevice>,
Settings::NativeKeyboard::NumKeyboardMods>; Settings::NativeKeyboard::NumKeyboardMods>;
using MouseButtonDevices = std::array<std::unique_ptr<Common::Input::InputDevice>, using MouseButtonDevices = std::array<std::unique_ptr<Common::Input::InputDevice>,
Settings::NativeMouseButton::NumMouseButtons>; Settings::NativeMouseButton::NumMouseButtons>;
using MouseAnalogDevices = std::array<std::unique_ptr<Common::Input::InputDevice>,
Settings::NativeMouseWheel::NumMouseWheels>;
using MouseStickDevice = std::unique_ptr<Common::Input::InputDevice>;
using MouseButtonParams = using MouseButtonParams =
std::array<Common::ParamPackage, Settings::NativeMouseButton::NumMouseButtons>; std::array<Common::ParamPackage, Settings::NativeMouseButton::NumMouseButtons>;
@ -34,12 +36,13 @@ using KeyboardModifierValues =
std::array<Common::Input::ButtonStatus, Settings::NativeKeyboard::NumKeyboardMods>; std::array<Common::Input::ButtonStatus, Settings::NativeKeyboard::NumKeyboardMods>;
using MouseButtonValues = using MouseButtonValues =
std::array<Common::Input::ButtonStatus, Settings::NativeMouseButton::NumMouseButtons>; std::array<Common::Input::ButtonStatus, Settings::NativeMouseButton::NumMouseButtons>;
using MouseAnalogValues =
std::array<Common::Input::AnalogStatus, Settings::NativeMouseWheel::NumMouseWheels>;
using MouseStickValue = Common::Input::StickStatus;
struct MousePosition { struct MousePosition {
s32 x; f32 x;
s32 y; f32 y;
s32 delta_wheel_x;
s32 delta_wheel_y;
}; };
struct DeviceStatus { struct DeviceStatus {
@ -47,12 +50,15 @@ struct DeviceStatus {
KeyboardValues keyboard_values{}; KeyboardValues keyboard_values{};
KeyboardModifierValues keyboard_moddifier_values{}; KeyboardModifierValues keyboard_moddifier_values{};
MouseButtonValues mouse_button_values{}; MouseButtonValues mouse_button_values{};
MouseAnalogValues mouse_analog_values{};
MouseStickValue mouse_stick_value{};
// Data for HID serices // Data for HID serices
KeyboardKey keyboard_state{}; KeyboardKey keyboard_state{};
KeyboardModifier keyboard_moddifier_state{}; KeyboardModifier keyboard_moddifier_state{};
MouseButton mouse_button_state{}; MouseButton mouse_button_state{};
MousePosition mouse_position_state{}; MousePosition mouse_position_state{};
AnalogStickState mouse_wheel_state{};
}; };
enum class DeviceTriggerType { enum class DeviceTriggerType {
@ -102,15 +108,6 @@ public:
/// Reverts any mapped changes made that weren't saved /// Reverts any mapped changes made that weren't saved
void RestoreConfig(); void RestoreConfig();
/// Returns the current mapped mouse button device
Common::ParamPackage GetMouseButtonParam(std::size_t index) const;
/**
* Updates the current mapped mouse button device
* @param ParamPackage with controller data to be mapped
*/
void SetMouseButtonParam(std::size_t index, Common::ParamPackage param);
/// Returns the latest status of button input from the keyboard with parameters /// Returns the latest status of button input from the keyboard with parameters
KeyboardValues GetKeyboardValues() const; KeyboardValues GetKeyboardValues() const;
@ -132,9 +129,12 @@ public:
/// Returns the latest mouse coordinates /// Returns the latest mouse coordinates
MousePosition GetMousePosition() const; MousePosition GetMousePosition() const;
/// Returns the latest mouse wheel change
AnalogStickState GetMouseDeltaWheel() const;
/** /**
* Adds a callback to the list of events * Adds a callback to the list of events
* @param ConsoleUpdateCallback that will be triggered * @param InterfaceUpdateCallback that will be triggered
* @return an unique key corresponding to the callback index in the list * @return an unique key corresponding to the callback index in the list
*/ */
int SetCallback(InterfaceUpdateCallback update_callback); int SetCallback(InterfaceUpdateCallback update_callback);
@ -150,26 +150,40 @@ private:
void UpdateKey(std::size_t key_index, bool status); void UpdateKey(std::size_t key_index, bool status);
/** /**
* Updates the touch status of the console * Updates the touch status of the keyboard device
* @param callback: A CallbackStatus containing the key status * @param callback: A CallbackStatus containing the key status
* @param index: key ID to be updated * @param index: key ID to be updated
*/ */
void SetKeyboardButton(Common::Input::CallbackStatus callback, std::size_t index); void SetKeyboardButton(Common::Input::CallbackStatus callback, std::size_t index);
/** /**
* Updates the touch status of the console * Updates the keyboard status of the keyboard device
* @param callback: A CallbackStatus containing the modifier key status * @param callback: A CallbackStatus containing the modifier key status
* @param index: modifier key ID to be updated * @param index: modifier key ID to be updated
*/ */
void SetKeyboardModifier(Common::Input::CallbackStatus callback, std::size_t index); void SetKeyboardModifier(Common::Input::CallbackStatus callback, std::size_t index);
/** /**
* Updates the touch status of the console * Updates the mouse button status of the mouse device
* @param callback: A CallbackStatus containing the button status * @param callback: A CallbackStatus containing the button status
* @param index: Button ID of the to be updated * @param index: Button ID to be updated
*/ */
void SetMouseButton(Common::Input::CallbackStatus callback, std::size_t index); void SetMouseButton(Common::Input::CallbackStatus callback, std::size_t index);
/**
* Updates the mouse wheel status of the mouse device
* @param callback: A CallbackStatus containing the wheel status
* @param index: wheel ID to be updated
*/
void SetMouseAnalog(Common::Input::CallbackStatus callback, std::size_t index);
/**
* Updates the mouse position status of the mouse device
* @param callback: A CallbackStatus containing the position status
* @param index: stick ID to be updated
*/
void SetMouseStick(Common::Input::CallbackStatus callback);
/** /**
* Triggers a callback that something has changed on the device status * Triggers a callback that something has changed on the device status
* @param Input type of the event to trigger * @param Input type of the event to trigger
@ -178,11 +192,11 @@ private:
bool is_configuring{false}; bool is_configuring{false};
MouseButtonParams mouse_button_params;
KeyboardDevices keyboard_devices; KeyboardDevices keyboard_devices;
KeyboardModifierDevices keyboard_modifier_devices; KeyboardModifierDevices keyboard_modifier_devices;
MouseButtonDevices mouse_button_devices; MouseButtonDevices mouse_button_devices;
MouseAnalogDevices mouse_analog_devices;
MouseStickDevice mouse_stick_device;
mutable std::mutex mutex; mutable std::mutex mutex;
std::unordered_map<int, InterfaceUpdateCallback> callback_list; std::unordered_map<int, InterfaceUpdateCallback> callback_list;

View file

@ -242,6 +242,27 @@ Common::Input::TriggerStatus TransformToTrigger(const Common::Input::CallbackSta
return status; return status;
} }
Common::Input::AnalogStatus TransformToAnalog(const Common::Input::CallbackStatus& callback) {
Common::Input::AnalogStatus status{};
switch (callback.type) {
case Common::Input::InputType::Analog:
status.properties = callback.analog_status.properties;
status.raw_value = callback.analog_status.raw_value;
break;
default:
LOG_ERROR(Input, "Conversion from type {} to analog not implemented", callback.type);
break;
}
SanitizeAnalog(status, false);
// Adjust if value is inverted
status.value = status.properties.inverted ? -status.value : status.value;
return status;
}
void SanitizeAnalog(Common::Input::AnalogStatus& analog, bool clamp_value) { void SanitizeAnalog(Common::Input::AnalogStatus& analog, bool clamp_value) {
const auto& properties = analog.properties; const auto& properties = analog.properties;
float& raw_value = analog.raw_value; float& raw_value = analog.raw_value;

View file

@ -68,6 +68,15 @@ Common::Input::TouchStatus TransformToTouch(const Common::Input::CallbackStatus&
*/ */
Common::Input::TriggerStatus TransformToTrigger(const Common::Input::CallbackStatus& callback); Common::Input::TriggerStatus TransformToTrigger(const Common::Input::CallbackStatus& callback);
/**
* Converts raw input data into a valid analog status. Applies offset, deadzone, range and
* invert properties to the output.
*
* @param Supported callbacks: Analog.
* @return A valid AnalogStatus object.
*/
Common::Input::AnalogStatus TransformToAnalog(const Common::Input::CallbackStatus& callback);
/** /**
* Converts raw analog data into a valid analog value * Converts raw analog data into a valid analog value
* @param An analog object containing raw data and properties, bool that determines if the value * @param An analog object containing raw data and properties, bool that determines if the value

View file

@ -10,6 +10,9 @@
#include "common/string_util.h" #include "common/string_util.h"
#include "core/core.h" #include "core/core.h"
#include "core/frontend/applets/controller.h" #include "core/frontend/applets/controller.h"
#include "core/hid/emulated_controller.h"
#include "core/hid/hid_core.h"
#include "core/hid/hid_types.h"
#include "core/hle/result.h" #include "core/hle/result.h"
#include "core/hle/service/am/am.h" #include "core/hle/service/am/am.h"
#include "core/hle/service/am/applets/applet_controller.h" #include "core/hle/service/am/applets/applet_controller.h"
@ -25,7 +28,7 @@ namespace Service::AM::Applets {
static Core::Frontend::ControllerParameters ConvertToFrontendParameters( static Core::Frontend::ControllerParameters ConvertToFrontendParameters(
ControllerSupportArgPrivate private_arg, ControllerSupportArgHeader header, bool enable_text, ControllerSupportArgPrivate private_arg, ControllerSupportArgHeader header, bool enable_text,
std::vector<IdentificationColor> identification_colors, std::vector<ExplainText> text) { std::vector<IdentificationColor> identification_colors, std::vector<ExplainText> text) {
HID::Controller_NPad::NpadStyleSet npad_style_set; Core::HID::NpadStyleTag npad_style_set;
npad_style_set.raw = private_arg.style_set; npad_style_set.raw = private_arg.style_set;
return { return {
@ -243,19 +246,11 @@ void Controller::Execute() {
void Controller::ConfigurationComplete() { void Controller::ConfigurationComplete() {
ControllerSupportResultInfo result_info{}; ControllerSupportResultInfo result_info{};
const auto& players = Settings::values.players.GetValue();
// If enable_single_mode is enabled, player_count is 1 regardless of any other parameters. // If enable_single_mode is enabled, player_count is 1 regardless of any other parameters.
// Otherwise, only count connected players from P1-P8. // Otherwise, only count connected players from P1-P8.
result_info.player_count = result_info.player_count = is_single_mode ? 1 : system.HIDCore().GetPlayerCount();
is_single_mode
? 1
: static_cast<s8>(std::count_if(players.begin(), players.end() - 2,
[](const auto& player) { return player.connected; }));
result_info.selected_id = HID::Controller_NPad::IndexToNPad(std::distance( result_info.selected_id = static_cast<u32>(system.HIDCore().GetFirstNpadId());
players.begin(), std::find_if(players.begin(), players.end(),
[](const auto& player) { return player.connected; })));
result_info.result = 0; result_info.result = 0;

View file

@ -16,6 +16,10 @@ namespace Core {
class System; class System;
} }
namespace Core::HID {
enum class NpadStyleSet : u32;
}
namespace Service::AM::Applets { namespace Service::AM::Applets {
using IdentificationColor = std::array<u8, 4>; using IdentificationColor = std::array<u8, 4>;
@ -52,7 +56,7 @@ struct ControllerSupportArgPrivate {
bool flag_1{}; bool flag_1{};
ControllerSupportMode mode{}; ControllerSupportMode mode{};
ControllerSupportCaller caller{}; ControllerSupportCaller caller{};
u32 style_set{}; Core::HID::NpadStyleSet style_set{};
u32 joy_hold_type{}; u32 joy_hold_type{};
}; };
static_assert(sizeof(ControllerSupportArgPrivate) == 0x14, static_assert(sizeof(ControllerSupportArgPrivate) == 0x14,

View file

@ -231,7 +231,7 @@ void AppletManager::SetDefaultAppletFrontendSet() {
void AppletManager::SetDefaultAppletsIfMissing() { void AppletManager::SetDefaultAppletsIfMissing() {
if (frontend.controller == nullptr) { if (frontend.controller == nullptr) {
frontend.controller = frontend.controller =
std::make_unique<Core::Frontend::DefaultControllerApplet>(system.ServiceManager()); std::make_unique<Core::Frontend::DefaultControllerApplet>(system.HIDCore());
} }
if (frontend.error == nullptr) { if (frontend.error == nullptr) {

View file

@ -4,13 +4,18 @@
#include "common/settings.h" #include "common/settings.h"
#include "core/core_timing.h" #include "core/core_timing.h"
#include "core/hid/emulated_console.h"
#include "core/hid/hid_core.h"
#include "core/hle/service/hid/controllers/console_sixaxis.h" #include "core/hle/service/hid/controllers/console_sixaxis.h"
namespace Service::HID { namespace Service::HID {
constexpr std::size_t SHARED_MEMORY_OFFSET = 0x3C200; constexpr std::size_t SHARED_MEMORY_OFFSET = 0x3C200;
Controller_ConsoleSixAxis::Controller_ConsoleSixAxis(Core::System& system_) Controller_ConsoleSixAxis::Controller_ConsoleSixAxis(Core::HID::HIDCore& hid_core_)
: ControllerBase{system_} {} : ControllerBase{hid_core_} {
console = hid_core.GetEmulatedConsole();
}
Controller_ConsoleSixAxis::~Controller_ConsoleSixAxis() = default; Controller_ConsoleSixAxis::~Controller_ConsoleSixAxis() = default;
void Controller_ConsoleSixAxis::OnInit() {} void Controller_ConsoleSixAxis::OnInit() {}
@ -38,25 +43,21 @@ void Controller_ConsoleSixAxis::OnUpdate(const Core::Timing::CoreTiming& core_ti
cur_entry.sampling_number2 = cur_entry.sampling_number; cur_entry.sampling_number2 = cur_entry.sampling_number;
// Try to read sixaxis sensor states // Try to read sixaxis sensor states
MotionDevice motion_device{}; const auto motion_status = console->GetMotion();
const auto& device = motions[0];
if (device) {
std::tie(motion_device.accel, motion_device.gyro, motion_device.rotation,
motion_device.orientation, motion_device.quaternion) = device->GetStatus();
console_six_axis.is_seven_six_axis_sensor_at_rest = motion_device.gyro.Length2() < 0.0001f;
}
cur_entry.accel = motion_device.accel; console_six_axis.is_seven_six_axis_sensor_at_rest = motion_status.is_at_rest;
cur_entry.accel = motion_status.accel;
// Zero gyro values as they just mess up with the camera // Zero gyro values as they just mess up with the camera
// Note: Probably a correct sensivity setting must be set // Note: Probably a correct sensivity setting must be set
cur_entry.gyro = {}; cur_entry.gyro = {};
cur_entry.quaternion = { cur_entry.quaternion = {
{ {
motion_device.quaternion.xyz.y, motion_status.quaternion.xyz.y,
motion_device.quaternion.xyz.x, motion_status.quaternion.xyz.x,
-motion_device.quaternion.w, -motion_status.quaternion.w,
}, },
-motion_device.quaternion.xyz.z, -motion_status.quaternion.xyz.z,
}; };
console_six_axis.sampling_number++; console_six_axis.sampling_number++;
@ -70,13 +71,6 @@ void Controller_ConsoleSixAxis::OnUpdate(const Core::Timing::CoreTiming& core_ti
std::memcpy(transfer_memory, &seven_six_axis, sizeof(seven_six_axis)); std::memcpy(transfer_memory, &seven_six_axis, sizeof(seven_six_axis));
} }
void Controller_ConsoleSixAxis::OnLoadInputDevices() {
const auto player = Settings::values.players.GetValue()[0];
std::transform(player.motions.begin() + Settings::NativeMotion::MOTION_HID_BEGIN,
player.motions.begin() + Settings::NativeMotion::MOTION_HID_END, motions.begin(),
Input::CreateDevice<Input::MotionDevice>);
}
void Controller_ConsoleSixAxis::SetTransferMemoryPointer(u8* t_mem) { void Controller_ConsoleSixAxis::SetTransferMemoryPointer(u8* t_mem) {
is_transfer_memory_set = true; is_transfer_memory_set = true;
transfer_memory = t_mem; transfer_memory = t_mem;

View file

@ -5,16 +5,20 @@
#pragma once #pragma once
#include <array> #include <array>
#include "common/bit_field.h"
#include "common/common_types.h" #include "common/common_types.h"
#include "common/quaternion.h" #include "common/quaternion.h"
#include "core/frontend/input.h" #include "core/hid/hid_types.h"
#include "core/hle/service/hid/controllers/controller_base.h" #include "core/hle/service/hid/controllers/controller_base.h"
namespace Core::HID {
class EmulatedConsole;
} // namespace Core::HID
namespace Service::HID { namespace Service::HID {
class Controller_ConsoleSixAxis final : public ControllerBase { class Controller_ConsoleSixAxis final : public ControllerBase {
public: public:
explicit Controller_ConsoleSixAxis(Core::System& system_); explicit Controller_ConsoleSixAxis(Core::HID::HIDCore& hid_core_);
~Controller_ConsoleSixAxis() override; ~Controller_ConsoleSixAxis() override;
// Called when the controller is initialized // Called when the controller is initialized
@ -26,9 +30,6 @@ public:
// When the controller is requesting an update for the shared memory // When the controller is requesting an update for the shared memory
void OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, size_t size) override; void OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, size_t size) override;
// Called when input devices should be loaded
void OnLoadInputDevices() override;
// Called on InitializeSevenSixAxisSensor // Called on InitializeSevenSixAxisSensor
void SetTransferMemoryPointer(u8* t_mem); void SetTransferMemoryPointer(u8* t_mem);
@ -38,8 +39,8 @@ public:
private: private:
struct SevenSixAxisState { struct SevenSixAxisState {
INSERT_PADDING_WORDS(4); // unused INSERT_PADDING_WORDS(4); // unused
s64_le sampling_number{}; s64 sampling_number{};
s64_le sampling_number2{}; s64 sampling_number2{};
u64 unknown{}; u64 unknown{};
Common::Vec3f accel{}; Common::Vec3f accel{};
Common::Vec3f gyro{}; Common::Vec3f gyro{};
@ -47,14 +48,24 @@ private:
}; };
static_assert(sizeof(SevenSixAxisState) == 0x50, "SevenSixAxisState is an invalid size"); static_assert(sizeof(SevenSixAxisState) == 0x50, "SevenSixAxisState is an invalid size");
struct CommonHeader {
s64 timestamp;
s64 total_entry_count;
s64 last_entry_index;
s64 entry_count;
};
static_assert(sizeof(CommonHeader) == 0x20, "CommonHeader is an invalid size");
// TODO(german77): SevenSixAxisMemory doesn't follow the standard lifo. Investigate
struct SevenSixAxisMemory { struct SevenSixAxisMemory {
CommonHeader header{}; CommonHeader header{};
std::array<SevenSixAxisState, 0x21> sevensixaxis_states{}; std::array<SevenSixAxisState, 0x21> sevensixaxis_states{};
}; };
static_assert(sizeof(SevenSixAxisMemory) == 0xA70, "SevenSixAxisMemory is an invalid size"); static_assert(sizeof(SevenSixAxisMemory) == 0xA70, "SevenSixAxisMemory is an invalid size");
// This is nn::hid::detail::ConsoleSixAxisSensorSharedMemoryFormat
struct ConsoleSharedMemory { struct ConsoleSharedMemory {
u64_le sampling_number{}; u64 sampling_number{};
bool is_seven_six_axis_sensor_at_rest{}; bool is_seven_six_axis_sensor_at_rest{};
f32 verticalization_error{}; f32 verticalization_error{};
Common::Vec3f gyro_bias{}; Common::Vec3f gyro_bias{};
@ -69,9 +80,7 @@ private:
Common::Quaternion<f32> quaternion; Common::Quaternion<f32> quaternion;
}; };
using MotionArray = Core::HID::EmulatedConsole* console;
std::array<std::unique_ptr<Input::MotionDevice>, Settings::NativeMotion::NUM_MOTIONS_HID>;
MotionArray motions;
u8* transfer_memory = nullptr; u8* transfer_memory = nullptr;
bool is_transfer_memory_set = false; bool is_transfer_memory_set = false;
ConsoleSharedMemory console_six_axis{}; ConsoleSharedMemory console_six_axis{};

View file

@ -6,12 +6,12 @@
namespace Service::HID { namespace Service::HID {
ControllerBase::ControllerBase(Core::System& system_) : system(system_) {} ControllerBase::ControllerBase(Core::HID::HIDCore& hid_core_) : hid_core(hid_core_) {}
ControllerBase::~ControllerBase() = default; ControllerBase::~ControllerBase() = default;
void ControllerBase::ActivateController() { void ControllerBase::ActivateController() {
if (is_activated) { if (is_activated) {
OnRelease(); return;
} }
is_activated = true; is_activated = true;
OnInit(); OnInit();

View file

@ -11,14 +11,14 @@ namespace Core::Timing {
class CoreTiming; class CoreTiming;
} }
namespace Core { namespace Core::HID {
class System; class HIDCore;
} }
namespace Service::HID { namespace Service::HID {
class ControllerBase { class ControllerBase {
public: public:
explicit ControllerBase(Core::System& system_); explicit ControllerBase(Core::HID::HIDCore& hid_core_);
virtual ~ControllerBase(); virtual ~ControllerBase();
// Called when the controller is initialized // Called when the controller is initialized
@ -35,9 +35,6 @@ public:
virtual void OnMotionUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, virtual void OnMotionUpdate(const Core::Timing::CoreTiming& core_timing, u8* data,
std::size_t size) {} std::size_t size) {}
// Called when input devices should be loaded
virtual void OnLoadInputDevices() = 0;
void ActivateController(); void ActivateController();
void DeactivateController(); void DeactivateController();
@ -47,14 +44,6 @@ public:
protected: protected:
bool is_activated{false}; bool is_activated{false};
struct CommonHeader { Core::HID::HIDCore& hid_core;
s64_le timestamp;
s64_le total_entry_count;
s64_le last_entry_index;
s64_le entry_count;
};
static_assert(sizeof(CommonHeader) == 0x20, "CommonHeader is an invalid size");
Core::System& system;
}; };
} // namespace Service::HID } // namespace Service::HID

View file

@ -6,15 +6,19 @@
#include "common/common_types.h" #include "common/common_types.h"
#include "common/settings.h" #include "common/settings.h"
#include "core/core_timing.h" #include "core/core_timing.h"
#include "core/hid/emulated_controller.h"
#include "core/hid/hid_core.h"
#include "core/hid/hid_types.h"
#include "core/hle/service/hid/controllers/debug_pad.h" #include "core/hle/service/hid/controllers/debug_pad.h"
namespace Service::HID { namespace Service::HID {
constexpr std::size_t SHARED_MEMORY_OFFSET = 0x00000;
constexpr s32 HID_JOYSTICK_MAX = 0x7fff; Controller_DebugPad::Controller_DebugPad(Core::HID::HIDCore& hid_core_)
[[maybe_unused]] constexpr s32 HID_JOYSTICK_MIN = -0x7fff; : ControllerBase{hid_core_} {
enum class JoystickId : std::size_t { Joystick_Left, Joystick_Right }; controller = hid_core.GetEmulatedController(Core::HID::NpadIdType::Other);
}
Controller_DebugPad::Controller_DebugPad(Core::System& system_) : ControllerBase{system_} {}
Controller_DebugPad::~Controller_DebugPad() = default; Controller_DebugPad::~Controller_DebugPad() = default;
void Controller_DebugPad::OnInit() {} void Controller_DebugPad::OnInit() {}
@ -23,63 +27,29 @@ void Controller_DebugPad::OnRelease() {}
void Controller_DebugPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, void Controller_DebugPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data,
std::size_t size) { std::size_t size) {
shared_memory.header.timestamp = core_timing.GetCPUTicks();
shared_memory.header.total_entry_count = 17;
if (!IsControllerActivated()) { if (!IsControllerActivated()) {
shared_memory.header.entry_count = 0; debug_pad_lifo.buffer_count = 0;
shared_memory.header.last_entry_index = 0; debug_pad_lifo.buffer_tail = 0;
std::memcpy(data + SHARED_MEMORY_OFFSET, &debug_pad_lifo, sizeof(debug_pad_lifo));
return; return;
} }
shared_memory.header.entry_count = 16;
const auto& last_entry = shared_memory.pad_states[shared_memory.header.last_entry_index]; const auto& last_entry = debug_pad_lifo.ReadCurrentEntry().state;
shared_memory.header.last_entry_index = (shared_memory.header.last_entry_index + 1) % 17; next_state.sampling_number = last_entry.sampling_number + 1;
auto& cur_entry = shared_memory.pad_states[shared_memory.header.last_entry_index];
cur_entry.sampling_number = last_entry.sampling_number + 1;
cur_entry.sampling_number2 = cur_entry.sampling_number;
if (Settings::values.debug_pad_enabled) { if (Settings::values.debug_pad_enabled) {
cur_entry.attribute.connected.Assign(1); next_state.attribute.connected.Assign(1);
auto& pad = cur_entry.pad_state;
using namespace Settings::NativeButton; const auto& button_state = controller->GetDebugPadButtons();
pad.a.Assign(buttons[A - BUTTON_HID_BEGIN]->GetStatus()); const auto& stick_state = controller->GetSticks();
pad.b.Assign(buttons[B - BUTTON_HID_BEGIN]->GetStatus());
pad.x.Assign(buttons[X - BUTTON_HID_BEGIN]->GetStatus());
pad.y.Assign(buttons[Y - BUTTON_HID_BEGIN]->GetStatus());
pad.l.Assign(buttons[L - BUTTON_HID_BEGIN]->GetStatus());
pad.r.Assign(buttons[R - BUTTON_HID_BEGIN]->GetStatus());
pad.zl.Assign(buttons[ZL - BUTTON_HID_BEGIN]->GetStatus());
pad.zr.Assign(buttons[ZR - BUTTON_HID_BEGIN]->GetStatus());
pad.plus.Assign(buttons[Plus - BUTTON_HID_BEGIN]->GetStatus());
pad.minus.Assign(buttons[Minus - BUTTON_HID_BEGIN]->GetStatus());
pad.d_left.Assign(buttons[DLeft - BUTTON_HID_BEGIN]->GetStatus());
pad.d_up.Assign(buttons[DUp - BUTTON_HID_BEGIN]->GetStatus());
pad.d_right.Assign(buttons[DRight - BUTTON_HID_BEGIN]->GetStatus());
pad.d_down.Assign(buttons[DDown - BUTTON_HID_BEGIN]->GetStatus());
const auto [stick_l_x_f, stick_l_y_f] = next_state.pad_state = button_state;
analogs[static_cast<std::size_t>(JoystickId::Joystick_Left)]->GetStatus(); next_state.l_stick = stick_state.left;
const auto [stick_r_x_f, stick_r_y_f] = next_state.r_stick = stick_state.right;
analogs[static_cast<std::size_t>(JoystickId::Joystick_Right)]->GetStatus();
cur_entry.l_stick.x = static_cast<s32>(stick_l_x_f * HID_JOYSTICK_MAX);
cur_entry.l_stick.y = static_cast<s32>(stick_l_y_f * HID_JOYSTICK_MAX);
cur_entry.r_stick.x = static_cast<s32>(stick_r_x_f * HID_JOYSTICK_MAX);
cur_entry.r_stick.y = static_cast<s32>(stick_r_y_f * HID_JOYSTICK_MAX);
} }
std::memcpy(data, &shared_memory, sizeof(SharedMemory)); debug_pad_lifo.WriteNextEntry(next_state);
std::memcpy(data + SHARED_MEMORY_OFFSET, &debug_pad_lifo, sizeof(debug_pad_lifo));
} }
void Controller_DebugPad::OnLoadInputDevices() {
std::transform(Settings::values.debug_pad_buttons.begin(),
Settings::values.debug_pad_buttons.begin() +
Settings::NativeButton::NUM_BUTTONS_HID,
buttons.begin(), Input::CreateDevice<Input::ButtonDevice>);
std::transform(Settings::values.debug_pad_analogs.begin(),
Settings::values.debug_pad_analogs.end(), analogs.begin(),
Input::CreateDevice<Input::AnalogDevice>);
}
} // namespace Service::HID } // namespace Service::HID

View file

@ -8,15 +8,20 @@
#include "common/bit_field.h" #include "common/bit_field.h"
#include "common/common_funcs.h" #include "common/common_funcs.h"
#include "common/common_types.h" #include "common/common_types.h"
#include "common/settings.h"
#include "common/swap.h" #include "common/swap.h"
#include "core/frontend/input.h"
#include "core/hle/service/hid/controllers/controller_base.h" #include "core/hle/service/hid/controllers/controller_base.h"
#include "core/hle/service/hid/ring_lifo.h"
namespace Core::HID {
class EmulatedController;
struct DebugPadButton;
struct AnalogStickState;
} // namespace Core::HID
namespace Service::HID { namespace Service::HID {
class Controller_DebugPad final : public ControllerBase { class Controller_DebugPad final : public ControllerBase {
public: public:
explicit Controller_DebugPad(Core::System& system_); explicit Controller_DebugPad(Core::HID::HIDCore& hid_core_);
~Controller_DebugPad() override; ~Controller_DebugPad() override;
// Called when the controller is initialized // Called when the controller is initialized
@ -28,66 +33,31 @@ public:
// When the controller is requesting an update for the shared memory // When the controller is requesting an update for the shared memory
void OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, std::size_t size) override; void OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, std::size_t size) override;
// Called when input devices should be loaded
void OnLoadInputDevices() override;
private: private:
struct AnalogStick { // This is nn::hid::DebugPadAttribute
s32_le x; struct DebugPadAttribute {
s32_le y;
};
static_assert(sizeof(AnalogStick) == 0x8);
struct PadState {
union { union {
u32_le raw{}; u32 raw{};
BitField<0, 1, u32> a;
BitField<1, 1, u32> b;
BitField<2, 1, u32> x;
BitField<3, 1, u32> y;
BitField<4, 1, u32> l;
BitField<5, 1, u32> r;
BitField<6, 1, u32> zl;
BitField<7, 1, u32> zr;
BitField<8, 1, u32> plus;
BitField<9, 1, u32> minus;
BitField<10, 1, u32> d_left;
BitField<11, 1, u32> d_up;
BitField<12, 1, u32> d_right;
BitField<13, 1, u32> d_down;
};
};
static_assert(sizeof(PadState) == 0x4, "PadState is an invalid size");
struct Attributes {
union {
u32_le raw{};
BitField<0, 1, u32> connected; BitField<0, 1, u32> connected;
}; };
}; };
static_assert(sizeof(Attributes) == 0x4, "Attributes is an invalid size"); static_assert(sizeof(DebugPadAttribute) == 0x4, "DebugPadAttribute is an invalid size");
struct PadStates { // This is nn::hid::DebugPadState
s64_le sampling_number; struct DebugPadState {
s64_le sampling_number2; s64 sampling_number;
Attributes attribute; DebugPadAttribute attribute;
PadState pad_state; Core::HID::DebugPadButton pad_state;
AnalogStick r_stick; Core::HID::AnalogStickState r_stick;
AnalogStick l_stick; Core::HID::AnalogStickState l_stick;
}; };
static_assert(sizeof(PadStates) == 0x28, "PadStates is an invalid state"); static_assert(sizeof(DebugPadState) == 0x20, "DebugPadState is an invalid state");
struct SharedMemory { // This is nn::hid::detail::DebugPadLifo
CommonHeader header; Lifo<DebugPadState> debug_pad_lifo{};
std::array<PadStates, 17> pad_states; static_assert(sizeof(debug_pad_lifo) == 0x2C8, "debug_pad_lifo is an invalid size");
INSERT_PADDING_BYTES(0x138); DebugPadState next_state{};
};
static_assert(sizeof(SharedMemory) == 0x400, "SharedMemory is an invalid size");
SharedMemory shared_memory{};
std::array<std::unique_ptr<Input::ButtonDevice>, Settings::NativeButton::NUM_BUTTONS_HID> Core::HID::EmulatedController* controller;
buttons;
std::array<std::unique_ptr<Input::AnalogDevice>, Settings::NativeAnalog::NUM_STICKS_HID>
analogs;
}; };
} // namespace Service::HID } // namespace Service::HID

View file

@ -7,6 +7,7 @@
#include "common/settings.h" #include "common/settings.h"
#include "core/core_timing.h" #include "core/core_timing.h"
#include "core/frontend/emu_window.h" #include "core/frontend/emu_window.h"
#include "core/hid/hid_core.h"
#include "core/hle/service/hid/controllers/gesture.h" #include "core/hle/service/hid/controllers/gesture.h"
namespace Service::HID { namespace Service::HID {
@ -23,16 +24,14 @@ constexpr f32 Square(s32 num) {
return static_cast<f32>(num * num); return static_cast<f32>(num * num);
} }
Controller_Gesture::Controller_Gesture(Core::System& system_) : ControllerBase(system_) {} Controller_Gesture::Controller_Gesture(Core::HID::HIDCore& hid_core_) : ControllerBase(hid_core_) {
console = hid_core.GetEmulatedConsole();
}
Controller_Gesture::~Controller_Gesture() = default; Controller_Gesture::~Controller_Gesture() = default;
void Controller_Gesture::OnInit() { void Controller_Gesture::OnInit() {
for (std::size_t id = 0; id < MAX_FINGERS; ++id) { gesture_lifo.buffer_count = 0;
mouse_finger_id[id] = MAX_POINTS; gesture_lifo.buffer_tail = 0;
keyboard_finger_id[id] = MAX_POINTS;
udp_finger_id[id] = MAX_POINTS;
}
shared_memory.header.entry_count = 0;
force_update = true; force_update = true;
} }
@ -40,50 +39,38 @@ void Controller_Gesture::OnRelease() {}
void Controller_Gesture::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, void Controller_Gesture::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data,
std::size_t size) { std::size_t size) {
shared_memory.header.timestamp = core_timing.GetCPUTicks();
shared_memory.header.total_entry_count = 17;
if (!IsControllerActivated()) { if (!IsControllerActivated()) {
shared_memory.header.entry_count = 0; gesture_lifo.buffer_count = 0;
shared_memory.header.last_entry_index = 0; gesture_lifo.buffer_tail = 0;
std::memcpy(data + SHARED_MEMORY_OFFSET, &gesture_lifo, sizeof(gesture_lifo));
return; return;
} }
ReadTouchInput(); ReadTouchInput();
GestureProperties gesture = GetGestureProperties(); GestureProperties gesture = GetGestureProperties();
f32 time_difference = static_cast<f32>(shared_memory.header.timestamp - last_update_timestamp) / f32 time_difference =
(1000 * 1000 * 1000); static_cast<f32>(gesture_lifo.timestamp - last_update_timestamp) / (1000 * 1000 * 1000);
// Only update if necesary // Only update if necesary
if (!ShouldUpdateGesture(gesture, time_difference)) { if (!ShouldUpdateGesture(gesture, time_difference)) {
return; return;
} }
last_update_timestamp = shared_memory.header.timestamp; last_update_timestamp = gesture_lifo.timestamp;
UpdateGestureSharedMemory(data, size, gesture, time_difference); UpdateGestureSharedMemory(data, size, gesture, time_difference);
} }
void Controller_Gesture::ReadTouchInput() { void Controller_Gesture::ReadTouchInput() {
const Input::TouchStatus& mouse_status = touch_mouse_device->GetStatus(); const auto touch_status = console->GetTouch();
const Input::TouchStatus& udp_status = touch_udp_device->GetStatus(); for (std::size_t id = 0; id < fingers.size(); ++id) {
for (std::size_t id = 0; id < mouse_status.size(); ++id) { fingers[id] = touch_status[id];
mouse_finger_id[id] = UpdateTouchInputEvent(mouse_status[id], mouse_finger_id[id]);
udp_finger_id[id] = UpdateTouchInputEvent(udp_status[id], udp_finger_id[id]);
}
if (Settings::values.use_touch_from_button) {
const Input::TouchStatus& keyboard_status = touch_btn_device->GetStatus();
for (std::size_t id = 0; id < mouse_status.size(); ++id) {
keyboard_finger_id[id] =
UpdateTouchInputEvent(keyboard_status[id], keyboard_finger_id[id]);
}
} }
} }
bool Controller_Gesture::ShouldUpdateGesture(const GestureProperties& gesture, bool Controller_Gesture::ShouldUpdateGesture(const GestureProperties& gesture,
f32 time_difference) { f32 time_difference) {
const auto& last_entry = shared_memory.gesture_states[shared_memory.header.last_entry_index]; const auto& last_entry = GetLastGestureEntry();
if (force_update) { if (force_update) {
force_update = false; force_update = false;
return true; return true;
@ -97,7 +84,7 @@ bool Controller_Gesture::ShouldUpdateGesture(const GestureProperties& gesture,
} }
// Update on press and hold event after 0.5 seconds // Update on press and hold event after 0.5 seconds
if (last_entry.type == TouchType::Touch && last_entry.point_count == 1 && if (last_entry.type == GestureType::Touch && last_entry.point_count == 1 &&
time_difference > press_delay) { time_difference > press_delay) {
return enable_press_and_tap; return enable_press_and_tap;
} }
@ -108,27 +95,19 @@ bool Controller_Gesture::ShouldUpdateGesture(const GestureProperties& gesture,
void Controller_Gesture::UpdateGestureSharedMemory(u8* data, std::size_t size, void Controller_Gesture::UpdateGestureSharedMemory(u8* data, std::size_t size,
GestureProperties& gesture, GestureProperties& gesture,
f32 time_difference) { f32 time_difference) {
TouchType type = TouchType::Idle; GestureType type = GestureType::Idle;
Attribute attributes{}; GestureAttribute attributes{};
const auto& last_entry = shared_memory.gesture_states[shared_memory.header.last_entry_index]; const auto& last_entry = gesture_lifo.ReadCurrentEntry().state;
shared_memory.header.last_entry_index = (shared_memory.header.last_entry_index + 1) % 17;
auto& cur_entry = shared_memory.gesture_states[shared_memory.header.last_entry_index];
if (shared_memory.header.entry_count < 16) { // Reset next state to default
shared_memory.header.entry_count++; next_state.sampling_number = last_entry.sampling_number + 1;
} next_state.delta = {};
next_state.vel_x = 0;
cur_entry.sampling_number = last_entry.sampling_number + 1; next_state.vel_y = 0;
cur_entry.sampling_number2 = cur_entry.sampling_number; next_state.direction = GestureDirection::None;
next_state.rotation_angle = 0;
// Reset values to default next_state.scale = 0;
cur_entry.delta = {};
cur_entry.vel_x = 0;
cur_entry.vel_y = 0;
cur_entry.direction = Direction::None;
cur_entry.rotation_angle = 0;
cur_entry.scale = 0;
if (gesture.active_points > 0) { if (gesture.active_points > 0) {
if (last_gesture.active_points == 0) { if (last_gesture.active_points == 0) {
@ -141,46 +120,47 @@ void Controller_Gesture::UpdateGestureSharedMemory(u8* data, std::size_t size,
} }
// Apply attributes // Apply attributes
cur_entry.detection_count = gesture.detection_count; next_state.detection_count = gesture.detection_count;
cur_entry.type = type; next_state.type = type;
cur_entry.attributes = attributes; next_state.attributes = attributes;
cur_entry.pos = gesture.mid_point; next_state.pos = gesture.mid_point;
cur_entry.point_count = static_cast<s32>(gesture.active_points); next_state.point_count = static_cast<s32>(gesture.active_points);
cur_entry.points = gesture.points; next_state.points = gesture.points;
last_gesture = gesture; last_gesture = gesture;
std::memcpy(data + SHARED_MEMORY_OFFSET, &shared_memory, sizeof(SharedMemory)); gesture_lifo.WriteNextEntry(next_state);
std::memcpy(data + SHARED_MEMORY_OFFSET, &gesture_lifo, sizeof(gesture_lifo));
} }
void Controller_Gesture::NewGesture(GestureProperties& gesture, TouchType& type, void Controller_Gesture::NewGesture(GestureProperties& gesture, GestureType& type,
Attribute& attributes) { GestureAttribute& attributes) {
const auto& last_entry = GetLastGestureEntry(); const auto& last_entry = GetLastGestureEntry();
gesture.detection_count++; gesture.detection_count++;
type = TouchType::Touch; type = GestureType::Touch;
// New touch after cancel is not considered new // New touch after cancel is not considered new
if (last_entry.type != TouchType::Cancel) { if (last_entry.type != GestureType::Cancel) {
attributes.is_new_touch.Assign(1); attributes.is_new_touch.Assign(1);
enable_press_and_tap = true; enable_press_and_tap = true;
} }
} }
void Controller_Gesture::UpdateExistingGesture(GestureProperties& gesture, TouchType& type, void Controller_Gesture::UpdateExistingGesture(GestureProperties& gesture, GestureType& type,
f32 time_difference) { f32 time_difference) {
const auto& last_entry = GetLastGestureEntry(); const auto& last_entry = GetLastGestureEntry();
// Promote to pan type if touch moved // Promote to pan type if touch moved
for (size_t id = 0; id < MAX_POINTS; id++) { for (size_t id = 0; id < MAX_POINTS; id++) {
if (gesture.points[id] != last_gesture.points[id]) { if (gesture.points[id] != last_gesture.points[id]) {
type = TouchType::Pan; type = GestureType::Pan;
break; break;
} }
} }
// Number of fingers changed cancel the last event and clear data // Number of fingers changed cancel the last event and clear data
if (gesture.active_points != last_gesture.active_points) { if (gesture.active_points != last_gesture.active_points) {
type = TouchType::Cancel; type = GestureType::Cancel;
enable_press_and_tap = false; enable_press_and_tap = false;
gesture.active_points = 0; gesture.active_points = 0;
gesture.mid_point = {}; gesture.mid_point = {};
@ -189,41 +169,41 @@ void Controller_Gesture::UpdateExistingGesture(GestureProperties& gesture, Touch
} }
// Calculate extra parameters of panning // Calculate extra parameters of panning
if (type == TouchType::Pan) { if (type == GestureType::Pan) {
UpdatePanEvent(gesture, last_gesture, type, time_difference); UpdatePanEvent(gesture, last_gesture, type, time_difference);
return; return;
} }
// Promote to press type // Promote to press type
if (last_entry.type == TouchType::Touch) { if (last_entry.type == GestureType::Touch) {
type = TouchType::Press; type = GestureType::Press;
} }
} }
void Controller_Gesture::EndGesture(GestureProperties& gesture, void Controller_Gesture::EndGesture(GestureProperties& gesture,
GestureProperties& last_gesture_props, TouchType& type, GestureProperties& last_gesture_props, GestureType& type,
Attribute& attributes, f32 time_difference) { GestureAttribute& attributes, f32 time_difference) {
const auto& last_entry = GetLastGestureEntry(); const auto& last_entry = GetLastGestureEntry();
if (last_gesture_props.active_points != 0) { if (last_gesture_props.active_points != 0) {
switch (last_entry.type) { switch (last_entry.type) {
case TouchType::Touch: case GestureType::Touch:
if (enable_press_and_tap) { if (enable_press_and_tap) {
SetTapEvent(gesture, last_gesture_props, type, attributes); SetTapEvent(gesture, last_gesture_props, type, attributes);
return; return;
} }
type = TouchType::Cancel; type = GestureType::Cancel;
force_update = true; force_update = true;
break; break;
case TouchType::Press: case GestureType::Press:
case TouchType::Tap: case GestureType::Tap:
case TouchType::Swipe: case GestureType::Swipe:
case TouchType::Pinch: case GestureType::Pinch:
case TouchType::Rotate: case GestureType::Rotate:
type = TouchType::Complete; type = GestureType::Complete;
force_update = true; force_update = true;
break; break;
case TouchType::Pan: case GestureType::Pan:
EndPanEvent(gesture, last_gesture_props, type, time_difference); EndPanEvent(gesture, last_gesture_props, type, time_difference);
break; break;
default: default:
@ -231,15 +211,15 @@ void Controller_Gesture::EndGesture(GestureProperties& gesture,
} }
return; return;
} }
if (last_entry.type == TouchType::Complete || last_entry.type == TouchType::Cancel) { if (last_entry.type == GestureType::Complete || last_entry.type == GestureType::Cancel) {
gesture.detection_count++; gesture.detection_count++;
} }
} }
void Controller_Gesture::SetTapEvent(GestureProperties& gesture, void Controller_Gesture::SetTapEvent(GestureProperties& gesture,
GestureProperties& last_gesture_props, TouchType& type, GestureProperties& last_gesture_props, GestureType& type,
Attribute& attributes) { GestureAttribute& attributes) {
type = TouchType::Tap; type = GestureType::Tap;
gesture = last_gesture_props; gesture = last_gesture_props;
force_update = true; force_update = true;
f32 tap_time_difference = f32 tap_time_difference =
@ -251,44 +231,42 @@ void Controller_Gesture::SetTapEvent(GestureProperties& gesture,
} }
void Controller_Gesture::UpdatePanEvent(GestureProperties& gesture, void Controller_Gesture::UpdatePanEvent(GestureProperties& gesture,
GestureProperties& last_gesture_props, TouchType& type, GestureProperties& last_gesture_props, GestureType& type,
f32 time_difference) { f32 time_difference) {
auto& cur_entry = shared_memory.gesture_states[shared_memory.header.last_entry_index];
const auto& last_entry = GetLastGestureEntry(); const auto& last_entry = GetLastGestureEntry();
cur_entry.delta = gesture.mid_point - last_entry.pos; next_state.delta = gesture.mid_point - last_entry.pos;
cur_entry.vel_x = static_cast<f32>(cur_entry.delta.x) / time_difference; next_state.vel_x = static_cast<f32>(next_state.delta.x) / time_difference;
cur_entry.vel_y = static_cast<f32>(cur_entry.delta.y) / time_difference; next_state.vel_y = static_cast<f32>(next_state.delta.y) / time_difference;
last_pan_time_difference = time_difference; last_pan_time_difference = time_difference;
// Promote to pinch type // Promote to pinch type
if (std::abs(gesture.average_distance - last_gesture_props.average_distance) > if (std::abs(gesture.average_distance - last_gesture_props.average_distance) >
pinch_threshold) { pinch_threshold) {
type = TouchType::Pinch; type = GestureType::Pinch;
cur_entry.scale = gesture.average_distance / last_gesture_props.average_distance; next_state.scale = gesture.average_distance / last_gesture_props.average_distance;
} }
const f32 angle_between_two_lines = std::atan((gesture.angle - last_gesture_props.angle) / const f32 angle_between_two_lines = std::atan((gesture.angle - last_gesture_props.angle) /
(1 + (gesture.angle * last_gesture_props.angle))); (1 + (gesture.angle * last_gesture_props.angle)));
// Promote to rotate type // Promote to rotate type
if (std::abs(angle_between_two_lines) > angle_threshold) { if (std::abs(angle_between_two_lines) > angle_threshold) {
type = TouchType::Rotate; type = GestureType::Rotate;
cur_entry.scale = 0; next_state.scale = 0;
cur_entry.rotation_angle = angle_between_two_lines * 180.0f / Common::PI; next_state.rotation_angle = angle_between_two_lines * 180.0f / Common::PI;
} }
} }
void Controller_Gesture::EndPanEvent(GestureProperties& gesture, void Controller_Gesture::EndPanEvent(GestureProperties& gesture,
GestureProperties& last_gesture_props, TouchType& type, GestureProperties& last_gesture_props, GestureType& type,
f32 time_difference) { f32 time_difference) {
auto& cur_entry = shared_memory.gesture_states[shared_memory.header.last_entry_index];
const auto& last_entry = GetLastGestureEntry(); const auto& last_entry = GetLastGestureEntry();
cur_entry.vel_x = next_state.vel_x =
static_cast<f32>(last_entry.delta.x) / (last_pan_time_difference + time_difference); static_cast<f32>(last_entry.delta.x) / (last_pan_time_difference + time_difference);
cur_entry.vel_y = next_state.vel_y =
static_cast<f32>(last_entry.delta.y) / (last_pan_time_difference + time_difference); static_cast<f32>(last_entry.delta.y) / (last_pan_time_difference + time_difference);
const f32 curr_vel = const f32 curr_vel =
std::sqrt((cur_entry.vel_x * cur_entry.vel_x) + (cur_entry.vel_y * cur_entry.vel_y)); std::sqrt((next_state.vel_x * next_state.vel_x) + (next_state.vel_y * next_state.vel_y));
// Set swipe event with parameters // Set swipe event with parameters
if (curr_vel > swipe_threshold) { if (curr_vel > swipe_threshold) {
@ -297,105 +275,50 @@ void Controller_Gesture::EndPanEvent(GestureProperties& gesture,
} }
// End panning without swipe // End panning without swipe
type = TouchType::Complete; type = GestureType::Complete;
cur_entry.vel_x = 0; next_state.vel_x = 0;
cur_entry.vel_y = 0; next_state.vel_y = 0;
force_update = true; force_update = true;
} }
void Controller_Gesture::SetSwipeEvent(GestureProperties& gesture, void Controller_Gesture::SetSwipeEvent(GestureProperties& gesture,
GestureProperties& last_gesture_props, TouchType& type) { GestureProperties& last_gesture_props, GestureType& type) {
auto& cur_entry = shared_memory.gesture_states[shared_memory.header.last_entry_index];
const auto& last_entry = GetLastGestureEntry(); const auto& last_entry = GetLastGestureEntry();
type = TouchType::Swipe; type = GestureType::Swipe;
gesture = last_gesture_props; gesture = last_gesture_props;
force_update = true; force_update = true;
cur_entry.delta = last_entry.delta; next_state.delta = last_entry.delta;
if (std::abs(cur_entry.delta.x) > std::abs(cur_entry.delta.y)) { if (std::abs(next_state.delta.x) > std::abs(next_state.delta.y)) {
if (cur_entry.delta.x > 0) { if (next_state.delta.x > 0) {
cur_entry.direction = Direction::Right; next_state.direction = GestureDirection::Right;
return; return;
} }
cur_entry.direction = Direction::Left; next_state.direction = GestureDirection::Left;
return; return;
} }
if (cur_entry.delta.y > 0) { if (next_state.delta.y > 0) {
cur_entry.direction = Direction::Down; next_state.direction = GestureDirection::Down;
return; return;
} }
cur_entry.direction = Direction::Up; next_state.direction = GestureDirection::Up;
}
void Controller_Gesture::OnLoadInputDevices() {
touch_mouse_device = Input::CreateDevice<Input::TouchDevice>("engine:emu_window");
touch_udp_device = Input::CreateDevice<Input::TouchDevice>("engine:cemuhookudp");
touch_btn_device = Input::CreateDevice<Input::TouchDevice>("engine:touch_from_button");
}
std::optional<std::size_t> Controller_Gesture::GetUnusedFingerID() const {
// Dont assign any touch input to a point if disabled
if (!Settings::values.touchscreen.enabled) {
return std::nullopt;
}
std::size_t first_free_id = 0;
while (first_free_id < MAX_POINTS) {
if (!fingers[first_free_id].pressed) {
return first_free_id;
} else {
first_free_id++;
}
}
return std::nullopt;
}
Controller_Gesture::GestureState& Controller_Gesture::GetLastGestureEntry() {
return shared_memory.gesture_states[(shared_memory.header.last_entry_index + 16) % 17];
} }
const Controller_Gesture::GestureState& Controller_Gesture::GetLastGestureEntry() const { const Controller_Gesture::GestureState& Controller_Gesture::GetLastGestureEntry() const {
return shared_memory.gesture_states[(shared_memory.header.last_entry_index + 16) % 17]; return gesture_lifo.ReadCurrentEntry().state;
}
std::size_t Controller_Gesture::UpdateTouchInputEvent(
const std::tuple<float, float, bool>& touch_input, std::size_t finger_id) {
const auto& [x, y, pressed] = touch_input;
if (finger_id > MAX_POINTS) {
LOG_ERROR(Service_HID, "Invalid finger id {}", finger_id);
return MAX_POINTS;
}
if (pressed) {
if (finger_id == MAX_POINTS) {
const auto first_free_id = GetUnusedFingerID();
if (!first_free_id) {
// Invalid finger id do nothing
return MAX_POINTS;
}
finger_id = first_free_id.value();
fingers[finger_id].pressed = true;
}
fingers[finger_id].pos = {x, y};
return finger_id;
}
if (finger_id != MAX_POINTS) {
fingers[finger_id].pressed = false;
}
return MAX_POINTS;
} }
Controller_Gesture::GestureProperties Controller_Gesture::GetGestureProperties() { Controller_Gesture::GestureProperties Controller_Gesture::GetGestureProperties() {
GestureProperties gesture; GestureProperties gesture;
std::array<Finger, MAX_POINTS> active_fingers; std::array<Core::HID::TouchFinger, MAX_POINTS> active_fingers;
const auto end_iter = std::copy_if(fingers.begin(), fingers.end(), active_fingers.begin(), const auto end_iter = std::copy_if(fingers.begin(), fingers.end(), active_fingers.begin(),
[](const auto& finger) { return finger.pressed; }); [](const auto& finger) { return finger.pressed; });
gesture.active_points = gesture.active_points =
static_cast<std::size_t>(std::distance(active_fingers.begin(), end_iter)); static_cast<std::size_t>(std::distance(active_fingers.begin(), end_iter));
for (size_t id = 0; id < gesture.active_points; ++id) { for (size_t id = 0; id < gesture.active_points; ++id) {
const auto& [active_x, active_y] = active_fingers[id].pos; const auto& [active_x, active_y] = active_fingers[id].position;
gesture.points[id] = { gesture.points[id] = {
.x = static_cast<s32>(active_x * Layout::ScreenUndocked::Width), .x = static_cast<s32>(active_x * Layout::ScreenUndocked::Width),
.y = static_cast<s32>(active_y * Layout::ScreenUndocked::Height), .y = static_cast<s32>(active_y * Layout::ScreenUndocked::Height),

View file

@ -8,13 +8,14 @@
#include "common/bit_field.h" #include "common/bit_field.h"
#include "common/common_types.h" #include "common/common_types.h"
#include "common/point.h" #include "common/point.h"
#include "core/frontend/input.h" #include "core/hid/emulated_console.h"
#include "core/hle/service/hid/controllers/controller_base.h" #include "core/hle/service/hid/controllers/controller_base.h"
#include "core/hle/service/hid/ring_lifo.h"
namespace Service::HID { namespace Service::HID {
class Controller_Gesture final : public ControllerBase { class Controller_Gesture final : public ControllerBase {
public: public:
explicit Controller_Gesture(Core::System& system_); explicit Controller_Gesture(Core::HID::HIDCore& hid_core_);
~Controller_Gesture() override; ~Controller_Gesture() override;
// Called when the controller is initialized // Called when the controller is initialized
@ -26,14 +27,12 @@ public:
// When the controller is requesting an update for the shared memory // When the controller is requesting an update for the shared memory
void OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, size_t size) override; void OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, size_t size) override;
// Called when input devices should be loaded
void OnLoadInputDevices() override;
private: private:
static constexpr size_t MAX_FINGERS = 16; static constexpr size_t MAX_FINGERS = 16;
static constexpr size_t MAX_POINTS = 4; static constexpr size_t MAX_POINTS = 4;
enum class TouchType : u32 { // This is nn::hid::GestureType
enum class GestureType : u32 {
Idle, // Nothing touching the screen Idle, // Nothing touching the screen
Complete, // Set at the end of a touch event Complete, // Set at the end of a touch event
Cancel, // Set when the number of fingers change Cancel, // Set when the number of fingers change
@ -46,7 +45,8 @@ private:
Rotate, // All points rotating from the midpoint Rotate, // All points rotating from the midpoint
}; };
enum class Direction : u32 { // This is nn::hid::GestureDirection
enum class GestureDirection : u32 {
None, None,
Left, Left,
Up, Up,
@ -54,51 +54,41 @@ private:
Down, Down,
}; };
struct Attribute { // This is nn::hid::GestureAttribute
struct GestureAttribute {
union { union {
u32_le raw{}; u32 raw{};
BitField<4, 1, u32> is_new_touch; BitField<4, 1, u32> is_new_touch;
BitField<8, 1, u32> is_double_tap; BitField<8, 1, u32> is_double_tap;
}; };
}; };
static_assert(sizeof(Attribute) == 4, "Attribute is an invalid size"); static_assert(sizeof(GestureAttribute) == 4, "GestureAttribute is an invalid size");
// This is nn::hid::GestureState
struct GestureState { struct GestureState {
s64_le sampling_number; s64 sampling_number;
s64_le sampling_number2; s64 detection_count;
s64_le detection_count; GestureType type;
TouchType type; GestureDirection direction;
Direction direction; Common::Point<s32> pos;
Common::Point<s32_le> pos; Common::Point<s32> delta;
Common::Point<s32_le> delta;
f32 vel_x; f32 vel_x;
f32 vel_y; f32 vel_y;
Attribute attributes; GestureAttribute attributes;
f32 scale; f32 scale;
f32 rotation_angle; f32 rotation_angle;
s32_le point_count; s32 point_count;
std::array<Common::Point<s32_le>, 4> points; std::array<Common::Point<s32>, 4> points;
};
static_assert(sizeof(GestureState) == 0x68, "GestureState is an invalid size");
struct SharedMemory {
CommonHeader header;
std::array<GestureState, 17> gesture_states;
};
static_assert(sizeof(SharedMemory) == 0x708, "SharedMemory is an invalid size");
struct Finger {
Common::Point<f32> pos{};
bool pressed{};
}; };
static_assert(sizeof(GestureState) == 0x60, "GestureState is an invalid size");
struct GestureProperties { struct GestureProperties {
std::array<Common::Point<s32_le>, MAX_POINTS> points{}; std::array<Common::Point<s32>, MAX_POINTS> points{};
std::size_t active_points{}; std::size_t active_points{};
Common::Point<s32_le> mid_point{}; Common::Point<s32> mid_point{};
s64_le detection_count{}; s64 detection_count{};
u64_le delta_time{}; u64 delta_time{};
f32 average_distance{}; f32 average_distance{};
f32 angle{}; f32 angle{};
}; };
@ -114,61 +104,48 @@ private:
f32 time_difference); f32 time_difference);
// Initializes new gesture // Initializes new gesture
void NewGesture(GestureProperties& gesture, TouchType& type, Attribute& attributes); void NewGesture(GestureProperties& gesture, GestureType& type, GestureAttribute& attributes);
// Updates existing gesture state // Updates existing gesture state
void UpdateExistingGesture(GestureProperties& gesture, TouchType& type, f32 time_difference); void UpdateExistingGesture(GestureProperties& gesture, GestureType& type, f32 time_difference);
// Terminates exiting gesture // Terminates exiting gesture
void EndGesture(GestureProperties& gesture, GestureProperties& last_gesture_props, void EndGesture(GestureProperties& gesture, GestureProperties& last_gesture_props,
TouchType& type, Attribute& attributes, f32 time_difference); GestureType& type, GestureAttribute& attributes, f32 time_difference);
// Set current event to a tap event // Set current event to a tap event
void SetTapEvent(GestureProperties& gesture, GestureProperties& last_gesture_props, void SetTapEvent(GestureProperties& gesture, GestureProperties& last_gesture_props,
TouchType& type, Attribute& attributes); GestureType& type, GestureAttribute& attributes);
// Calculates and set the extra parameters related to a pan event // Calculates and set the extra parameters related to a pan event
void UpdatePanEvent(GestureProperties& gesture, GestureProperties& last_gesture_props, void UpdatePanEvent(GestureProperties& gesture, GestureProperties& last_gesture_props,
TouchType& type, f32 time_difference); GestureType& type, f32 time_difference);
// Terminates the pan event // Terminates the pan event
void EndPanEvent(GestureProperties& gesture, GestureProperties& last_gesture_props, void EndPanEvent(GestureProperties& gesture, GestureProperties& last_gesture_props,
TouchType& type, f32 time_difference); GestureType& type, f32 time_difference);
// Set current event to a swipe event // Set current event to a swipe event
void SetSwipeEvent(GestureProperties& gesture, GestureProperties& last_gesture_props, void SetSwipeEvent(GestureProperties& gesture, GestureProperties& last_gesture_props,
TouchType& type); GestureType& type);
// Returns an unused finger id, if there is no fingers available std::nullopt is returned.
[[nodiscard]] std::optional<size_t> GetUnusedFingerID() const;
// Retrieves the last gesture entry, as indicated by shared memory indices. // Retrieves the last gesture entry, as indicated by shared memory indices.
[[nodiscard]] GestureState& GetLastGestureEntry();
[[nodiscard]] const GestureState& GetLastGestureEntry() const; [[nodiscard]] const GestureState& GetLastGestureEntry() const;
/**
* If the touch is new it tries to assign a new finger id, if there is no fingers available no
* changes will be made. Updates the coordinates if the finger id it's already set. If the touch
* ends delays the output by one frame to set the end_touch flag before finally freeing the
* finger id
*/
size_t UpdateTouchInputEvent(const std::tuple<float, float, bool>& touch_input,
size_t finger_id);
// Returns the average distance, angle and middle point of the active fingers // Returns the average distance, angle and middle point of the active fingers
GestureProperties GetGestureProperties(); GestureProperties GetGestureProperties();
SharedMemory shared_memory{}; // This is nn::hid::detail::GestureLifo
std::unique_ptr<Input::TouchDevice> touch_mouse_device; Lifo<GestureState> gesture_lifo{};
std::unique_ptr<Input::TouchDevice> touch_udp_device; static_assert(sizeof(gesture_lifo) == 0x708, "gesture_lifo is an invalid size");
std::unique_ptr<Input::TouchDevice> touch_btn_device; GestureState next_state{};
std::array<size_t, MAX_FINGERS> mouse_finger_id{};
std::array<size_t, MAX_FINGERS> keyboard_finger_id{}; Core::HID::EmulatedConsole* console;
std::array<size_t, MAX_FINGERS> udp_finger_id{};
std::array<Finger, MAX_POINTS> fingers{}; std::array<Core::HID::TouchFinger, MAX_POINTS> fingers{};
GestureProperties last_gesture{}; GestureProperties last_gesture{};
s64_le last_update_timestamp{}; s64 last_update_timestamp{};
s64_le last_tap_timestamp{}; s64 last_tap_timestamp{};
f32 last_pan_time_difference{}; f32 last_pan_time_difference{};
bool force_update{false}; bool force_update{false};
bool enable_press_and_tap{false}; bool enable_press_and_tap{false};

View file

@ -6,13 +6,18 @@
#include "common/common_types.h" #include "common/common_types.h"
#include "common/settings.h" #include "common/settings.h"
#include "core/core_timing.h" #include "core/core_timing.h"
#include "core/hid/emulated_devices.h"
#include "core/hid/hid_core.h"
#include "core/hle/service/hid/controllers/keyboard.h" #include "core/hle/service/hid/controllers/keyboard.h"
namespace Service::HID { namespace Service::HID {
constexpr std::size_t SHARED_MEMORY_OFFSET = 0x3800; constexpr std::size_t SHARED_MEMORY_OFFSET = 0x3800;
constexpr u8 KEYS_PER_BYTE = 8;
Controller_Keyboard::Controller_Keyboard(Core::System& system_) : ControllerBase{system_} {} Controller_Keyboard::Controller_Keyboard(Core::HID::HIDCore& hid_core_)
: ControllerBase{hid_core_} {
emulated_devices = hid_core.GetEmulatedDevices();
}
Controller_Keyboard::~Controller_Keyboard() = default; Controller_Keyboard::~Controller_Keyboard() = default;
void Controller_Keyboard::OnInit() {} void Controller_Keyboard::OnInit() {}
@ -21,51 +26,28 @@ void Controller_Keyboard::OnRelease() {}
void Controller_Keyboard::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, void Controller_Keyboard::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data,
std::size_t size) { std::size_t size) {
shared_memory.header.timestamp = core_timing.GetCPUTicks();
shared_memory.header.total_entry_count = 17;
if (!IsControllerActivated()) { if (!IsControllerActivated()) {
shared_memory.header.entry_count = 0; keyboard_lifo.buffer_count = 0;
shared_memory.header.last_entry_index = 0; keyboard_lifo.buffer_tail = 0;
std::memcpy(data + SHARED_MEMORY_OFFSET, &keyboard_lifo, sizeof(keyboard_lifo));
return; return;
} }
shared_memory.header.entry_count = 16;
const auto& last_entry = shared_memory.pad_states[shared_memory.header.last_entry_index]; const auto& last_entry = keyboard_lifo.ReadCurrentEntry().state;
shared_memory.header.last_entry_index = (shared_memory.header.last_entry_index + 1) % 17; next_state.sampling_number = last_entry.sampling_number + 1;
auto& cur_entry = shared_memory.pad_states[shared_memory.header.last_entry_index];
cur_entry.sampling_number = last_entry.sampling_number + 1;
cur_entry.sampling_number2 = cur_entry.sampling_number;
cur_entry.key.fill(0);
if (Settings::values.keyboard_enabled) { if (Settings::values.keyboard_enabled) {
for (std::size_t i = 0; i < keyboard_keys.size(); ++i) { const auto& keyboard_state = emulated_devices->GetKeyboard();
auto& entry = cur_entry.key[i / KEYS_PER_BYTE]; const auto& keyboard_modifier_state = emulated_devices->GetKeyboardModifier();
entry = static_cast<u8>(entry | (keyboard_keys[i]->GetStatus() << (i % KEYS_PER_BYTE)));
next_state.key = keyboard_state;
next_state.modifier = keyboard_modifier_state;
// This is always enabled on HW. Check what it actually does
next_state.modifier.unknown.Assign(1);
} }
using namespace Settings::NativeKeyboard; keyboard_lifo.WriteNextEntry(next_state);
std::memcpy(data + SHARED_MEMORY_OFFSET, &keyboard_lifo, sizeof(keyboard_lifo));
// TODO: Assign the correct key to all modifiers
cur_entry.modifier.control.Assign(keyboard_mods[LeftControl]->GetStatus());
cur_entry.modifier.shift.Assign(keyboard_mods[LeftShift]->GetStatus());
cur_entry.modifier.left_alt.Assign(keyboard_mods[LeftAlt]->GetStatus());
cur_entry.modifier.right_alt.Assign(keyboard_mods[RightAlt]->GetStatus());
cur_entry.modifier.gui.Assign(0);
cur_entry.modifier.caps_lock.Assign(keyboard_mods[CapsLock]->GetStatus());
cur_entry.modifier.scroll_lock.Assign(keyboard_mods[ScrollLock]->GetStatus());
cur_entry.modifier.num_lock.Assign(keyboard_mods[NumLock]->GetStatus());
cur_entry.modifier.katakana.Assign(0);
cur_entry.modifier.hiragana.Assign(0);
}
std::memcpy(data + SHARED_MEMORY_OFFSET, &shared_memory, sizeof(SharedMemory));
} }
void Controller_Keyboard::OnLoadInputDevices() {
std::transform(Settings::values.keyboard_keys.begin(), Settings::values.keyboard_keys.end(),
keyboard_keys.begin(), Input::CreateDevice<Input::ButtonDevice>);
std::transform(Settings::values.keyboard_mods.begin(), Settings::values.keyboard_mods.end(),
keyboard_mods.begin(), Input::CreateDevice<Input::ButtonDevice>);
}
} // namespace Service::HID } // namespace Service::HID

View file

@ -8,15 +8,20 @@
#include "common/bit_field.h" #include "common/bit_field.h"
#include "common/common_funcs.h" #include "common/common_funcs.h"
#include "common/common_types.h" #include "common/common_types.h"
#include "common/settings.h"
#include "common/swap.h" #include "common/swap.h"
#include "core/frontend/input.h"
#include "core/hle/service/hid/controllers/controller_base.h" #include "core/hle/service/hid/controllers/controller_base.h"
#include "core/hle/service/hid/ring_lifo.h"
namespace Core::HID {
class EmulatedDevices;
struct KeyboardModifier;
struct KeyboardKey;
} // namespace Core::HID
namespace Service::HID { namespace Service::HID {
class Controller_Keyboard final : public ControllerBase { class Controller_Keyboard final : public ControllerBase {
public: public:
explicit Controller_Keyboard(Core::System& system_); explicit Controller_Keyboard(Core::HID::HIDCore& hid_core_);
~Controller_Keyboard() override; ~Controller_Keyboard() override;
// Called when the controller is initialized // Called when the controller is initialized
@ -28,47 +33,20 @@ public:
// When the controller is requesting an update for the shared memory // When the controller is requesting an update for the shared memory
void OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, std::size_t size) override; void OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, std::size_t size) override;
// Called when input devices should be loaded
void OnLoadInputDevices() override;
private: private:
struct Modifiers { // This is nn::hid::detail::KeyboardState
union {
u32_le raw{};
BitField<0, 1, u32> control;
BitField<1, 1, u32> shift;
BitField<2, 1, u32> left_alt;
BitField<3, 1, u32> right_alt;
BitField<4, 1, u32> gui;
BitField<8, 1, u32> caps_lock;
BitField<9, 1, u32> scroll_lock;
BitField<10, 1, u32> num_lock;
BitField<11, 1, u32> katakana;
BitField<12, 1, u32> hiragana;
};
};
static_assert(sizeof(Modifiers) == 0x4, "Modifiers is an invalid size");
struct KeyboardState { struct KeyboardState {
s64_le sampling_number; s64 sampling_number;
s64_le sampling_number2; Core::HID::KeyboardModifier modifier;
Core::HID::KeyboardKey key;
Modifiers modifier;
std::array<u8, 32> key;
}; };
static_assert(sizeof(KeyboardState) == 0x38, "KeyboardState is an invalid size"); static_assert(sizeof(KeyboardState) == 0x30, "KeyboardState is an invalid size");
struct SharedMemory { // This is nn::hid::detail::KeyboardLifo
CommonHeader header; Lifo<KeyboardState> keyboard_lifo{};
std::array<KeyboardState, 17> pad_states; static_assert(sizeof(keyboard_lifo) == 0x3D8, "keyboard_lifo is an invalid size");
INSERT_PADDING_BYTES(0x28); KeyboardState next_state{};
};
static_assert(sizeof(SharedMemory) == 0x400, "SharedMemory is an invalid size");
SharedMemory shared_memory{};
std::array<std::unique_ptr<Input::ButtonDevice>, Settings::NativeKeyboard::NumKeyboardKeys> Core::HID::EmulatedDevices* emulated_devices;
keyboard_keys;
std::array<std::unique_ptr<Input::ButtonDevice>, Settings::NativeKeyboard::NumKeyboardMods>
keyboard_mods;
}; };
} // namespace Service::HID } // namespace Service::HID

View file

@ -6,12 +6,17 @@
#include "common/common_types.h" #include "common/common_types.h"
#include "core/core_timing.h" #include "core/core_timing.h"
#include "core/frontend/emu_window.h" #include "core/frontend/emu_window.h"
#include "core/hid/emulated_devices.h"
#include "core/hid/hid_core.h"
#include "core/hle/service/hid/controllers/mouse.h" #include "core/hle/service/hid/controllers/mouse.h"
namespace Service::HID { namespace Service::HID {
constexpr std::size_t SHARED_MEMORY_OFFSET = 0x3400; constexpr std::size_t SHARED_MEMORY_OFFSET = 0x3400;
Controller_Mouse::Controller_Mouse(Core::System& system_) : ControllerBase{system_} {} Controller_Mouse::Controller_Mouse(Core::HID::HIDCore& hid_core_) : ControllerBase{hid_core_} {
emulated_devices = hid_core.GetEmulatedDevices();
}
Controller_Mouse::~Controller_Mouse() = default; Controller_Mouse::~Controller_Mouse() = default;
void Controller_Mouse::OnInit() {} void Controller_Mouse::OnInit() {}
@ -19,50 +24,34 @@ void Controller_Mouse::OnRelease() {}
void Controller_Mouse::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, void Controller_Mouse::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data,
std::size_t size) { std::size_t size) {
shared_memory.header.timestamp = core_timing.GetCPUTicks();
shared_memory.header.total_entry_count = 17;
if (!IsControllerActivated()) { if (!IsControllerActivated()) {
shared_memory.header.entry_count = 0; mouse_lifo.buffer_count = 0;
shared_memory.header.last_entry_index = 0; mouse_lifo.buffer_tail = 0;
std::memcpy(data + SHARED_MEMORY_OFFSET, &mouse_lifo, sizeof(mouse_lifo));
return; return;
} }
shared_memory.header.entry_count = 16;
auto& last_entry = shared_memory.mouse_states[shared_memory.header.last_entry_index]; const auto& last_entry = mouse_lifo.ReadCurrentEntry().state;
shared_memory.header.last_entry_index = (shared_memory.header.last_entry_index + 1) % 17; next_state.sampling_number = last_entry.sampling_number + 1;
auto& cur_entry = shared_memory.mouse_states[shared_memory.header.last_entry_index];
cur_entry.sampling_number = last_entry.sampling_number + 1; next_state.attribute.raw = 0;
cur_entry.sampling_number2 = cur_entry.sampling_number;
cur_entry.attribute.raw = 0;
if (Settings::values.mouse_enabled) { if (Settings::values.mouse_enabled) {
const auto [px, py, sx, sy] = mouse_device->GetStatus(); const auto& mouse_button_state = emulated_devices->GetMouseButtons();
const auto x = static_cast<s32>(px * Layout::ScreenUndocked::Width); const auto& mouse_position_state = emulated_devices->GetMousePosition();
const auto y = static_cast<s32>(py * Layout::ScreenUndocked::Height); const auto& mouse_wheel_state = emulated_devices->GetMouseDeltaWheel();
cur_entry.x = x; next_state.attribute.is_connected.Assign(1);
cur_entry.y = y; next_state.x = static_cast<s32>(mouse_position_state.x * Layout::ScreenUndocked::Width);
cur_entry.delta_x = x - last_entry.x; next_state.y = static_cast<s32>(mouse_position_state.y * Layout::ScreenUndocked::Height);
cur_entry.delta_y = y - last_entry.y; next_state.delta_x = next_state.x - last_entry.x;
cur_entry.mouse_wheel_x = sx; next_state.delta_y = next_state.y - last_entry.y;
cur_entry.mouse_wheel_y = sy; next_state.delta_wheel_x = mouse_wheel_state.x;
cur_entry.attribute.is_connected.Assign(1); next_state.delta_wheel_y = mouse_wheel_state.y;
using namespace Settings::NativeMouseButton; next_state.button = mouse_button_state;
cur_entry.button.left.Assign(mouse_button_devices[Left]->GetStatus());
cur_entry.button.right.Assign(mouse_button_devices[Right]->GetStatus());
cur_entry.button.middle.Assign(mouse_button_devices[Middle]->GetStatus());
cur_entry.button.forward.Assign(mouse_button_devices[Forward]->GetStatus());
cur_entry.button.back.Assign(mouse_button_devices[Back]->GetStatus());
} }
std::memcpy(data + SHARED_MEMORY_OFFSET, &shared_memory, sizeof(SharedMemory)); mouse_lifo.WriteNextEntry(next_state);
std::memcpy(data + SHARED_MEMORY_OFFSET, &mouse_lifo, sizeof(mouse_lifo));
} }
void Controller_Mouse::OnLoadInputDevices() {
mouse_device = Input::CreateDevice<Input::MouseDevice>(Settings::values.mouse_device);
std::transform(Settings::values.mouse_buttons.begin(), Settings::values.mouse_buttons.end(),
mouse_button_devices.begin(), Input::CreateDevice<Input::ButtonDevice>);
}
} // namespace Service::HID } // namespace Service::HID

View file

@ -7,15 +7,19 @@
#include <array> #include <array>
#include "common/bit_field.h" #include "common/bit_field.h"
#include "common/common_types.h" #include "common/common_types.h"
#include "common/settings.h"
#include "common/swap.h" #include "common/swap.h"
#include "core/frontend/input.h"
#include "core/hle/service/hid/controllers/controller_base.h" #include "core/hle/service/hid/controllers/controller_base.h"
#include "core/hle/service/hid/ring_lifo.h"
namespace Core::HID {
class EmulatedDevices;
struct MouseState;
} // namespace Core::HID
namespace Service::HID { namespace Service::HID {
class Controller_Mouse final : public ControllerBase { class Controller_Mouse final : public ControllerBase {
public: public:
explicit Controller_Mouse(Core::System& system_); explicit Controller_Mouse(Core::HID::HIDCore& hid_core_);
~Controller_Mouse() override; ~Controller_Mouse() override;
// Called when the controller is initialized // Called when the controller is initialized
@ -27,53 +31,12 @@ public:
// When the controller is requesting an update for the shared memory // When the controller is requesting an update for the shared memory
void OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, std::size_t size) override; void OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, std::size_t size) override;
// Called when input devices should be loaded
void OnLoadInputDevices() override;
private: private:
struct Buttons { // This is nn::hid::detail::MouseLifo
union { Lifo<Core::HID::MouseState> mouse_lifo{};
u32_le raw{}; static_assert(sizeof(mouse_lifo) == 0x350, "mouse_lifo is an invalid size");
BitField<0, 1, u32> left; Core::HID::MouseState next_state{};
BitField<1, 1, u32> right;
BitField<2, 1, u32> middle;
BitField<3, 1, u32> forward;
BitField<4, 1, u32> back;
};
};
static_assert(sizeof(Buttons) == 0x4, "Buttons is an invalid size");
struct Attributes { Core::HID::EmulatedDevices* emulated_devices;
union {
u32_le raw{};
BitField<0, 1, u32> transferable;
BitField<1, 1, u32> is_connected;
};
};
static_assert(sizeof(Attributes) == 0x4, "Attributes is an invalid size");
struct MouseState {
s64_le sampling_number;
s64_le sampling_number2;
s32_le x;
s32_le y;
s32_le delta_x;
s32_le delta_y;
s32_le mouse_wheel_x;
s32_le mouse_wheel_y;
Buttons button;
Attributes attribute;
};
static_assert(sizeof(MouseState) == 0x30, "MouseState is an invalid size");
struct SharedMemory {
CommonHeader header;
std::array<MouseState, 17> mouse_states;
};
SharedMemory shared_memory{};
std::unique_ptr<Input::MouseDevice> mouse_device;
std::array<std::unique_ptr<Input::ButtonDevice>, Settings::NativeMouseButton::NumMouseButtons>
mouse_button_devices;
}; };
} // namespace Service::HID } // namespace Service::HID

File diff suppressed because it is too large Load diff

View file

@ -11,9 +11,14 @@
#include "common/bit_field.h" #include "common/bit_field.h"
#include "common/common_types.h" #include "common/common_types.h"
#include "common/quaternion.h" #include "common/quaternion.h"
#include "common/settings.h" #include "core/hid/hid_types.h"
#include "core/frontend/input.h"
#include "core/hle/service/hid/controllers/controller_base.h" #include "core/hle/service/hid/controllers/controller_base.h"
#include "core/hle/service/hid/ring_lifo.h"
namespace Core::HID {
class EmulatedController;
enum class ControllerTriggerType;
} // namespace Core::HID
namespace Kernel { namespace Kernel {
class KEvent; class KEvent;
@ -26,12 +31,9 @@ class ServiceContext;
namespace Service::HID { namespace Service::HID {
constexpr u32 NPAD_HANDHELD = 32;
constexpr u32 NPAD_UNKNOWN = 16; // TODO(ogniK): What is this?
class Controller_NPad final : public ControllerBase { class Controller_NPad final : public ControllerBase {
public: public:
explicit Controller_NPad(Core::System& system_, explicit Controller_NPad(Core::HID::HIDCore& hid_core_,
KernelHelpers::ServiceContext& service_context_); KernelHelpers::ServiceContext& service_context_);
~Controller_NPad() override; ~Controller_NPad() override;
@ -48,60 +50,39 @@ public:
void OnMotionUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, void OnMotionUpdate(const Core::Timing::CoreTiming& core_timing, u8* data,
std::size_t size) override; std::size_t size) override;
// Called when input devices should be loaded // This is nn::hid::GyroscopeZeroDriftMode
void OnLoadInputDevices() override;
enum class NPadControllerType {
None,
ProController,
Handheld,
JoyDual,
JoyLeft,
JoyRight,
GameCube,
Pokeball,
};
enum class NpadType : u8 {
ProController = 3,
Handheld = 4,
JoyconDual = 5,
JoyconLeft = 6,
JoyconRight = 7,
GameCube = 8,
Pokeball = 9,
MaxNpadType = 10,
};
enum class DeviceIndex : u8 {
Left = 0,
Right = 1,
None = 2,
MaxDeviceIndex = 3,
};
enum class GyroscopeZeroDriftMode : u32 { enum class GyroscopeZeroDriftMode : u32 {
Loose = 0, Loose = 0,
Standard = 1, Standard = 1,
Tight = 2, Tight = 2,
}; };
enum class NpadHoldType : u64 { // This is nn::hid::NpadJoyHoldType
enum class NpadJoyHoldType : u64 {
Vertical = 0, Vertical = 0,
Horizontal = 1, Horizontal = 1,
}; };
enum class NpadAssignments : u32 { // This is nn::hid::NpadJoyAssignmentMode
enum class NpadJoyAssignmentMode : u32 {
Dual = 0, Dual = 0,
Single = 1, Single = 1,
}; };
// This is nn::hid::NpadJoyDeviceType
enum class NpadJoyDeviceType : s64 {
Left = 0,
Right = 1,
};
// This is nn::hid::NpadHandheldActivationMode
enum class NpadHandheldActivationMode : u64 { enum class NpadHandheldActivationMode : u64 {
Dual = 0, Dual = 0,
Single = 1, Single = 1,
None = 2, None = 2,
}; };
// This is nn::hid::NpadCommunicationMode
enum class NpadCommunicationMode : u64 { enum class NpadCommunicationMode : u64 {
Mode_5ms = 0, Mode_5ms = 0,
Mode_10ms = 1, Mode_10ms = 1,
@ -109,74 +90,22 @@ public:
Default = 3, Default = 3,
}; };
struct DeviceHandle { static constexpr Core::HID::VibrationValue DEFAULT_VIBRATION_VALUE{
NpadType npad_type; .low_amplitude = 0.0f,
u8 npad_id; .low_frequency = 160.0f,
DeviceIndex device_index; .high_amplitude = 0.0f,
INSERT_PADDING_BYTES_NOINIT(1); .high_frequency = 320.0f,
};
static_assert(sizeof(DeviceHandle) == 4, "DeviceHandle is an invalid size");
struct NpadStyleSet {
union {
u32_le raw{};
BitField<0, 1, u32> fullkey;
BitField<1, 1, u32> handheld;
BitField<2, 1, u32> joycon_dual;
BitField<3, 1, u32> joycon_left;
BitField<4, 1, u32> joycon_right;
BitField<5, 1, u32> gamecube;
BitField<6, 1, u32> palma;
BitField<7, 1, u32> lark;
BitField<8, 1, u32> handheld_lark;
BitField<9, 1, u32> lucia;
BitField<29, 1, u32> system_ext;
BitField<30, 1, u32> system;
};
};
static_assert(sizeof(NpadStyleSet) == 4, "NpadStyleSet is an invalid size");
struct VibrationValue {
f32 amp_low;
f32 freq_low;
f32 amp_high;
f32 freq_high;
};
static_assert(sizeof(VibrationValue) == 0x10, "Vibration is an invalid size");
static constexpr VibrationValue DEFAULT_VIBRATION_VALUE{
.amp_low = 0.0f,
.freq_low = 160.0f,
.amp_high = 0.0f,
.freq_high = 320.0f,
}; };
struct LedPattern { void SetSupportedStyleSet(Core::HID::NpadStyleTag style_set);
explicit LedPattern(u64 light1, u64 light2, u64 light3, u64 light4) { Core::HID::NpadStyleTag GetSupportedStyleSet() const;
position1.Assign(light1);
position2.Assign(light2);
position3.Assign(light3);
position4.Assign(light4);
}
union {
u64 raw{};
BitField<0, 1, u64> position1;
BitField<1, 1, u64> position2;
BitField<2, 1, u64> position3;
BitField<3, 1, u64> position4;
};
};
void SetSupportedStyleSet(NpadStyleSet style_set);
NpadStyleSet GetSupportedStyleSet() const;
void SetSupportedNpadIdTypes(u8* data, std::size_t length); void SetSupportedNpadIdTypes(u8* data, std::size_t length);
void GetSupportedNpadIdTypes(u32* data, std::size_t max_length); void GetSupportedNpadIdTypes(u32* data, std::size_t max_length);
std::size_t GetSupportedNpadIdTypesSize() const; std::size_t GetSupportedNpadIdTypesSize() const;
void SetHoldType(NpadHoldType joy_hold_type); void SetHoldType(NpadJoyHoldType joy_hold_type);
NpadHoldType GetHoldType() const; NpadJoyHoldType GetHoldType() const;
void SetNpadHandheldActivationMode(NpadHandheldActivationMode activation_mode); void SetNpadHandheldActivationMode(NpadHandheldActivationMode activation_mode);
NpadHandheldActivationMode GetNpadHandheldActivationMode() const; NpadHandheldActivationMode GetNpadHandheldActivationMode() const;
@ -184,162 +113,106 @@ public:
void SetNpadCommunicationMode(NpadCommunicationMode communication_mode_); void SetNpadCommunicationMode(NpadCommunicationMode communication_mode_);
NpadCommunicationMode GetNpadCommunicationMode() const; NpadCommunicationMode GetNpadCommunicationMode() const;
void SetNpadMode(u32 npad_id, NpadAssignments assignment_mode); void SetNpadMode(Core::HID::NpadIdType npad_id, NpadJoyAssignmentMode assignment_mode);
bool VibrateControllerAtIndex(std::size_t npad_index, std::size_t device_index, bool VibrateControllerAtIndex(Core::HID::NpadIdType npad_id, std::size_t device_index,
const VibrationValue& vibration_value); const Core::HID::VibrationValue& vibration_value);
void VibrateController(const DeviceHandle& vibration_device_handle, void VibrateController(const Core::HID::VibrationDeviceHandle& vibration_device_handle,
const VibrationValue& vibration_value); const Core::HID::VibrationValue& vibration_value);
void VibrateControllers(const std::vector<DeviceHandle>& vibration_device_handles, void VibrateControllers(
const std::vector<VibrationValue>& vibration_values); const std::vector<Core::HID::VibrationDeviceHandle>& vibration_device_handles,
const std::vector<Core::HID::VibrationValue>& vibration_values);
VibrationValue GetLastVibration(const DeviceHandle& vibration_device_handle) const; Core::HID::VibrationValue GetLastVibration(
const Core::HID::VibrationDeviceHandle& vibration_device_handle) const;
void InitializeVibrationDevice(const DeviceHandle& vibration_device_handle); void InitializeVibrationDevice(const Core::HID::VibrationDeviceHandle& vibration_device_handle);
void InitializeVibrationDeviceAtIndex(std::size_t npad_index, std::size_t device_index); void InitializeVibrationDeviceAtIndex(Core::HID::NpadIdType npad_id, std::size_t device_index);
void SetPermitVibrationSession(bool permit_vibration_session); void SetPermitVibrationSession(bool permit_vibration_session);
bool IsVibrationDeviceMounted(const DeviceHandle& vibration_device_handle) const; bool IsVibrationDeviceMounted(
const Core::HID::VibrationDeviceHandle& vibration_device_handle) const;
Kernel::KReadableEvent& GetStyleSetChangedEvent(u32 npad_id); Kernel::KReadableEvent& GetStyleSetChangedEvent(Core::HID::NpadIdType npad_id);
void SignalStyleSetChangedEvent(u32 npad_id) const; void SignalStyleSetChangedEvent(Core::HID::NpadIdType npad_id) const;
// Adds a new controller at an index. // Adds a new controller at an index.
void AddNewControllerAt(NPadControllerType controller, std::size_t npad_index); void AddNewControllerAt(Core::HID::NpadStyleIndex controller, Core::HID::NpadIdType npad_id);
// Adds a new controller at an index with connection status. // Adds a new controller at an index with connection status.
void UpdateControllerAt(NPadControllerType controller, std::size_t npad_index, bool connected); void UpdateControllerAt(Core::HID::NpadStyleIndex controller, Core::HID::NpadIdType npad_id,
bool connected);
void DisconnectNpad(u32 npad_id); void DisconnectNpad(Core::HID::NpadIdType npad_id);
void DisconnectNpadAtIndex(std::size_t index);
void SetGyroscopeZeroDriftMode(GyroscopeZeroDriftMode drift_mode); void SetGyroscopeZeroDriftMode(Core::HID::SixAxisSensorHandle sixaxis_handle,
GyroscopeZeroDriftMode GetGyroscopeZeroDriftMode() const; GyroscopeZeroDriftMode drift_mode);
bool IsSixAxisSensorAtRest() const; GyroscopeZeroDriftMode GetGyroscopeZeroDriftMode(
void SetSixAxisEnabled(bool six_axis_status); Core::HID::SixAxisSensorHandle sixaxis_handle) const;
void SetSixAxisFusionParameters(f32 parameter1, f32 parameter2); bool IsSixAxisSensorAtRest(Core::HID::SixAxisSensorHandle sixaxis_handle) const;
std::pair<f32, f32> GetSixAxisFusionParameters(); void SetSixAxisEnabled(Core::HID::SixAxisSensorHandle sixaxis_handle, bool sixaxis_status);
void ResetSixAxisFusionParameters(); void SetSixAxisFusionEnabled(Core::HID::SixAxisSensorHandle sixaxis_handle,
LedPattern GetLedPattern(u32 npad_id); bool sixaxis_fusion_status);
bool IsUnintendedHomeButtonInputProtectionEnabled(u32 npad_id) const; void SetSixAxisFusionParameters(
void SetUnintendedHomeButtonInputProtectionEnabled(bool is_protection_enabled, u32 npad_id); Core::HID::SixAxisSensorHandle sixaxis_handle,
Core::HID::SixAxisSensorFusionParameters sixaxis_fusion_parameters);
Core::HID::SixAxisSensorFusionParameters GetSixAxisFusionParameters(
Core::HID::SixAxisSensorHandle sixaxis_handle);
void ResetSixAxisFusionParameters(Core::HID::SixAxisSensorHandle sixaxis_handle);
Core::HID::LedPattern GetLedPattern(Core::HID::NpadIdType npad_id);
bool IsUnintendedHomeButtonInputProtectionEnabled(Core::HID::NpadIdType npad_id) const;
void SetUnintendedHomeButtonInputProtectionEnabled(bool is_protection_enabled,
Core::HID::NpadIdType npad_id);
void SetAnalogStickUseCenterClamp(bool use_center_clamp); void SetAnalogStickUseCenterClamp(bool use_center_clamp);
void ClearAllConnectedControllers(); void ClearAllConnectedControllers();
void DisconnectAllConnectedControllers(); void DisconnectAllConnectedControllers();
void ConnectAllDisconnectedControllers(); void ConnectAllDisconnectedControllers();
void ClearAllControllers(); void ClearAllControllers();
void MergeSingleJoyAsDualJoy(u32 npad_id_1, u32 npad_id_2); void MergeSingleJoyAsDualJoy(Core::HID::NpadIdType npad_id_1, Core::HID::NpadIdType npad_id_2);
void StartLRAssignmentMode(); void StartLRAssignmentMode();
void StopLRAssignmentMode(); void StopLRAssignmentMode();
bool SwapNpadAssignment(u32 npad_id_1, u32 npad_id_2); bool SwapNpadAssignment(Core::HID::NpadIdType npad_id_1, Core::HID::NpadIdType npad_id_2);
// Logical OR for all buttons presses on all controllers // Logical OR for all buttons presses on all controllers
// Specifically for cheat engine and other features. // Specifically for cheat engine and other features.
u32 GetAndResetPressState(); u32 GetAndResetPressState();
static Controller_NPad::NPadControllerType MapSettingsTypeToNPad(Settings::ControllerType type); static bool IsNpadIdValid(Core::HID::NpadIdType npad_id);
static Settings::ControllerType MapNPadToSettingsType(Controller_NPad::NPadControllerType type); static bool IsDeviceHandleValid(const Core::HID::SixAxisSensorHandle& device_handle);
static std::size_t NPadIdToIndex(u32 npad_id); static bool IsDeviceHandleValid(const Core::HID::VibrationDeviceHandle& device_handle);
static u32 IndexToNPad(std::size_t index);
static bool IsNpadIdValid(u32 npad_id);
static bool IsDeviceHandleValid(const DeviceHandle& device_handle);
private: private:
struct CommonHeader { // This is nn::hid::detail::ColorAttribute
s64_le timestamp; enum class ColorAttribute : u32 {
s64_le total_entry_count;
s64_le last_entry_index;
s64_le entry_count;
};
static_assert(sizeof(CommonHeader) == 0x20, "CommonHeader is an invalid size");
enum class ColorAttributes : u32_le {
Ok = 0, Ok = 0,
ReadError = 1, ReadError = 1,
NoController = 2, NoController = 2,
}; };
static_assert(sizeof(ColorAttributes) == 4, "ColorAttributes is an invalid size"); static_assert(sizeof(ColorAttribute) == 4, "ColorAttribute is an invalid size");
struct ControllerColor { // This is nn::hid::detail::NpadFullKeyColorState
u32_le body; struct NpadFullKeyColorState {
u32_le button; ColorAttribute attribute;
Core::HID::NpadControllerColor fullkey;
}; };
static_assert(sizeof(ControllerColor) == 8, "ControllerColor is an invalid size"); static_assert(sizeof(NpadFullKeyColorState) == 0xC, "NpadFullKeyColorState is an invalid size");
struct FullKeyColor { // This is nn::hid::detail::NpadJoyColorState
ColorAttributes attribute; struct NpadJoyColorState {
ControllerColor fullkey; ColorAttribute attribute;
Core::HID::NpadControllerColor left;
Core::HID::NpadControllerColor right;
}; };
static_assert(sizeof(FullKeyColor) == 0xC, "FullKeyColor is an invalid size"); static_assert(sizeof(NpadJoyColorState) == 0x14, "NpadJoyColorState is an invalid size");
struct JoyconColor { // This is nn::hid::NpadAttribute
ColorAttributes attribute; struct NpadAttribute {
ControllerColor left;
ControllerColor right;
};
static_assert(sizeof(JoyconColor) == 0x14, "JoyconColor is an invalid size");
struct ControllerPadState {
union { union {
u64_le raw{}; u32 raw{};
// Button states
BitField<0, 1, u64> a;
BitField<1, 1, u64> b;
BitField<2, 1, u64> x;
BitField<3, 1, u64> y;
BitField<4, 1, u64> l_stick;
BitField<5, 1, u64> r_stick;
BitField<6, 1, u64> l;
BitField<7, 1, u64> r;
BitField<8, 1, u64> zl;
BitField<9, 1, u64> zr;
BitField<10, 1, u64> plus;
BitField<11, 1, u64> minus;
// D-Pad
BitField<12, 1, u64> d_left;
BitField<13, 1, u64> d_up;
BitField<14, 1, u64> d_right;
BitField<15, 1, u64> d_down;
// Left JoyStick
BitField<16, 1, u64> l_stick_left;
BitField<17, 1, u64> l_stick_up;
BitField<18, 1, u64> l_stick_right;
BitField<19, 1, u64> l_stick_down;
// Right JoyStick
BitField<20, 1, u64> r_stick_left;
BitField<21, 1, u64> r_stick_up;
BitField<22, 1, u64> r_stick_right;
BitField<23, 1, u64> r_stick_down;
// Not always active?
BitField<24, 1, u64> left_sl;
BitField<25, 1, u64> left_sr;
BitField<26, 1, u64> right_sl;
BitField<27, 1, u64> right_sr;
BitField<28, 1, u64> palma;
BitField<30, 1, u64> handheld_left_b;
};
};
static_assert(sizeof(ControllerPadState) == 8, "ControllerPadState is an invalid size");
struct AnalogPosition {
s32_le x;
s32_le y;
};
static_assert(sizeof(AnalogPosition) == 8, "AnalogPosition is an invalid size");
struct ConnectionState {
union {
u32_le raw{};
BitField<0, 1, u32> is_connected; BitField<0, 1, u32> is_connected;
BitField<1, 1, u32> is_wired; BitField<1, 1, u32> is_wired;
BitField<2, 1, u32> is_left_connected; BitField<2, 1, u32> is_left_connected;
@ -348,79 +221,60 @@ private:
BitField<5, 1, u32> is_right_wired; BitField<5, 1, u32> is_right_wired;
}; };
}; };
static_assert(sizeof(ConnectionState) == 4, "ConnectionState is an invalid size"); static_assert(sizeof(NpadAttribute) == 4, "NpadAttribute is an invalid size");
struct ControllerPad { // This is nn::hid::NpadFullKeyState
ControllerPadState pad_states; // This is nn::hid::NpadHandheldState
AnalogPosition l_stick; // This is nn::hid::NpadJoyDualState
AnalogPosition r_stick; // This is nn::hid::NpadJoyLeftState
// This is nn::hid::NpadJoyRightState
// This is nn::hid::NpadPalmaState
// This is nn::hid::NpadSystemExtState
struct NPadGenericState {
s64_le sampling_number;
Core::HID::NpadButtonState npad_buttons;
Core::HID::AnalogStickState l_stick;
Core::HID::AnalogStickState r_stick;
NpadAttribute connection_status;
INSERT_PADDING_BYTES(4); // Reserved
}; };
static_assert(sizeof(ControllerPad) == 0x18, "ControllerPad is an invalid size"); static_assert(sizeof(NPadGenericState) == 0x28, "NPadGenericState is an invalid size");
struct GenericStates { // This is nn::hid::SixAxisSensorAttribute
s64_le timestamp; struct SixAxisSensorAttribute {
s64_le timestamp2;
ControllerPad pad;
ConnectionState connection_status;
};
static_assert(sizeof(GenericStates) == 0x30, "NPadGenericStates is an invalid size");
struct NPadGeneric {
CommonHeader common;
std::array<GenericStates, 17> npad;
};
static_assert(sizeof(NPadGeneric) == 0x350, "NPadGeneric is an invalid size");
struct SixAxisAttributes {
union { union {
u32_le raw{}; u32 raw{};
BitField<0, 1, u32> is_connected; BitField<0, 1, u32> is_connected;
BitField<1, 1, u32> is_interpolated; BitField<1, 1, u32> is_interpolated;
}; };
}; };
static_assert(sizeof(SixAxisAttributes) == 4, "SixAxisAttributes is an invalid size"); static_assert(sizeof(SixAxisSensorAttribute) == 4, "SixAxisSensorAttribute is an invalid size");
struct SixAxisStates { // This is nn::hid::SixAxisSensorState
s64_le timestamp{}; struct SixAxisSensorState {
INSERT_PADDING_WORDS(2); s64 delta_time{};
s64_le timestamp2{}; s64 sampling_number{};
Common::Vec3f accel{}; Common::Vec3f accel{};
Common::Vec3f gyro{}; Common::Vec3f gyro{};
Common::Vec3f rotation{}; Common::Vec3f rotation{};
std::array<Common::Vec3f, 3> orientation{}; std::array<Common::Vec3f, 3> orientation{};
SixAxisAttributes attribute; SixAxisSensorAttribute attribute;
INSERT_PADDING_BYTES(4); // Reserved INSERT_PADDING_BYTES(4); // Reserved
}; };
static_assert(sizeof(SixAxisStates) == 0x68, "SixAxisStates is an invalid size"); static_assert(sizeof(SixAxisSensorState) == 0x60, "SixAxisSensorState is an invalid size");
struct SixAxisGeneric { // This is nn::hid::server::NpadGcTriggerState
CommonHeader common{}; struct NpadGcTriggerState {
std::array<SixAxisStates, 17> sixaxis{}; s64 sampling_number{};
s32 l_analog{};
s32 r_analog{};
}; };
static_assert(sizeof(SixAxisGeneric) == 0x708, "SixAxisGeneric is an invalid size"); static_assert(sizeof(NpadGcTriggerState) == 0x10, "NpadGcTriggerState is an invalid size");
struct TriggerState {
s64_le timestamp{};
s64_le timestamp2{};
s32_le l_analog{};
s32_le r_analog{};
};
static_assert(sizeof(TriggerState) == 0x18, "TriggerState is an invalid size");
struct TriggerGeneric {
INSERT_PADDING_BYTES(0x4);
s64_le timestamp;
INSERT_PADDING_BYTES(0x4);
s64_le total_entry_count;
s64_le last_entry_index;
s64_le entry_count;
std::array<TriggerState, 17> trigger{};
};
static_assert(sizeof(TriggerGeneric) == 0x1C8, "TriggerGeneric is an invalid size");
// This is nn::hid::NpadSystemProperties
struct NPadSystemProperties { struct NPadSystemProperties {
union { union {
s64_le raw{}; s64 raw{};
BitField<0, 1, s64> is_charging_joy_dual; BitField<0, 1, s64> is_charging_joy_dual;
BitField<1, 1, s64> is_charging_joy_left; BitField<1, 1, s64> is_charging_joy_left;
BitField<2, 1, s64> is_charging_joy_right; BitField<2, 1, s64> is_charging_joy_right;
@ -438,17 +292,20 @@ private:
}; };
static_assert(sizeof(NPadSystemProperties) == 0x8, "NPadSystemProperties is an invalid size"); static_assert(sizeof(NPadSystemProperties) == 0x8, "NPadSystemProperties is an invalid size");
struct NPadButtonProperties { // This is nn::hid::NpadSystemButtonProperties
struct NpadSystemButtonProperties {
union { union {
s32_le raw{}; s32 raw{};
BitField<0, 1, s32> is_home_button_protection_enabled; BitField<0, 1, s32> is_home_button_protection_enabled;
}; };
}; };
static_assert(sizeof(NPadButtonProperties) == 0x4, "NPadButtonProperties is an invalid size"); static_assert(sizeof(NpadSystemButtonProperties) == 0x4,
"NPadButtonProperties is an invalid size");
struct NPadDevice { // This is nn::hid::system::DeviceType
struct DeviceType {
union { union {
u32_le raw{}; u32 raw{};
BitField<0, 1, s32> fullkey; BitField<0, 1, s32> fullkey;
BitField<1, 1, s32> debug_pad; BitField<1, 1, s32> debug_pad;
BitField<2, 1, s32> handheld_left; BitField<2, 1, s32> handheld_left;
@ -465,26 +322,49 @@ private:
BitField<13, 1, s32> handheld_lark_nes_left; BitField<13, 1, s32> handheld_lark_nes_left;
BitField<14, 1, s32> handheld_lark_nes_right; BitField<14, 1, s32> handheld_lark_nes_right;
BitField<15, 1, s32> lucia; BitField<15, 1, s32> lucia;
BitField<16, 1, s32> lagon;
BitField<17, 1, s32> lager;
BitField<31, 1, s32> system; BitField<31, 1, s32> system;
}; };
}; };
struct MotionDevice { // This is nn::hid::detail::NfcXcdDeviceHandleStateImpl
Common::Vec3f accel; struct NfcXcdDeviceHandleStateImpl {
Common::Vec3f gyro; u64 handle;
Common::Vec3f rotation; bool is_available;
std::array<Common::Vec3f, 3> orientation; bool is_activated;
Common::Quaternion<f32> quaternion; INSERT_PADDING_BYTES(0x6); // Reserved
u64 sampling_number;
}; };
static_assert(sizeof(NfcXcdDeviceHandleStateImpl) == 0x18,
"NfcXcdDeviceHandleStateImpl is an invalid size");
struct NfcXcdHandle { // nn::hid::detail::NfcXcdDeviceHandleStateImplAtomicStorage
INSERT_PADDING_BYTES(0x60); struct NfcXcdDeviceHandleStateImplAtomicStorage {
u64 sampling_number;
NfcXcdDeviceHandleStateImpl nfc_xcd_device_handle_state;
}; };
static_assert(sizeof(NfcXcdDeviceHandleStateImplAtomicStorage) == 0x20,
"NfcXcdDeviceHandleStateImplAtomicStorage is an invalid size");
// This is nn::hid::detail::NfcXcdDeviceHandleState
struct NfcXcdDeviceHandleState {
// TODO(german77): Make this struct a ring lifo object
INSERT_PADDING_BYTES(0x8); // Unused
s64 total_buffer_count = max_buffer_size;
s64 buffer_tail{};
s64 buffer_count{};
std::array<NfcXcdDeviceHandleStateImplAtomicStorage, 2> nfc_xcd_device_handle_storage;
};
static_assert(sizeof(NfcXcdDeviceHandleState) == 0x60,
"NfcXcdDeviceHandleState is an invalid size");
// This is nn::hid::system::AppletFooterUiAttributesSet
struct AppletFooterUiAttributes { struct AppletFooterUiAttributes {
INSERT_PADDING_BYTES(0x4); INSERT_PADDING_BYTES(0x4);
}; };
// This is nn::hid::system::AppletFooterUiType
enum class AppletFooterUiType : u8 { enum class AppletFooterUiType : u8 {
None = 0, None = 0,
HandheldNone = 1, HandheldNone = 1,
@ -510,95 +390,150 @@ private:
Lagon = 21, Lagon = 21,
}; };
struct NPadEntry { struct AppletFooterUi {
NpadStyleSet style_set; AppletFooterUiAttributes attributes;
NpadAssignments assignment_mode; AppletFooterUiType type;
FullKeyColor fullkey_color; INSERT_PADDING_BYTES(0x5B); // Reserved
JoyconColor joycon_color; };
static_assert(sizeof(AppletFooterUi) == 0x60, "AppletFooterUi is an invalid size");
NPadGeneric fullkey_states; // This is nn::hid::NpadLarkType
NPadGeneric handheld_states; enum class NpadLarkType : u32 {
NPadGeneric joy_dual_states; Invalid,
NPadGeneric joy_left_states; H1,
NPadGeneric joy_right_states; H2,
NPadGeneric palma_states; NL,
NPadGeneric system_ext_states; NR,
SixAxisGeneric sixaxis_fullkey; };
SixAxisGeneric sixaxis_handheld;
SixAxisGeneric sixaxis_dual_left; // This is nn::hid::NpadLuciaType
SixAxisGeneric sixaxis_dual_right; enum class NpadLuciaType : u32 {
SixAxisGeneric sixaxis_left; Invalid,
SixAxisGeneric sixaxis_right; J,
NPadDevice device_type; E,
INSERT_PADDING_BYTES(0x4); // reserved U,
};
// This is nn::hid::NpadLagonType
enum class NpadLagonType : u32 {
Invalid,
};
// This is nn::hid::NpadLagerType
enum class NpadLagerType : u32 {
Invalid,
J,
E,
U,
};
// This is nn::hid::detail::NpadInternalState
struct NpadInternalState {
Core::HID::NpadStyleTag style_tag;
NpadJoyAssignmentMode assignment_mode;
NpadFullKeyColorState fullkey_color;
NpadJoyColorState joycon_color;
Lifo<NPadGenericState> fullkey_lifo;
Lifo<NPadGenericState> handheld_lifo;
Lifo<NPadGenericState> joy_dual_lifo;
Lifo<NPadGenericState> joy_left_lifo;
Lifo<NPadGenericState> joy_right_lifo;
Lifo<NPadGenericState> palma_lifo;
Lifo<NPadGenericState> system_ext_lifo;
Lifo<SixAxisSensorState> sixaxis_fullkey_lifo;
Lifo<SixAxisSensorState> sixaxis_handheld_lifo;
Lifo<SixAxisSensorState> sixaxis_dual_left_lifo;
Lifo<SixAxisSensorState> sixaxis_dual_right_lifo;
Lifo<SixAxisSensorState> sixaxis_left_lifo;
Lifo<SixAxisSensorState> sixaxis_right_lifo;
DeviceType device_type;
INSERT_PADDING_BYTES(0x4); // Reserved
NPadSystemProperties system_properties; NPadSystemProperties system_properties;
NPadButtonProperties button_properties; NpadSystemButtonProperties button_properties;
u32 battery_level_dual; Core::HID::BatteryLevel battery_level_dual;
u32 battery_level_left; Core::HID::BatteryLevel battery_level_left;
u32 battery_level_right; Core::HID::BatteryLevel battery_level_right;
AppletFooterUiAttributes footer_attributes; union {
AppletFooterUiType footer_type; NfcXcdDeviceHandleState nfc_xcd_device_handle;
// nfc_states needs to be checked switchbrew does not match with HW AppletFooterUi applet_footer;
NfcXcdHandle nfc_states;
INSERT_PADDING_BYTES(0x8); // Mutex
TriggerGeneric gc_trigger_states;
INSERT_PADDING_BYTES(0xc1f);
}; };
static_assert(sizeof(NPadEntry) == 0x5000, "NPadEntry is an invalid size"); INSERT_PADDING_BYTES(0x20); // Unknown
Lifo<NpadGcTriggerState> gc_trigger_lifo;
NpadLarkType lark_type_l_and_main;
NpadLarkType lark_type_r;
NpadLuciaType lucia_type;
NpadLagonType lagon_type;
NpadLagerType lager_type;
// FW 13.x Investigate there is some sort of bitflag related to joycons
INSERT_PADDING_BYTES(0x4);
INSERT_PADDING_BYTES(0xc08); // Unknown
};
static_assert(sizeof(NpadInternalState) == 0x5000, "NpadInternalState is an invalid size");
struct ControllerHolder { struct VibrationData {
NPadControllerType type; bool device_mounted{};
bool is_connected; Core::HID::VibrationValue latest_vibration_value{};
std::chrono::steady_clock::time_point last_vibration_timepoint{};
}; };
void InitNewlyAddedController(std::size_t controller_idx); struct NpadControllerData {
bool IsControllerSupported(NPadControllerType controller) const; Core::HID::EmulatedController* device;
void RequestPadStateUpdate(u32 npad_id); Kernel::KEvent* styleset_changed_event{};
NpadInternalState shared_memory_entry{};
std::array<VibrationData, 2> vibration{};
bool unintended_home_button_input_protection{};
bool is_connected{};
Core::HID::NpadStyleIndex npad_type{Core::HID::NpadStyleIndex::None};
// Motion parameters
bool sixaxis_at_rest{true};
bool sixaxis_sensor_enabled{true};
bool sixaxis_fusion_enabled{false};
Core::HID::SixAxisSensorFusionParameters sixaxis_fusion{};
GyroscopeZeroDriftMode gyroscope_zero_drift_mode{GyroscopeZeroDriftMode::Standard};
// Current pad state
NPadGenericState npad_pad_state{};
NPadGenericState npad_libnx_state{};
NpadGcTriggerState npad_trigger_state{};
SixAxisSensorState sixaxis_fullkey_state{};
SixAxisSensorState sixaxis_handheld_state{};
SixAxisSensorState sixaxis_dual_left_state{};
SixAxisSensorState sixaxis_dual_right_state{};
SixAxisSensorState sixaxis_left_lifo_state{};
SixAxisSensorState sixaxis_right_lifo_state{};
int callback_key;
};
void ControllerUpdate(Core::HID::ControllerTriggerType type, std::size_t controller_idx);
void InitNewlyAddedController(Core::HID::NpadIdType npad_id);
bool IsControllerSupported(Core::HID::NpadStyleIndex controller) const;
void RequestPadStateUpdate(Core::HID::NpadIdType npad_id);
void WriteEmptyEntry(NpadInternalState& npad);
NpadControllerData& GetControllerFromHandle(
const Core::HID::SixAxisSensorHandle& device_handle);
const NpadControllerData& GetControllerFromHandle(
const Core::HID::SixAxisSensorHandle& device_handle) const;
NpadControllerData& GetControllerFromHandle(
const Core::HID::VibrationDeviceHandle& device_handle);
const NpadControllerData& GetControllerFromHandle(
const Core::HID::VibrationDeviceHandle& device_handle) const;
NpadControllerData& GetControllerFromNpadIdType(Core::HID::NpadIdType npad_id);
const NpadControllerData& GetControllerFromNpadIdType(Core::HID::NpadIdType npad_id) const;
std::atomic<u32> press_state{}; std::atomic<u32> press_state{};
NpadStyleSet style{}; std::array<NpadControllerData, 10> controller_data{};
std::array<NPadEntry, 10> shared_memory_entries{};
using ButtonArray = std::array<
std::array<std::unique_ptr<Input::ButtonDevice>, Settings::NativeButton::NUM_BUTTONS_HID>,
10>;
using StickArray = std::array<
std::array<std::unique_ptr<Input::AnalogDevice>, Settings::NativeAnalog::NUM_STICKS_HID>,
10>;
using VibrationArray = std::array<std::array<std::unique_ptr<Input::VibrationDevice>,
Settings::NativeVibration::NUM_VIBRATIONS_HID>,
10>;
using MotionArray = std::array<
std::array<std::unique_ptr<Input::MotionDevice>, Settings::NativeMotion::NUM_MOTIONS_HID>,
10>;
KernelHelpers::ServiceContext& service_context; KernelHelpers::ServiceContext& service_context;
std::mutex mutex; std::mutex mutex;
ButtonArray buttons; std::vector<Core::HID::NpadIdType> supported_npad_id_types{};
StickArray sticks; NpadJoyHoldType hold_type{NpadJoyHoldType::Vertical};
VibrationArray vibrations;
MotionArray motions;
std::vector<u32> supported_npad_id_types{};
NpadHoldType hold_type{NpadHoldType::Vertical};
NpadHandheldActivationMode handheld_activation_mode{NpadHandheldActivationMode::Dual}; NpadHandheldActivationMode handheld_activation_mode{NpadHandheldActivationMode::Dual};
NpadCommunicationMode communication_mode{NpadCommunicationMode::Default}; NpadCommunicationMode communication_mode{NpadCommunicationMode::Default};
// Each controller should have their own styleset changed event
std::array<Kernel::KEvent*, 10> styleset_changed_events{};
std::array<std::array<std::chrono::steady_clock::time_point, 2>, 10>
last_vibration_timepoints{};
std::array<std::array<VibrationValue, 2>, 10> latest_vibration_values{};
bool permit_vibration_session_enabled{false}; bool permit_vibration_session_enabled{false};
std::array<std::array<bool, 2>, 10> vibration_devices_mounted{};
std::array<ControllerHolder, 10> connected_controllers{};
std::array<bool, 10> unintended_home_button_input_protection{};
bool analog_stick_use_center_clamp{}; bool analog_stick_use_center_clamp{};
GyroscopeZeroDriftMode gyroscope_zero_drift_mode{GyroscopeZeroDriftMode::Standard};
bool sixaxis_sensors_enabled{true};
f32 sixaxis_fusion_parameter1{};
f32 sixaxis_fusion_parameter2{};
bool sixaxis_at_rest{true};
std::array<ControllerPad, 10> npad_pad_states{};
std::array<TriggerState, 10> npad_trigger_states{};
bool is_in_lr_assignment_mode{false}; bool is_in_lr_assignment_mode{false};
}; };
} // namespace Service::HID } // namespace Service::HID

View file

@ -5,11 +5,12 @@
#include <cstring> #include <cstring>
#include "common/common_types.h" #include "common/common_types.h"
#include "core/core_timing.h" #include "core/core_timing.h"
#include "core/hid/hid_core.h"
#include "core/hle/service/hid/controllers/stubbed.h" #include "core/hle/service/hid/controllers/stubbed.h"
namespace Service::HID { namespace Service::HID {
Controller_Stubbed::Controller_Stubbed(Core::System& system_) : ControllerBase{system_} {} Controller_Stubbed::Controller_Stubbed(Core::HID::HIDCore& hid_core_) : ControllerBase{hid_core_} {}
Controller_Stubbed::~Controller_Stubbed() = default; Controller_Stubbed::~Controller_Stubbed() = default;
void Controller_Stubbed::OnInit() {} void Controller_Stubbed::OnInit() {}
@ -31,10 +32,9 @@ void Controller_Stubbed::OnUpdate(const Core::Timing::CoreTiming& core_timing, u
std::memcpy(data + common_offset, &header, sizeof(CommonHeader)); std::memcpy(data + common_offset, &header, sizeof(CommonHeader));
} }
void Controller_Stubbed::OnLoadInputDevices() {}
void Controller_Stubbed::SetCommonHeaderOffset(std::size_t off) { void Controller_Stubbed::SetCommonHeaderOffset(std::size_t off) {
common_offset = off; common_offset = off;
smart_update = true; smart_update = true;
} }
} // namespace Service::HID } // namespace Service::HID

View file

@ -10,7 +10,7 @@
namespace Service::HID { namespace Service::HID {
class Controller_Stubbed final : public ControllerBase { class Controller_Stubbed final : public ControllerBase {
public: public:
explicit Controller_Stubbed(Core::System& system_); explicit Controller_Stubbed(Core::HID::HIDCore& hid_core_);
~Controller_Stubbed() override; ~Controller_Stubbed() override;
// Called when the controller is initialized // Called when the controller is initialized
@ -22,12 +22,17 @@ public:
// When the controller is requesting an update for the shared memory // When the controller is requesting an update for the shared memory
void OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, std::size_t size) override; void OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, std::size_t size) override;
// Called when input devices should be loaded
void OnLoadInputDevices() override;
void SetCommonHeaderOffset(std::size_t off); void SetCommonHeaderOffset(std::size_t off);
private: private:
struct CommonHeader {
s64 timestamp;
s64 total_entry_count;
s64 last_entry_index;
s64 entry_count;
};
static_assert(sizeof(CommonHeader) == 0x20, "CommonHeader is an invalid size");
bool smart_update{}; bool smart_update{};
std::size_t common_offset{}; std::size_t common_offset{};
}; };

View file

@ -7,72 +7,82 @@
#include "common/common_types.h" #include "common/common_types.h"
#include "common/logging/log.h" #include "common/logging/log.h"
#include "common/settings.h" #include "common/settings.h"
#include "core/core.h"
#include "core/core_timing.h" #include "core/core_timing.h"
#include "core/frontend/emu_window.h" #include "core/frontend/emu_window.h"
#include "core/frontend/input.h" #include "core/hid/emulated_console.h"
#include "core/hid/hid_core.h"
#include "core/hle/service/hid/controllers/touchscreen.h" #include "core/hle/service/hid/controllers/touchscreen.h"
namespace Service::HID { namespace Service::HID {
constexpr std::size_t SHARED_MEMORY_OFFSET = 0x400; constexpr std::size_t SHARED_MEMORY_OFFSET = 0x400;
Controller_Touchscreen::Controller_Touchscreen(Core::System& system_) : ControllerBase{system_} {} Controller_Touchscreen::Controller_Touchscreen(Core::HID::HIDCore& hid_core_)
: ControllerBase{hid_core_} {
console = hid_core.GetEmulatedConsole();
}
Controller_Touchscreen::~Controller_Touchscreen() = default; Controller_Touchscreen::~Controller_Touchscreen() = default;
void Controller_Touchscreen::OnInit() { void Controller_Touchscreen::OnInit() {}
for (std::size_t id = 0; id < MAX_FINGERS; ++id) {
mouse_finger_id[id] = MAX_FINGERS;
keyboard_finger_id[id] = MAX_FINGERS;
udp_finger_id[id] = MAX_FINGERS;
}
}
void Controller_Touchscreen::OnRelease() {} void Controller_Touchscreen::OnRelease() {}
void Controller_Touchscreen::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, void Controller_Touchscreen::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data,
std::size_t size) { std::size_t size) {
shared_memory.header.timestamp = core_timing.GetCPUTicks(); touch_screen_lifo.timestamp = core_timing.GetCPUTicks();
shared_memory.header.total_entry_count = 17;
if (!IsControllerActivated()) { if (!IsControllerActivated()) {
shared_memory.header.entry_count = 0; touch_screen_lifo.buffer_count = 0;
shared_memory.header.last_entry_index = 0; touch_screen_lifo.buffer_tail = 0;
std::memcpy(data, &touch_screen_lifo, sizeof(touch_screen_lifo));
return; return;
} }
shared_memory.header.entry_count = 16;
const auto& last_entry = const auto touch_status = console->GetTouch();
shared_memory.shared_memory_entries[shared_memory.header.last_entry_index]; for (std::size_t id = 0; id < MAX_FINGERS; id++) {
shared_memory.header.last_entry_index = (shared_memory.header.last_entry_index + 1) % 17; const auto& current_touch = touch_status[id];
auto& cur_entry = shared_memory.shared_memory_entries[shared_memory.header.last_entry_index]; auto& finger = fingers[id];
finger.position = current_touch.position;
finger.id = current_touch.id;
cur_entry.sampling_number = last_entry.sampling_number + 1; if (finger.attribute.start_touch) {
cur_entry.sampling_number2 = cur_entry.sampling_number; finger.attribute.raw = 0;
continue;
const Input::TouchStatus& mouse_status = touch_mouse_device->GetStatus();
const Input::TouchStatus& udp_status = touch_udp_device->GetStatus();
for (std::size_t id = 0; id < mouse_status.size(); ++id) {
mouse_finger_id[id] = UpdateTouchInputEvent(mouse_status[id], mouse_finger_id[id]);
udp_finger_id[id] = UpdateTouchInputEvent(udp_status[id], udp_finger_id[id]);
} }
if (Settings::values.use_touch_from_button) { if (finger.attribute.end_touch) {
const Input::TouchStatus& keyboard_status = touch_btn_device->GetStatus(); finger.attribute.raw = 0;
for (std::size_t id = 0; id < mouse_status.size(); ++id) { finger.pressed = false;
keyboard_finger_id[id] = continue;
UpdateTouchInputEvent(keyboard_status[id], keyboard_finger_id[id]); }
if (!finger.pressed && current_touch.pressed) {
finger.attribute.start_touch.Assign(1);
finger.pressed = true;
continue;
}
if (finger.pressed && !current_touch.pressed) {
finger.attribute.raw = 0;
finger.attribute.end_touch.Assign(1);
} }
} }
std::array<Finger, 16> active_fingers; std::array<Core::HID::TouchFinger, MAX_FINGERS> active_fingers;
const auto end_iter = std::copy_if(fingers.begin(), fingers.end(), active_fingers.begin(), const auto end_iter = std::copy_if(fingers.begin(), fingers.end(), active_fingers.begin(),
[](const auto& finger) { return finger.pressed; }); [](const auto& finger) { return finger.pressed; });
const auto active_fingers_count = const auto active_fingers_count =
static_cast<std::size_t>(std::distance(active_fingers.begin(), end_iter)); static_cast<std::size_t>(std::distance(active_fingers.begin(), end_iter));
const u64 tick = core_timing.GetCPUTicks(); const u64 tick = core_timing.GetCPUTicks();
cur_entry.entry_count = static_cast<s32_le>(active_fingers_count); const auto& last_entry = touch_screen_lifo.ReadCurrentEntry().state;
next_state.sampling_number = last_entry.sampling_number + 1;
next_state.entry_count = static_cast<s32>(active_fingers_count);
for (std::size_t id = 0; id < MAX_FINGERS; ++id) { for (std::size_t id = 0; id < MAX_FINGERS; ++id) {
auto& touch_entry = cur_entry.states[id]; auto& touch_entry = next_state.states[id];
if (id < active_fingers_count) { if (id < active_fingers_count) {
const auto& [active_x, active_y] = active_fingers[id].position; const auto& [active_x, active_y] = active_fingers[id].position;
touch_entry.position = { touch_entry.position = {
@ -97,66 +107,9 @@ void Controller_Touchscreen::OnUpdate(const Core::Timing::CoreTiming& core_timin
touch_entry.finger = 0; touch_entry.finger = 0;
} }
} }
std::memcpy(data + SHARED_MEMORY_OFFSET, &shared_memory, sizeof(TouchScreenSharedMemory));
}
void Controller_Touchscreen::OnLoadInputDevices() { touch_screen_lifo.WriteNextEntry(next_state);
touch_mouse_device = Input::CreateDevice<Input::TouchDevice>("engine:emu_window"); std::memcpy(data + SHARED_MEMORY_OFFSET, &touch_screen_lifo, sizeof(touch_screen_lifo));
touch_udp_device = Input::CreateDevice<Input::TouchDevice>("engine:cemuhookudp");
touch_btn_device = Input::CreateDevice<Input::TouchDevice>("engine:touch_from_button");
}
std::optional<std::size_t> Controller_Touchscreen::GetUnusedFingerID() const {
// Dont assign any touch input to a finger if disabled
if (!Settings::values.touchscreen.enabled) {
return std::nullopt;
}
std::size_t first_free_id = 0;
while (first_free_id < MAX_FINGERS) {
if (!fingers[first_free_id].pressed) {
return first_free_id;
} else {
first_free_id++;
}
}
return std::nullopt;
}
std::size_t Controller_Touchscreen::UpdateTouchInputEvent(
const std::tuple<float, float, bool>& touch_input, std::size_t finger_id) {
const auto& [x, y, pressed] = touch_input;
if (finger_id > MAX_FINGERS) {
LOG_ERROR(Service_HID, "Invalid finger id {}", finger_id);
return MAX_FINGERS;
}
if (pressed) {
Attributes attribute{};
if (finger_id == MAX_FINGERS) {
const auto first_free_id = GetUnusedFingerID();
if (!first_free_id) {
// Invalid finger id do nothing
return MAX_FINGERS;
}
finger_id = first_free_id.value();
fingers[finger_id].pressed = true;
fingers[finger_id].id = static_cast<u32_le>(finger_id);
attribute.start_touch.Assign(1);
}
fingers[finger_id].position = {x, y};
fingers[finger_id].attribute = attribute;
return finger_id;
}
if (finger_id != MAX_FINGERS) {
if (!fingers[finger_id].attribute.end_touch) {
fingers[finger_id].attribute.end_touch.Assign(1);
fingers[finger_id].attribute.start_touch.Assign(0);
return finger_id;
}
fingers[finger_id].pressed = false;
}
return MAX_FINGERS;
} }
} // namespace Service::HID } // namespace Service::HID

View file

@ -9,18 +9,25 @@
#include "common/common_types.h" #include "common/common_types.h"
#include "common/point.h" #include "common/point.h"
#include "common/swap.h" #include "common/swap.h"
#include "core/frontend/input.h" #include "core/hid/hid_types.h"
#include "core/hle/service/hid/controllers/controller_base.h" #include "core/hle/service/hid/controllers/controller_base.h"
#include "core/hle/service/hid/ring_lifo.h"
namespace Core::HID {
class EmulatedConsole;
} // namespace Core::HID
namespace Service::HID { namespace Service::HID {
class Controller_Touchscreen final : public ControllerBase { class Controller_Touchscreen final : public ControllerBase {
public: public:
// This is nn::hid::TouchScreenModeForNx
enum class TouchScreenModeForNx : u8 { enum class TouchScreenModeForNx : u8 {
UseSystemSetting, UseSystemSetting,
Finger, Finger,
Heat2, Heat2,
}; };
// This is nn::hid::TouchScreenConfigurationForNx
struct TouchScreenConfigurationForNx { struct TouchScreenConfigurationForNx {
TouchScreenModeForNx mode; TouchScreenModeForNx mode;
INSERT_PADDING_BYTES_NOINIT(0x7); INSERT_PADDING_BYTES_NOINIT(0x7);
@ -29,7 +36,7 @@ public:
static_assert(sizeof(TouchScreenConfigurationForNx) == 0x17, static_assert(sizeof(TouchScreenConfigurationForNx) == 0x17,
"TouchScreenConfigurationForNx is an invalid size"); "TouchScreenConfigurationForNx is an invalid size");
explicit Controller_Touchscreen(Core::System& system_); explicit Controller_Touchscreen(Core::HID::HIDCore& hid_core_);
~Controller_Touchscreen() override; ~Controller_Touchscreen() override;
// Called when the controller is initialized // Called when the controller is initialized
@ -41,73 +48,24 @@ public:
// When the controller is requesting an update for the shared memory // When the controller is requesting an update for the shared memory
void OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, std::size_t size) override; void OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, std::size_t size) override;
// Called when input devices should be loaded
void OnLoadInputDevices() override;
private: private:
static constexpr std::size_t MAX_FINGERS = 16; static constexpr std::size_t MAX_FINGERS = 16;
// Returns an unused finger id, if there is no fingers available std::nullopt will be returned // This is nn::hid::TouchScreenState
std::optional<std::size_t> GetUnusedFingerID() const; struct TouchScreenState {
s64 sampling_number;
// If the touch is new it tries to assing a new finger id, if there is no fingers avaliable no s32 entry_count;
// changes will be made. Updates the coordinates if the finger id it's already set. If the touch INSERT_PADDING_BYTES(4); // Reserved
// ends delays the output by one frame to set the end_touch flag before finally freeing the std::array<Core::HID::TouchState, MAX_FINGERS> states;
// finger id
std::size_t UpdateTouchInputEvent(const std::tuple<float, float, bool>& touch_input,
std::size_t finger_id);
struct Attributes {
union {
u32 raw{};
BitField<0, 1, u32> start_touch;
BitField<1, 1, u32> end_touch;
}; };
}; static_assert(sizeof(TouchScreenState) == 0x290, "TouchScreenState is an invalid size");
static_assert(sizeof(Attributes) == 0x4, "Attributes is an invalid size");
struct TouchState { // This is nn::hid::detail::TouchScreenLifo
u64_le delta_time; Lifo<TouchScreenState> touch_screen_lifo{};
Attributes attribute; static_assert(sizeof(touch_screen_lifo) == 0x2C38, "touch_screen_lifo is an invalid size");
u32_le finger; TouchScreenState next_state{};
Common::Point<u32_le> position;
u32_le diameter_x;
u32_le diameter_y;
u32_le rotation_angle;
};
static_assert(sizeof(TouchState) == 0x28, "Touchstate is an invalid size");
struct TouchScreenEntry { std::array<Core::HID::TouchFinger, MAX_FINGERS> fingers;
s64_le sampling_number; Core::HID::EmulatedConsole* console;
s64_le sampling_number2;
s32_le entry_count;
std::array<TouchState, MAX_FINGERS> states;
};
static_assert(sizeof(TouchScreenEntry) == 0x298, "TouchScreenEntry is an invalid size");
struct TouchScreenSharedMemory {
CommonHeader header;
std::array<TouchScreenEntry, 17> shared_memory_entries{};
INSERT_PADDING_BYTES(0x3c8);
};
static_assert(sizeof(TouchScreenSharedMemory) == 0x3000,
"TouchScreenSharedMemory is an invalid size");
struct Finger {
u64_le last_touch{};
Common::Point<float> position;
u32_le id{};
bool pressed{};
Attributes attribute;
};
TouchScreenSharedMemory shared_memory{};
std::unique_ptr<Input::TouchDevice> touch_mouse_device;
std::unique_ptr<Input::TouchDevice> touch_udp_device;
std::unique_ptr<Input::TouchDevice> touch_btn_device;
std::array<std::size_t, MAX_FINGERS> mouse_finger_id;
std::array<std::size_t, MAX_FINGERS> keyboard_finger_id;
std::array<std::size_t, MAX_FINGERS> udp_finger_id;
std::array<Finger, MAX_FINGERS> fingers;
}; };
} // namespace Service::HID } // namespace Service::HID

View file

@ -5,12 +5,13 @@
#include <cstring> #include <cstring>
#include "common/common_types.h" #include "common/common_types.h"
#include "core/core_timing.h" #include "core/core_timing.h"
#include "core/hid/hid_core.h"
#include "core/hle/service/hid/controllers/xpad.h" #include "core/hle/service/hid/controllers/xpad.h"
namespace Service::HID { namespace Service::HID {
constexpr std::size_t SHARED_MEMORY_OFFSET = 0x3C00; constexpr std::size_t SHARED_MEMORY_OFFSET = 0x3C00;
Controller_XPad::Controller_XPad(Core::System& system_) : ControllerBase{system_} {} Controller_XPad::Controller_XPad(Core::HID::HIDCore& hid_core_) : ControllerBase{hid_core_} {}
Controller_XPad::~Controller_XPad() = default; Controller_XPad::~Controller_XPad() = default;
void Controller_XPad::OnInit() {} void Controller_XPad::OnInit() {}
@ -19,28 +20,19 @@ void Controller_XPad::OnRelease() {}
void Controller_XPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, void Controller_XPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data,
std::size_t size) { std::size_t size) {
for (auto& xpad_entry : shared_memory.shared_memory_entries) {
xpad_entry.header.timestamp = core_timing.GetCPUTicks();
xpad_entry.header.total_entry_count = 17;
if (!IsControllerActivated()) { if (!IsControllerActivated()) {
xpad_entry.header.entry_count = 0; basic_xpad_lifo.buffer_count = 0;
xpad_entry.header.last_entry_index = 0; basic_xpad_lifo.buffer_tail = 0;
std::memcpy(data + SHARED_MEMORY_OFFSET, &basic_xpad_lifo, sizeof(basic_xpad_lifo));
return; return;
} }
xpad_entry.header.entry_count = 16;
const auto& last_entry = xpad_entry.pad_states[xpad_entry.header.last_entry_index]; const auto& last_entry = basic_xpad_lifo.ReadCurrentEntry().state;
xpad_entry.header.last_entry_index = (xpad_entry.header.last_entry_index + 1) % 17; next_state.sampling_number = last_entry.sampling_number + 1;
auto& cur_entry = xpad_entry.pad_states[xpad_entry.header.last_entry_index];
cur_entry.sampling_number = last_entry.sampling_number + 1;
cur_entry.sampling_number2 = cur_entry.sampling_number;
}
// TODO(ogniK): Update xpad states // TODO(ogniK): Update xpad states
std::memcpy(data + SHARED_MEMORY_OFFSET, &shared_memory, sizeof(SharedMemory)); basic_xpad_lifo.WriteNextEntry(next_state);
std::memcpy(data + SHARED_MEMORY_OFFSET, &basic_xpad_lifo, sizeof(basic_xpad_lifo));
} }
void Controller_XPad::OnLoadInputDevices() {}
} // namespace Service::HID } // namespace Service::HID

View file

@ -8,12 +8,14 @@
#include "common/common_funcs.h" #include "common/common_funcs.h"
#include "common/common_types.h" #include "common/common_types.h"
#include "common/swap.h" #include "common/swap.h"
#include "core/hid/hid_types.h"
#include "core/hle/service/hid/controllers/controller_base.h" #include "core/hle/service/hid/controllers/controller_base.h"
#include "core/hle/service/hid/ring_lifo.h"
namespace Service::HID { namespace Service::HID {
class Controller_XPad final : public ControllerBase { class Controller_XPad final : public ControllerBase {
public: public:
explicit Controller_XPad(Core::System& system_); explicit Controller_XPad(Core::HID::HIDCore& hid_core_);
~Controller_XPad() override; ~Controller_XPad() override;
// Called when the controller is initialized // Called when the controller is initialized
@ -25,13 +27,11 @@ public:
// When the controller is requesting an update for the shared memory // When the controller is requesting an update for the shared memory
void OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, std::size_t size) override; void OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, std::size_t size) override;
// Called when input devices should be loaded
void OnLoadInputDevices() override;
private: private:
struct Attributes { // This is nn::hid::BasicXpadAttributeSet
struct BasicXpadAttributeSet {
union { union {
u32_le raw{}; u32 raw{};
BitField<0, 1, u32> is_connected; BitField<0, 1, u32> is_connected;
BitField<1, 1, u32> is_wired; BitField<1, 1, u32> is_wired;
BitField<2, 1, u32> is_left_connected; BitField<2, 1, u32> is_left_connected;
@ -40,11 +40,12 @@ private:
BitField<5, 1, u32> is_right_wired; BitField<5, 1, u32> is_right_wired;
}; };
}; };
static_assert(sizeof(Attributes) == 4, "Attributes is an invalid size"); static_assert(sizeof(BasicXpadAttributeSet) == 4, "BasicXpadAttributeSet is an invalid size");
struct Buttons { // This is nn::hid::BasicXpadButtonSet
struct BasicXpadButtonSet {
union { union {
u32_le raw{}; u32 raw{};
// Button states // Button states
BitField<0, 1, u32> a; BitField<0, 1, u32> a;
BitField<1, 1, u32> b; BitField<1, 1, u32> b;
@ -88,35 +89,21 @@ private:
BitField<30, 1, u32> handheld_left_b; BitField<30, 1, u32> handheld_left_b;
}; };
}; };
static_assert(sizeof(Buttons) == 4, "Buttons is an invalid size"); static_assert(sizeof(BasicXpadButtonSet) == 4, "BasicXpadButtonSet is an invalid size");
struct AnalogStick { // This is nn::hid::detail::BasicXpadState
s32_le x; struct BasicXpadState {
s32_le y; s64 sampling_number;
BasicXpadAttributeSet attributes;
BasicXpadButtonSet pad_states;
Core::HID::AnalogStickState l_stick;
Core::HID::AnalogStickState r_stick;
}; };
static_assert(sizeof(AnalogStick) == 0x8, "AnalogStick is an invalid size"); static_assert(sizeof(BasicXpadState) == 0x20, "BasicXpadState is an invalid size");
struct XPadState { // This is nn::hid::detail::BasicXpadLifo
s64_le sampling_number; Lifo<BasicXpadState> basic_xpad_lifo{};
s64_le sampling_number2; static_assert(sizeof(basic_xpad_lifo) == 0x2C8, "basic_xpad_lifo is an invalid size");
Attributes attributes; BasicXpadState next_state{};
Buttons pad_states;
AnalogStick l_stick;
AnalogStick r_stick;
};
static_assert(sizeof(XPadState) == 0x28, "XPadState is an invalid size");
struct XPadEntry {
CommonHeader header;
std::array<XPadState, 17> pad_states{};
INSERT_PADDING_BYTES(0x138);
};
static_assert(sizeof(XPadEntry) == 0x400, "XPadEntry is an invalid size");
struct SharedMemory {
std::array<XPadEntry, 4> shared_memory_entries{};
};
static_assert(sizeof(SharedMemory) == 0x1000, "SharedMemory is an invalid size");
SharedMemory shared_memory{};
}; };
} // namespace Service::HID } // namespace Service::HID

View file

@ -8,7 +8,7 @@
#include "common/settings.h" #include "common/settings.h"
#include "core/core.h" #include "core/core.h"
#include "core/core_timing.h" #include "core/core_timing.h"
#include "core/frontend/input.h" #include "core/hid/hid_core.h"
#include "core/hle/ipc_helpers.h" #include "core/hle/ipc_helpers.h"
#include "core/hle/kernel/k_readable_event.h" #include "core/hle/kernel/k_readable_event.h"
#include "core/hle/kernel/k_shared_memory.h" #include "core/hle/kernel/k_shared_memory.h"
@ -34,10 +34,10 @@
namespace Service::HID { namespace Service::HID {
// Updating period for each HID device. // Updating period for each HID device.
// HID is polled every 15ms, this value was derived from // Period time is obtained by measuring the number of samples in a second on HW using a homebrew
// https://github.com/dekuNukem/Nintendo_Switch_Reverse_Engineering#joy-con-status-data-packet constexpr auto pad_update_ns = std::chrono::nanoseconds{4 * 1000 * 1000}; // (4ms, 250Hz)
constexpr auto pad_update_ns = std::chrono::nanoseconds{1000 * 1000}; // (1ms, 1000Hz) constexpr auto keyboard_update_ns = std::chrono::nanoseconds{8 * 1000 * 1000}; // (8ms, 125Hz)
constexpr auto motion_update_ns = std::chrono::nanoseconds{15 * 1000 * 1000}; // (15ms, 66.666Hz) constexpr auto motion_update_ns = std::chrono::nanoseconds{5 * 1000 * 1000}; // (5ms, 200Hz)
constexpr std::size_t SHARED_MEMORY_SIZE = 0x40000; constexpr std::size_t SHARED_MEMORY_SIZE = 0x40000;
IAppletResource::IAppletResource(Core::System& system_, IAppletResource::IAppletResource(Core::System& system_,
@ -79,17 +79,24 @@ IAppletResource::IAppletResource(Core::System& system_,
const auto guard = LockService(); const auto guard = LockService();
UpdateControllers(user_data, ns_late); UpdateControllers(user_data, ns_late);
}); });
keyboard_update_event = Core::Timing::CreateEvent(
"HID::UpdatekeyboardCallback",
[this](std::uintptr_t user_data, std::chrono::nanoseconds ns_late) {
const auto guard = LockService();
UpdateKeyboard(user_data, ns_late);
});
motion_update_event = Core::Timing::CreateEvent( motion_update_event = Core::Timing::CreateEvent(
"HID::MotionPadCallback", "HID::UpdateMotionCallback",
[this](std::uintptr_t user_data, std::chrono::nanoseconds ns_late) { [this](std::uintptr_t user_data, std::chrono::nanoseconds ns_late) {
const auto guard = LockService(); const auto guard = LockService();
UpdateMotion(user_data, ns_late); UpdateMotion(user_data, ns_late);
}); });
system.CoreTiming().ScheduleEvent(pad_update_ns, pad_update_event); system.CoreTiming().ScheduleEvent(pad_update_ns, pad_update_event);
system.CoreTiming().ScheduleEvent(keyboard_update_ns, keyboard_update_event);
system.CoreTiming().ScheduleEvent(motion_update_ns, motion_update_event); system.CoreTiming().ScheduleEvent(motion_update_ns, motion_update_event);
ReloadInputDevices(); system.HIDCore().ReloadInputDevices();
} }
void IAppletResource::ActivateController(HidController controller) { void IAppletResource::ActivateController(HidController controller) {
@ -102,6 +109,7 @@ void IAppletResource::DeactivateController(HidController controller) {
IAppletResource::~IAppletResource() { IAppletResource::~IAppletResource() {
system.CoreTiming().UnscheduleEvent(pad_update_event, 0); system.CoreTiming().UnscheduleEvent(pad_update_event, 0);
system.CoreTiming().UnscheduleEvent(keyboard_update_event, 0);
system.CoreTiming().UnscheduleEvent(motion_update_event, 0); system.CoreTiming().UnscheduleEvent(motion_update_event, 0);
} }
@ -117,23 +125,37 @@ void IAppletResource::UpdateControllers(std::uintptr_t user_data,
std::chrono::nanoseconds ns_late) { std::chrono::nanoseconds ns_late) {
auto& core_timing = system.CoreTiming(); auto& core_timing = system.CoreTiming();
const bool should_reload = Settings::values.is_device_reload_pending.exchange(false);
for (const auto& controller : controllers) { for (const auto& controller : controllers) {
if (should_reload) { // Keyboard has it's own update event
controller->OnLoadInputDevices(); if (controller == controllers[static_cast<size_t>(HidController::Keyboard)]) {
continue;
} }
controller->OnUpdate(core_timing, system.Kernel().GetHidSharedMem().GetPointer(), controller->OnUpdate(core_timing, system.Kernel().GetHidSharedMem().GetPointer(),
SHARED_MEMORY_SIZE); SHARED_MEMORY_SIZE);
} }
// If ns_late is higher than the update rate ignore the delay // If ns_late is higher than the update rate ignore the delay
if (ns_late > motion_update_ns) { if (ns_late > pad_update_ns) {
ns_late = {}; ns_late = {};
} }
core_timing.ScheduleEvent(pad_update_ns - ns_late, pad_update_event); core_timing.ScheduleEvent(pad_update_ns - ns_late, pad_update_event);
} }
void IAppletResource::UpdateKeyboard(std::uintptr_t user_data, std::chrono::nanoseconds ns_late) {
auto& core_timing = system.CoreTiming();
controllers[static_cast<size_t>(HidController::Keyboard)]->OnUpdate(
core_timing, system.Kernel().GetHidSharedMem().GetPointer(), SHARED_MEMORY_SIZE);
// If ns_late is higher than the update rate ignore the delay
if (ns_late > keyboard_update_ns) {
ns_late = {};
}
core_timing.ScheduleEvent(keyboard_update_ns - ns_late, keyboard_update_event);
}
void IAppletResource::UpdateMotion(std::uintptr_t user_data, std::chrono::nanoseconds ns_late) { void IAppletResource::UpdateMotion(std::uintptr_t user_data, std::chrono::nanoseconds ns_late) {
auto& core_timing = system.CoreTiming(); auto& core_timing = system.CoreTiming();
@ -166,7 +188,7 @@ public:
private: private:
void InitializeVibrationDevice(Kernel::HLERequestContext& ctx) { void InitializeVibrationDevice(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx}; IPC::RequestParser rp{ctx};
const auto vibration_device_handle{rp.PopRaw<Controller_NPad::DeviceHandle>()}; const auto vibration_device_handle{rp.PopRaw<Core::HID::VibrationDeviceHandle>()};
if (applet_resource != nullptr) { if (applet_resource != nullptr) {
applet_resource->GetController<Controller_NPad>(HidController::NPad) applet_resource->GetController<Controller_NPad>(HidController::NPad)
@ -422,6 +444,7 @@ void Hid::ActivateXpad(Kernel::HLERequestContext& ctx) {
INSERT_PADDING_WORDS_NOINIT(1); INSERT_PADDING_WORDS_NOINIT(1);
u64 applet_resource_user_id; u64 applet_resource_user_id;
}; };
static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
const auto parameters{rp.PopRaw<Parameters>()}; const auto parameters{rp.PopRaw<Parameters>()};
@ -448,19 +471,18 @@ void Hid::GetXpadIDs(Kernel::HLERequestContext& ctx) {
void Hid::ActivateSixAxisSensor(Kernel::HLERequestContext& ctx) { void Hid::ActivateSixAxisSensor(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx}; IPC::RequestParser rp{ctx};
struct Parameters { struct Parameters {
Controller_NPad::DeviceHandle sixaxis_handle; u32 basic_xpad_id;
INSERT_PADDING_WORDS_NOINIT(1); INSERT_PADDING_WORDS_NOINIT(1);
u64 applet_resource_user_id; u64 applet_resource_user_id;
}; };
static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
const auto parameters{rp.PopRaw<Parameters>()}; const auto parameters{rp.PopRaw<Parameters>()};
applet_resource->GetController<Controller_NPad>(HidController::NPad).SetSixAxisEnabled(true); // This function does nothing on 10.0.0+
LOG_DEBUG(Service_HID, LOG_WARNING(Service_HID, "(STUBBED) called, basic_xpad_id={}, applet_resource_user_id={}",
"called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}", parameters.basic_xpad_id, parameters.applet_resource_user_id);
parameters.sixaxis_handle.npad_type, parameters.sixaxis_handle.npad_id,
parameters.sixaxis_handle.device_index, parameters.applet_resource_user_id);
IPC::ResponseBuilder rb{ctx, 2}; IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess); rb.Push(ResultSuccess);
@ -469,19 +491,18 @@ void Hid::ActivateSixAxisSensor(Kernel::HLERequestContext& ctx) {
void Hid::DeactivateSixAxisSensor(Kernel::HLERequestContext& ctx) { void Hid::DeactivateSixAxisSensor(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx}; IPC::RequestParser rp{ctx};
struct Parameters { struct Parameters {
Controller_NPad::DeviceHandle sixaxis_handle; u32 basic_xpad_id;
INSERT_PADDING_WORDS_NOINIT(1); INSERT_PADDING_WORDS_NOINIT(1);
u64 applet_resource_user_id; u64 applet_resource_user_id;
}; };
static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
const auto parameters{rp.PopRaw<Parameters>()}; const auto parameters{rp.PopRaw<Parameters>()};
applet_resource->GetController<Controller_NPad>(HidController::NPad).SetSixAxisEnabled(false); // This function does nothing on 10.0.0+
LOG_DEBUG(Service_HID, LOG_WARNING(Service_HID, "(STUBBED) called, basic_xpad_id={}, applet_resource_user_id={}",
"called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}", parameters.basic_xpad_id, parameters.applet_resource_user_id);
parameters.sixaxis_handle.npad_type, parameters.sixaxis_handle.npad_id,
parameters.sixaxis_handle.device_index, parameters.applet_resource_user_id);
IPC::ResponseBuilder rb{ctx, 2}; IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess); rb.Push(ResultSuccess);
@ -490,14 +511,16 @@ void Hid::DeactivateSixAxisSensor(Kernel::HLERequestContext& ctx) {
void Hid::StartSixAxisSensor(Kernel::HLERequestContext& ctx) { void Hid::StartSixAxisSensor(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx}; IPC::RequestParser rp{ctx};
struct Parameters { struct Parameters {
Controller_NPad::DeviceHandle sixaxis_handle; Core::HID::SixAxisSensorHandle sixaxis_handle;
INSERT_PADDING_WORDS_NOINIT(1); INSERT_PADDING_WORDS_NOINIT(1);
u64 applet_resource_user_id; u64 applet_resource_user_id;
}; };
static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
const auto parameters{rp.PopRaw<Parameters>()}; const auto parameters{rp.PopRaw<Parameters>()};
applet_resource->GetController<Controller_NPad>(HidController::NPad).SetSixAxisEnabled(true); applet_resource->GetController<Controller_NPad>(HidController::NPad)
.SetSixAxisEnabled(parameters.sixaxis_handle, true);
LOG_DEBUG(Service_HID, LOG_DEBUG(Service_HID,
"called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}", "called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}",
@ -511,14 +534,16 @@ void Hid::StartSixAxisSensor(Kernel::HLERequestContext& ctx) {
void Hid::StopSixAxisSensor(Kernel::HLERequestContext& ctx) { void Hid::StopSixAxisSensor(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx}; IPC::RequestParser rp{ctx};
struct Parameters { struct Parameters {
Controller_NPad::DeviceHandle sixaxis_handle; Core::HID::SixAxisSensorHandle sixaxis_handle;
INSERT_PADDING_WORDS_NOINIT(1); INSERT_PADDING_WORDS_NOINIT(1);
u64 applet_resource_user_id; u64 applet_resource_user_id;
}; };
static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
const auto parameters{rp.PopRaw<Parameters>()}; const auto parameters{rp.PopRaw<Parameters>()};
applet_resource->GetController<Controller_NPad>(HidController::NPad).SetSixAxisEnabled(false); applet_resource->GetController<Controller_NPad>(HidController::NPad)
.SetSixAxisEnabled(parameters.sixaxis_handle, false);
LOG_DEBUG(Service_HID, LOG_DEBUG(Service_HID,
"called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}", "called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}",
@ -534,15 +559,19 @@ void Hid::EnableSixAxisSensorFusion(Kernel::HLERequestContext& ctx) {
struct Parameters { struct Parameters {
bool enable_sixaxis_sensor_fusion; bool enable_sixaxis_sensor_fusion;
INSERT_PADDING_BYTES_NOINIT(3); INSERT_PADDING_BYTES_NOINIT(3);
Controller_NPad::DeviceHandle sixaxis_handle; Core::HID::SixAxisSensorHandle sixaxis_handle;
u64 applet_resource_user_id; u64 applet_resource_user_id;
}; };
static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size."); static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
const auto parameters{rp.PopRaw<Parameters>()}; const auto parameters{rp.PopRaw<Parameters>()};
LOG_WARNING(Service_HID, applet_resource->GetController<Controller_NPad>(HidController::NPad)
"(STUBBED) called, enable_sixaxis_sensor_fusion={}, npad_type={}, npad_id={}, " .SetSixAxisFusionEnabled(parameters.sixaxis_handle,
parameters.enable_sixaxis_sensor_fusion);
LOG_DEBUG(Service_HID,
"called, enable_sixaxis_sensor_fusion={}, npad_type={}, npad_id={}, "
"device_index={}, applet_resource_user_id={}", "device_index={}, applet_resource_user_id={}",
parameters.enable_sixaxis_sensor_fusion, parameters.sixaxis_handle.npad_type, parameters.enable_sixaxis_sensor_fusion, parameters.sixaxis_handle.npad_type,
parameters.sixaxis_handle.npad_id, parameters.sixaxis_handle.device_index, parameters.sixaxis_handle.npad_id, parameters.sixaxis_handle.device_index,
@ -555,9 +584,9 @@ void Hid::EnableSixAxisSensorFusion(Kernel::HLERequestContext& ctx) {
void Hid::SetSixAxisSensorFusionParameters(Kernel::HLERequestContext& ctx) { void Hid::SetSixAxisSensorFusionParameters(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx}; IPC::RequestParser rp{ctx};
struct Parameters { struct Parameters {
Controller_NPad::DeviceHandle sixaxis_handle; Core::HID::SixAxisSensorHandle sixaxis_handle;
f32 parameter1; Core::HID::SixAxisSensorFusionParameters sixaxis_fusion;
f32 parameter2; INSERT_PADDING_WORDS_NOINIT(1);
u64 applet_resource_user_id; u64 applet_resource_user_id;
}; };
static_assert(sizeof(Parameters) == 0x18, "Parameters has incorrect size."); static_assert(sizeof(Parameters) == 0x18, "Parameters has incorrect size.");
@ -565,14 +594,14 @@ void Hid::SetSixAxisSensorFusionParameters(Kernel::HLERequestContext& ctx) {
const auto parameters{rp.PopRaw<Parameters>()}; const auto parameters{rp.PopRaw<Parameters>()};
applet_resource->GetController<Controller_NPad>(HidController::NPad) applet_resource->GetController<Controller_NPad>(HidController::NPad)
.SetSixAxisFusionParameters(parameters.parameter1, parameters.parameter2); .SetSixAxisFusionParameters(parameters.sixaxis_handle, parameters.sixaxis_fusion);
LOG_WARNING(Service_HID, LOG_DEBUG(Service_HID,
"(STUBBED) called, npad_type={}, npad_id={}, device_index={}, parameter1={}, " "called, npad_type={}, npad_id={}, device_index={}, parameter1={}, "
"parameter2={}, applet_resource_user_id={}", "parameter2={}, applet_resource_user_id={}",
parameters.sixaxis_handle.npad_type, parameters.sixaxis_handle.npad_id, parameters.sixaxis_handle.npad_type, parameters.sixaxis_handle.npad_id,
parameters.sixaxis_handle.device_index, parameters.parameter1, parameters.sixaxis_handle.device_index, parameters.sixaxis_fusion.parameter1,
parameters.parameter2, parameters.applet_resource_user_id); parameters.sixaxis_fusion.parameter2, parameters.applet_resource_user_id);
IPC::ResponseBuilder rb{ctx, 2}; IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess); rb.Push(ResultSuccess);
@ -581,35 +610,33 @@ void Hid::SetSixAxisSensorFusionParameters(Kernel::HLERequestContext& ctx) {
void Hid::GetSixAxisSensorFusionParameters(Kernel::HLERequestContext& ctx) { void Hid::GetSixAxisSensorFusionParameters(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx}; IPC::RequestParser rp{ctx};
struct Parameters { struct Parameters {
Controller_NPad::DeviceHandle sixaxis_handle; Core::HID::SixAxisSensorHandle sixaxis_handle;
INSERT_PADDING_WORDS_NOINIT(1);
u64 applet_resource_user_id; u64 applet_resource_user_id;
}; };
static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size."); static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
f32 parameter1 = 0;
f32 parameter2 = 0;
const auto parameters{rp.PopRaw<Parameters>()}; const auto parameters{rp.PopRaw<Parameters>()};
std::tie(parameter1, parameter2) = const auto sixaxis_fusion_parameters =
applet_resource->GetController<Controller_NPad>(HidController::NPad) applet_resource->GetController<Controller_NPad>(HidController::NPad)
.GetSixAxisFusionParameters(); .GetSixAxisFusionParameters(parameters.sixaxis_handle);
LOG_WARNING( LOG_DEBUG(Service_HID,
Service_HID, "called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}",
"(STUBBED) called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}",
parameters.sixaxis_handle.npad_type, parameters.sixaxis_handle.npad_id, parameters.sixaxis_handle.npad_type, parameters.sixaxis_handle.npad_id,
parameters.sixaxis_handle.device_index, parameters.applet_resource_user_id); parameters.sixaxis_handle.device_index, parameters.applet_resource_user_id);
IPC::ResponseBuilder rb{ctx, 4}; IPC::ResponseBuilder rb{ctx, 4};
rb.Push(ResultSuccess); rb.Push(ResultSuccess);
rb.Push(parameter1); rb.PushRaw(sixaxis_fusion_parameters);
rb.Push(parameter2);
} }
void Hid::ResetSixAxisSensorFusionParameters(Kernel::HLERequestContext& ctx) { void Hid::ResetSixAxisSensorFusionParameters(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx}; IPC::RequestParser rp{ctx};
struct Parameters { struct Parameters {
Controller_NPad::DeviceHandle sixaxis_handle; Core::HID::SixAxisSensorHandle sixaxis_handle;
INSERT_PADDING_WORDS_NOINIT(1);
u64 applet_resource_user_id; u64 applet_resource_user_id;
}; };
static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size."); static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
@ -617,11 +644,10 @@ void Hid::ResetSixAxisSensorFusionParameters(Kernel::HLERequestContext& ctx) {
const auto parameters{rp.PopRaw<Parameters>()}; const auto parameters{rp.PopRaw<Parameters>()};
applet_resource->GetController<Controller_NPad>(HidController::NPad) applet_resource->GetController<Controller_NPad>(HidController::NPad)
.ResetSixAxisFusionParameters(); .ResetSixAxisFusionParameters(parameters.sixaxis_handle);
LOG_WARNING( LOG_DEBUG(Service_HID,
Service_HID, "called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}",
"(STUBBED) called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}",
parameters.sixaxis_handle.npad_type, parameters.sixaxis_handle.npad_id, parameters.sixaxis_handle.npad_type, parameters.sixaxis_handle.npad_id,
parameters.sixaxis_handle.device_index, parameters.applet_resource_user_id); parameters.sixaxis_handle.device_index, parameters.applet_resource_user_id);
@ -631,12 +657,12 @@ void Hid::ResetSixAxisSensorFusionParameters(Kernel::HLERequestContext& ctx) {
void Hid::SetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx) { void Hid::SetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx}; IPC::RequestParser rp{ctx};
const auto sixaxis_handle{rp.PopRaw<Controller_NPad::DeviceHandle>()}; const auto sixaxis_handle{rp.PopRaw<Core::HID::SixAxisSensorHandle>()};
const auto drift_mode{rp.PopEnum<Controller_NPad::GyroscopeZeroDriftMode>()}; const auto drift_mode{rp.PopEnum<Controller_NPad::GyroscopeZeroDriftMode>()};
const auto applet_resource_user_id{rp.Pop<u64>()}; const auto applet_resource_user_id{rp.Pop<u64>()};
applet_resource->GetController<Controller_NPad>(HidController::NPad) applet_resource->GetController<Controller_NPad>(HidController::NPad)
.SetGyroscopeZeroDriftMode(drift_mode); .SetGyroscopeZeroDriftMode(sixaxis_handle, drift_mode);
LOG_DEBUG(Service_HID, LOG_DEBUG(Service_HID,
"called, npad_type={}, npad_id={}, device_index={}, drift_mode={}, " "called, npad_type={}, npad_id={}, device_index={}, drift_mode={}, "
@ -651,10 +677,11 @@ void Hid::SetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx) {
void Hid::GetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx) { void Hid::GetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx}; IPC::RequestParser rp{ctx};
struct Parameters { struct Parameters {
Controller_NPad::DeviceHandle sixaxis_handle; Core::HID::SixAxisSensorHandle sixaxis_handle;
INSERT_PADDING_WORDS_NOINIT(1); INSERT_PADDING_WORDS_NOINIT(1);
u64 applet_resource_user_id; u64 applet_resource_user_id;
}; };
static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
const auto parameters{rp.PopRaw<Parameters>()}; const auto parameters{rp.PopRaw<Parameters>()};
@ -666,21 +693,23 @@ void Hid::GetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 3}; IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess); rb.Push(ResultSuccess);
rb.PushEnum(applet_resource->GetController<Controller_NPad>(HidController::NPad) rb.PushEnum(applet_resource->GetController<Controller_NPad>(HidController::NPad)
.GetGyroscopeZeroDriftMode()); .GetGyroscopeZeroDriftMode(parameters.sixaxis_handle));
} }
void Hid::ResetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx) { void Hid::ResetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx}; IPC::RequestParser rp{ctx};
struct Parameters { struct Parameters {
Controller_NPad::DeviceHandle sixaxis_handle; Core::HID::SixAxisSensorHandle sixaxis_handle;
INSERT_PADDING_WORDS_NOINIT(1); INSERT_PADDING_WORDS_NOINIT(1);
u64 applet_resource_user_id; u64 applet_resource_user_id;
}; };
static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
const auto parameters{rp.PopRaw<Parameters>()}; const auto parameters{rp.PopRaw<Parameters>()};
const auto drift_mode{Controller_NPad::GyroscopeZeroDriftMode::Standard};
applet_resource->GetController<Controller_NPad>(HidController::NPad) applet_resource->GetController<Controller_NPad>(HidController::NPad)
.SetGyroscopeZeroDriftMode(Controller_NPad::GyroscopeZeroDriftMode::Standard); .SetGyroscopeZeroDriftMode(parameters.sixaxis_handle, drift_mode);
LOG_DEBUG(Service_HID, LOG_DEBUG(Service_HID,
"called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}", "called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}",
@ -694,10 +723,11 @@ void Hid::ResetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx) {
void Hid::IsSixAxisSensorAtRest(Kernel::HLERequestContext& ctx) { void Hid::IsSixAxisSensorAtRest(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx}; IPC::RequestParser rp{ctx};
struct Parameters { struct Parameters {
Controller_NPad::DeviceHandle sixaxis_handle; Core::HID::SixAxisSensorHandle sixaxis_handle;
INSERT_PADDING_WORDS_NOINIT(1); INSERT_PADDING_WORDS_NOINIT(1);
u64 applet_resource_user_id; u64 applet_resource_user_id;
}; };
static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
const auto parameters{rp.PopRaw<Parameters>()}; const auto parameters{rp.PopRaw<Parameters>()};
@ -709,16 +739,17 @@ void Hid::IsSixAxisSensorAtRest(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 3}; IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess); rb.Push(ResultSuccess);
rb.Push(applet_resource->GetController<Controller_NPad>(HidController::NPad) rb.Push(applet_resource->GetController<Controller_NPad>(HidController::NPad)
.IsSixAxisSensorAtRest()); .IsSixAxisSensorAtRest(parameters.sixaxis_handle));
} }
void Hid::IsFirmwareUpdateAvailableForSixAxisSensor(Kernel::HLERequestContext& ctx) { void Hid::IsFirmwareUpdateAvailableForSixAxisSensor(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx}; IPC::RequestParser rp{ctx};
struct Parameters { struct Parameters {
Controller_NPad::DeviceHandle sixaxis_handle; Core::HID::SixAxisSensorHandle sixaxis_handle;
INSERT_PADDING_WORDS_NOINIT(1); INSERT_PADDING_WORDS_NOINIT(1);
u64 applet_resource_user_id; u64 applet_resource_user_id;
}; };
static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
const auto parameters{rp.PopRaw<Parameters>()}; const auto parameters{rp.PopRaw<Parameters>()};
@ -740,13 +771,14 @@ void Hid::ActivateGesture(Kernel::HLERequestContext& ctx) {
INSERT_PADDING_WORDS_NOINIT(1); INSERT_PADDING_WORDS_NOINIT(1);
u64 applet_resource_user_id; u64 applet_resource_user_id;
}; };
static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
const auto parameters{rp.PopRaw<Parameters>()}; const auto parameters{rp.PopRaw<Parameters>()};
applet_resource->ActivateController(HidController::Gesture); applet_resource->ActivateController(HidController::Gesture);
LOG_DEBUG(Service_HID, "called, unknown={}, applet_resource_user_id={}", parameters.unknown, LOG_WARNING(Service_HID, "(STUBBED) called, unknown={}, applet_resource_user_id={}",
parameters.applet_resource_user_id); parameters.unknown, parameters.applet_resource_user_id);
IPC::ResponseBuilder rb{ctx, 2}; IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess); rb.Push(ResultSuccess);
@ -754,12 +786,20 @@ void Hid::ActivateGesture(Kernel::HLERequestContext& ctx) {
void Hid::SetSupportedNpadStyleSet(Kernel::HLERequestContext& ctx) { void Hid::SetSupportedNpadStyleSet(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx}; IPC::RequestParser rp{ctx};
const auto supported_styleset{rp.Pop<u32>()}; struct Parameters {
Core::HID::NpadStyleSet supported_styleset;
INSERT_PADDING_WORDS_NOINIT(1);
u64 applet_resource_user_id;
};
static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
const auto parameters{rp.PopRaw<Parameters>()};
applet_resource->GetController<Controller_NPad>(HidController::NPad) applet_resource->GetController<Controller_NPad>(HidController::NPad)
.SetSupportedStyleSet({supported_styleset}); .SetSupportedStyleSet({parameters.supported_styleset});
LOG_DEBUG(Service_HID, "called, supported_styleset={}", supported_styleset); LOG_DEBUG(Service_HID, "called, supported_styleset={}, applet_resource_user_id={}",
parameters.supported_styleset, parameters.applet_resource_user_id);
IPC::ResponseBuilder rb{ctx, 2}; IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess); rb.Push(ResultSuccess);
@ -773,7 +813,7 @@ void Hid::GetSupportedNpadStyleSet(Kernel::HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 3}; IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess); rb.Push(ResultSuccess);
rb.Push(applet_resource->GetController<Controller_NPad>(HidController::NPad) rb.PushEnum(applet_resource->GetController<Controller_NPad>(HidController::NPad)
.GetSupportedStyleSet() .GetSupportedStyleSet()
.raw); .raw);
} }
@ -818,11 +858,12 @@ void Hid::DeactivateNpad(Kernel::HLERequestContext& ctx) {
void Hid::AcquireNpadStyleSetUpdateEventHandle(Kernel::HLERequestContext& ctx) { void Hid::AcquireNpadStyleSetUpdateEventHandle(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx}; IPC::RequestParser rp{ctx};
struct Parameters { struct Parameters {
u32 npad_id; Core::HID::NpadIdType npad_id;
INSERT_PADDING_WORDS_NOINIT(1); INSERT_PADDING_WORDS_NOINIT(1);
u64 applet_resource_user_id; u64 applet_resource_user_id;
u64 unknown; u64 unknown;
}; };
static_assert(sizeof(Parameters) == 0x18, "Parameters has incorrect size.");
const auto parameters{rp.PopRaw<Parameters>()}; const auto parameters{rp.PopRaw<Parameters>()};
@ -838,10 +879,11 @@ void Hid::AcquireNpadStyleSetUpdateEventHandle(Kernel::HLERequestContext& ctx) {
void Hid::DisconnectNpad(Kernel::HLERequestContext& ctx) { void Hid::DisconnectNpad(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx}; IPC::RequestParser rp{ctx};
struct Parameters { struct Parameters {
u32 npad_id; Core::HID::NpadIdType npad_id;
INSERT_PADDING_WORDS_NOINIT(1); INSERT_PADDING_WORDS_NOINIT(1);
u64 applet_resource_user_id; u64 applet_resource_user_id;
}; };
static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
const auto parameters{rp.PopRaw<Parameters>()}; const auto parameters{rp.PopRaw<Parameters>()};
@ -857,7 +899,7 @@ void Hid::DisconnectNpad(Kernel::HLERequestContext& ctx) {
void Hid::GetPlayerLedPattern(Kernel::HLERequestContext& ctx) { void Hid::GetPlayerLedPattern(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx}; IPC::RequestParser rp{ctx};
const auto npad_id{rp.Pop<u32>()}; const auto npad_id{rp.PopEnum<Core::HID::NpadIdType>()};
LOG_DEBUG(Service_HID, "called, npad_id={}", npad_id); LOG_DEBUG(Service_HID, "called, npad_id={}", npad_id);
@ -872,16 +914,17 @@ void Hid::ActivateNpadWithRevision(Kernel::HLERequestContext& ctx) {
// Should have no effect with how our npad sets up the data // Should have no effect with how our npad sets up the data
IPC::RequestParser rp{ctx}; IPC::RequestParser rp{ctx};
struct Parameters { struct Parameters {
u32 unknown; s32 revision;
INSERT_PADDING_WORDS_NOINIT(1); INSERT_PADDING_WORDS_NOINIT(1);
u64 applet_resource_user_id; u64 applet_resource_user_id;
}; };
static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
const auto parameters{rp.PopRaw<Parameters>()}; const auto parameters{rp.PopRaw<Parameters>()};
applet_resource->ActivateController(HidController::NPad); applet_resource->ActivateController(HidController::NPad);
LOG_DEBUG(Service_HID, "called, unknown={}, applet_resource_user_id={}", parameters.unknown, LOG_DEBUG(Service_HID, "called, revision={}, applet_resource_user_id={}", parameters.revision,
parameters.applet_resource_user_id); parameters.applet_resource_user_id);
IPC::ResponseBuilder rb{ctx, 2}; IPC::ResponseBuilder rb{ctx, 2};
@ -891,7 +934,7 @@ void Hid::ActivateNpadWithRevision(Kernel::HLERequestContext& ctx) {
void Hid::SetNpadJoyHoldType(Kernel::HLERequestContext& ctx) { void Hid::SetNpadJoyHoldType(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx}; IPC::RequestParser rp{ctx};
const auto applet_resource_user_id{rp.Pop<u64>()}; const auto applet_resource_user_id{rp.Pop<u64>()};
const auto hold_type{rp.PopEnum<Controller_NPad::NpadHoldType>()}; const auto hold_type{rp.PopEnum<Controller_NPad::NpadJoyHoldType>()};
applet_resource->GetController<Controller_NPad>(HidController::NPad).SetHoldType(hold_type); applet_resource->GetController<Controller_NPad>(HidController::NPad).SetHoldType(hold_type);
@ -916,15 +959,16 @@ void Hid::GetNpadJoyHoldType(Kernel::HLERequestContext& ctx) {
void Hid::SetNpadJoyAssignmentModeSingleByDefault(Kernel::HLERequestContext& ctx) { void Hid::SetNpadJoyAssignmentModeSingleByDefault(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx}; IPC::RequestParser rp{ctx};
struct Parameters { struct Parameters {
u32 npad_id; Core::HID::NpadIdType npad_id;
INSERT_PADDING_WORDS_NOINIT(1); INSERT_PADDING_WORDS_NOINIT(1);
u64 applet_resource_user_id; u64 applet_resource_user_id;
}; };
static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
const auto parameters{rp.PopRaw<Parameters>()}; const auto parameters{rp.PopRaw<Parameters>()};
applet_resource->GetController<Controller_NPad>(HidController::NPad) applet_resource->GetController<Controller_NPad>(HidController::NPad)
.SetNpadMode(parameters.npad_id, Controller_NPad::NpadAssignments::Single); .SetNpadMode(parameters.npad_id, Controller_NPad::NpadJoyAssignmentMode::Single);
LOG_WARNING(Service_HID, "(STUBBED) called, npad_id={}, applet_resource_user_id={}", LOG_WARNING(Service_HID, "(STUBBED) called, npad_id={}, applet_resource_user_id={}",
parameters.npad_id, parameters.applet_resource_user_id); parameters.npad_id, parameters.applet_resource_user_id);
@ -937,16 +981,17 @@ void Hid::SetNpadJoyAssignmentModeSingle(Kernel::HLERequestContext& ctx) {
// TODO: Check the differences between this and SetNpadJoyAssignmentModeSingleByDefault // TODO: Check the differences between this and SetNpadJoyAssignmentModeSingleByDefault
IPC::RequestParser rp{ctx}; IPC::RequestParser rp{ctx};
struct Parameters { struct Parameters {
u32 npad_id; Core::HID::NpadIdType npad_id;
INSERT_PADDING_WORDS_NOINIT(1); INSERT_PADDING_WORDS_NOINIT(1);
u64 applet_resource_user_id; u64 applet_resource_user_id;
u64 npad_joy_device_type; u64 npad_joy_device_type;
}; };
static_assert(sizeof(Parameters) == 0x18, "Parameters has incorrect size.");
const auto parameters{rp.PopRaw<Parameters>()}; const auto parameters{rp.PopRaw<Parameters>()};
applet_resource->GetController<Controller_NPad>(HidController::NPad) applet_resource->GetController<Controller_NPad>(HidController::NPad)
.SetNpadMode(parameters.npad_id, Controller_NPad::NpadAssignments::Single); .SetNpadMode(parameters.npad_id, Controller_NPad::NpadJoyAssignmentMode::Single);
LOG_WARNING(Service_HID, LOG_WARNING(Service_HID,
"(STUBBED) called, npad_id={}, applet_resource_user_id={}, npad_joy_device_type={}", "(STUBBED) called, npad_id={}, applet_resource_user_id={}, npad_joy_device_type={}",
@ -960,15 +1005,16 @@ void Hid::SetNpadJoyAssignmentModeSingle(Kernel::HLERequestContext& ctx) {
void Hid::SetNpadJoyAssignmentModeDual(Kernel::HLERequestContext& ctx) { void Hid::SetNpadJoyAssignmentModeDual(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx}; IPC::RequestParser rp{ctx};
struct Parameters { struct Parameters {
u32 npad_id; Core::HID::NpadIdType npad_id;
INSERT_PADDING_WORDS_NOINIT(1); INSERT_PADDING_WORDS_NOINIT(1);
u64 applet_resource_user_id; u64 applet_resource_user_id;
}; };
static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
const auto parameters{rp.PopRaw<Parameters>()}; const auto parameters{rp.PopRaw<Parameters>()};
applet_resource->GetController<Controller_NPad>(HidController::NPad) applet_resource->GetController<Controller_NPad>(HidController::NPad)
.SetNpadMode(parameters.npad_id, Controller_NPad::NpadAssignments::Dual); .SetNpadMode(parameters.npad_id, Controller_NPad::NpadJoyAssignmentMode::Dual);
LOG_WARNING(Service_HID, "(STUBBED) called, npad_id={}, applet_resource_user_id={}", LOG_WARNING(Service_HID, "(STUBBED) called, npad_id={}, applet_resource_user_id={}",
parameters.npad_id, parameters.applet_resource_user_id); parameters.npad_id, parameters.applet_resource_user_id);
@ -979,8 +1025,8 @@ void Hid::SetNpadJoyAssignmentModeDual(Kernel::HLERequestContext& ctx) {
void Hid::MergeSingleJoyAsDualJoy(Kernel::HLERequestContext& ctx) { void Hid::MergeSingleJoyAsDualJoy(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx}; IPC::RequestParser rp{ctx};
const auto npad_id_1{rp.Pop<u32>()}; const auto npad_id_1{rp.PopEnum<Core::HID::NpadIdType>()};
const auto npad_id_2{rp.Pop<u32>()}; const auto npad_id_2{rp.PopEnum<Core::HID::NpadIdType>()};
const auto applet_resource_user_id{rp.Pop<u64>()}; const auto applet_resource_user_id{rp.Pop<u64>()};
applet_resource->GetController<Controller_NPad>(HidController::NPad) applet_resource->GetController<Controller_NPad>(HidController::NPad)
@ -1046,8 +1092,8 @@ void Hid::GetNpadHandheldActivationMode(Kernel::HLERequestContext& ctx) {
void Hid::SwapNpadAssignment(Kernel::HLERequestContext& ctx) { void Hid::SwapNpadAssignment(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx}; IPC::RequestParser rp{ctx};
const auto npad_id_1{rp.Pop<u32>()}; const auto npad_id_1{rp.PopEnum<Core::HID::NpadIdType>()};
const auto npad_id_2{rp.Pop<u32>()}; const auto npad_id_2{rp.PopEnum<Core::HID::NpadIdType>()};
const auto applet_resource_user_id{rp.Pop<u64>()}; const auto applet_resource_user_id{rp.Pop<u64>()};
const bool res = applet_resource->GetController<Controller_NPad>(HidController::NPad) const bool res = applet_resource->GetController<Controller_NPad>(HidController::NPad)
@ -1068,10 +1114,11 @@ void Hid::SwapNpadAssignment(Kernel::HLERequestContext& ctx) {
void Hid::IsUnintendedHomeButtonInputProtectionEnabled(Kernel::HLERequestContext& ctx) { void Hid::IsUnintendedHomeButtonInputProtectionEnabled(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx}; IPC::RequestParser rp{ctx};
struct Parameters { struct Parameters {
u32 npad_id; Core::HID::NpadIdType npad_id;
INSERT_PADDING_WORDS_NOINIT(1); INSERT_PADDING_WORDS_NOINIT(1);
u64 applet_resource_user_id; u64 applet_resource_user_id;
}; };
static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
const auto parameters{rp.PopRaw<Parameters>()}; const auto parameters{rp.PopRaw<Parameters>()};
@ -1089,9 +1136,10 @@ void Hid::EnableUnintendedHomeButtonInputProtection(Kernel::HLERequestContext& c
struct Parameters { struct Parameters {
bool unintended_home_button_input_protection; bool unintended_home_button_input_protection;
INSERT_PADDING_BYTES_NOINIT(3); INSERT_PADDING_BYTES_NOINIT(3);
u32 npad_id; Core::HID::NpadIdType npad_id;
u64 applet_resource_user_id; u64 applet_resource_user_id;
}; };
static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
const auto parameters{rp.PopRaw<Parameters>()}; const auto parameters{rp.PopRaw<Parameters>()};
@ -1113,6 +1161,7 @@ void Hid::SetNpadAnalogStickUseCenterClamp(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx}; IPC::RequestParser rp{ctx};
struct Parameters { struct Parameters {
bool analog_stick_use_center_clamp; bool analog_stick_use_center_clamp;
INSERT_PADDING_BYTES_NOINIT(7);
u64 applet_resource_user_id; u64 applet_resource_user_id;
}; };
static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size."); static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
@ -1132,38 +1181,38 @@ void Hid::SetNpadAnalogStickUseCenterClamp(Kernel::HLERequestContext& ctx) {
void Hid::GetVibrationDeviceInfo(Kernel::HLERequestContext& ctx) { void Hid::GetVibrationDeviceInfo(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx}; IPC::RequestParser rp{ctx};
const auto vibration_device_handle{rp.PopRaw<Controller_NPad::DeviceHandle>()}; const auto vibration_device_handle{rp.PopRaw<Core::HID::VibrationDeviceHandle>()};
VibrationDeviceInfo vibration_device_info; Core::HID::VibrationDeviceInfo vibration_device_info;
switch (vibration_device_handle.npad_type) { switch (vibration_device_handle.npad_type) {
case Controller_NPad::NpadType::ProController: case Core::HID::NpadStyleIndex::ProController:
case Controller_NPad::NpadType::Handheld: case Core::HID::NpadStyleIndex::Handheld:
case Controller_NPad::NpadType::JoyconDual: case Core::HID::NpadStyleIndex::JoyconDual:
case Controller_NPad::NpadType::JoyconLeft: case Core::HID::NpadStyleIndex::JoyconLeft:
case Controller_NPad::NpadType::JoyconRight: case Core::HID::NpadStyleIndex::JoyconRight:
default: default:
vibration_device_info.type = VibrationDeviceType::LinearResonantActuator; vibration_device_info.type = Core::HID::VibrationDeviceType::LinearResonantActuator;
break; break;
case Controller_NPad::NpadType::GameCube: case Core::HID::NpadStyleIndex::GameCube:
vibration_device_info.type = VibrationDeviceType::GcErm; vibration_device_info.type = Core::HID::VibrationDeviceType::GcErm;
break; break;
case Controller_NPad::NpadType::Pokeball: case Core::HID::NpadStyleIndex::Pokeball:
vibration_device_info.type = VibrationDeviceType::Unknown; vibration_device_info.type = Core::HID::VibrationDeviceType::Unknown;
break; break;
} }
switch (vibration_device_handle.device_index) { switch (vibration_device_handle.device_index) {
case Controller_NPad::DeviceIndex::Left: case Core::HID::DeviceIndex::Left:
vibration_device_info.position = VibrationDevicePosition::Left; vibration_device_info.position = Core::HID::VibrationDevicePosition::Left;
break; break;
case Controller_NPad::DeviceIndex::Right: case Core::HID::DeviceIndex::Right:
vibration_device_info.position = VibrationDevicePosition::Right; vibration_device_info.position = Core::HID::VibrationDevicePosition::Right;
break; break;
case Controller_NPad::DeviceIndex::None: case Core::HID::DeviceIndex::None:
default: default:
UNREACHABLE_MSG("DeviceIndex should never be None!"); UNREACHABLE_MSG("DeviceIndex should never be None!");
vibration_device_info.position = VibrationDevicePosition::None; vibration_device_info.position = Core::HID::VibrationDevicePosition::None;
break; break;
} }
@ -1178,11 +1227,12 @@ void Hid::GetVibrationDeviceInfo(Kernel::HLERequestContext& ctx) {
void Hid::SendVibrationValue(Kernel::HLERequestContext& ctx) { void Hid::SendVibrationValue(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx}; IPC::RequestParser rp{ctx};
struct Parameters { struct Parameters {
Controller_NPad::DeviceHandle vibration_device_handle; Core::HID::VibrationDeviceHandle vibration_device_handle;
Controller_NPad::VibrationValue vibration_value; Core::HID::VibrationValue vibration_value;
INSERT_PADDING_WORDS_NOINIT(1); INSERT_PADDING_WORDS_NOINIT(1);
u64 applet_resource_user_id; u64 applet_resource_user_id;
}; };
static_assert(sizeof(Parameters) == 0x20, "Parameters has incorrect size.");
const auto parameters{rp.PopRaw<Parameters>()}; const auto parameters{rp.PopRaw<Parameters>()};
@ -1202,10 +1252,11 @@ void Hid::SendVibrationValue(Kernel::HLERequestContext& ctx) {
void Hid::GetActualVibrationValue(Kernel::HLERequestContext& ctx) { void Hid::GetActualVibrationValue(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx}; IPC::RequestParser rp{ctx};
struct Parameters { struct Parameters {
Controller_NPad::DeviceHandle vibration_device_handle; Core::HID::VibrationDeviceHandle vibration_device_handle;
INSERT_PADDING_WORDS_NOINIT(1); INSERT_PADDING_WORDS_NOINIT(1);
u64 applet_resource_user_id; u64 applet_resource_user_id;
}; };
static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
const auto parameters{rp.PopRaw<Parameters>()}; const auto parameters{rp.PopRaw<Parameters>()};
@ -1256,10 +1307,10 @@ void Hid::SendVibrationValues(Kernel::HLERequestContext& ctx) {
const auto handles = ctx.ReadBuffer(0); const auto handles = ctx.ReadBuffer(0);
const auto vibrations = ctx.ReadBuffer(1); const auto vibrations = ctx.ReadBuffer(1);
std::vector<Controller_NPad::DeviceHandle> vibration_device_handles( std::vector<Core::HID::VibrationDeviceHandle> vibration_device_handles(
handles.size() / sizeof(Controller_NPad::DeviceHandle)); handles.size() / sizeof(Core::HID::VibrationDeviceHandle));
std::vector<Controller_NPad::VibrationValue> vibration_values( std::vector<Core::HID::VibrationValue> vibration_values(vibrations.size() /
vibrations.size() / sizeof(Controller_NPad::VibrationValue)); sizeof(Core::HID::VibrationValue));
std::memcpy(vibration_device_handles.data(), handles.data(), handles.size()); std::memcpy(vibration_device_handles.data(), handles.data(), handles.size());
std::memcpy(vibration_values.data(), vibrations.data(), vibrations.size()); std::memcpy(vibration_values.data(), vibrations.data(), vibrations.size());
@ -1276,9 +1327,10 @@ void Hid::SendVibrationValues(Kernel::HLERequestContext& ctx) {
void Hid::SendVibrationGcErmCommand(Kernel::HLERequestContext& ctx) { void Hid::SendVibrationGcErmCommand(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx}; IPC::RequestParser rp{ctx};
struct Parameters { struct Parameters {
Controller_NPad::DeviceHandle vibration_device_handle; Core::HID::VibrationDeviceHandle vibration_device_handle;
INSERT_PADDING_WORDS_NOINIT(1);
u64 applet_resource_user_id; u64 applet_resource_user_id;
VibrationGcErmCommand gc_erm_command; Core::HID::VibrationGcErmCommand gc_erm_command;
}; };
static_assert(sizeof(Parameters) == 0x18, "Parameters has incorrect size."); static_assert(sizeof(Parameters) == 0x18, "Parameters has incorrect size.");
@ -1292,26 +1344,26 @@ void Hid::SendVibrationGcErmCommand(Kernel::HLERequestContext& ctx) {
*/ */
const auto vibration_value = [parameters] { const auto vibration_value = [parameters] {
switch (parameters.gc_erm_command) { switch (parameters.gc_erm_command) {
case VibrationGcErmCommand::Stop: case Core::HID::VibrationGcErmCommand::Stop:
return Controller_NPad::VibrationValue{ return Core::HID::VibrationValue{
.amp_low = 0.0f, .low_amplitude = 0.0f,
.freq_low = 160.0f, .low_frequency = 160.0f,
.amp_high = 0.0f, .high_amplitude = 0.0f,
.freq_high = 320.0f, .high_frequency = 320.0f,
}; };
case VibrationGcErmCommand::Start: case Core::HID::VibrationGcErmCommand::Start:
return Controller_NPad::VibrationValue{ return Core::HID::VibrationValue{
.amp_low = 1.0f, .low_amplitude = 1.0f,
.freq_low = 160.0f, .low_frequency = 160.0f,
.amp_high = 1.0f, .high_amplitude = 1.0f,
.freq_high = 320.0f, .high_frequency = 320.0f,
}; };
case VibrationGcErmCommand::StopHard: case Core::HID::VibrationGcErmCommand::StopHard:
return Controller_NPad::VibrationValue{ return Core::HID::VibrationValue{
.amp_low = 0.0f, .low_amplitude = 0.0f,
.freq_low = 0.0f, .low_frequency = 0.0f,
.amp_high = 0.0f, .high_amplitude = 0.0f,
.freq_high = 0.0f, .high_frequency = 0.0f,
}; };
default: default:
return Controller_NPad::DEFAULT_VIBRATION_VALUE; return Controller_NPad::DEFAULT_VIBRATION_VALUE;
@ -1336,7 +1388,7 @@ void Hid::SendVibrationGcErmCommand(Kernel::HLERequestContext& ctx) {
void Hid::GetActualVibrationGcErmCommand(Kernel::HLERequestContext& ctx) { void Hid::GetActualVibrationGcErmCommand(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx}; IPC::RequestParser rp{ctx};
struct Parameters { struct Parameters {
Controller_NPad::DeviceHandle vibration_device_handle; Core::HID::VibrationDeviceHandle vibration_device_handle;
INSERT_PADDING_WORDS_NOINIT(1); INSERT_PADDING_WORDS_NOINIT(1);
u64 applet_resource_user_id; u64 applet_resource_user_id;
}; };
@ -1347,8 +1399,8 @@ void Hid::GetActualVibrationGcErmCommand(Kernel::HLERequestContext& ctx) {
.GetLastVibration(parameters.vibration_device_handle); .GetLastVibration(parameters.vibration_device_handle);
const auto gc_erm_command = [last_vibration] { const auto gc_erm_command = [last_vibration] {
if (last_vibration.amp_low != 0.0f || last_vibration.amp_high != 0.0f) { if (last_vibration.low_amplitude != 0.0f || last_vibration.high_amplitude != 0.0f) {
return VibrationGcErmCommand::Start; return Core::HID::VibrationGcErmCommand::Start;
} }
/** /**
@ -1357,11 +1409,11 @@ void Hid::GetActualVibrationGcErmCommand(Kernel::HLERequestContext& ctx) {
* SendVibrationGcErmCommand, in order to differentiate between Stop and StopHard commands. * SendVibrationGcErmCommand, in order to differentiate between Stop and StopHard commands.
* This is done to reuse the controller vibration functions made for regular controllers. * This is done to reuse the controller vibration functions made for regular controllers.
*/ */
if (last_vibration.freq_low == 0.0f && last_vibration.freq_high == 0.0f) { if (last_vibration.low_frequency == 0.0f && last_vibration.high_frequency == 0.0f) {
return VibrationGcErmCommand::StopHard; return Core::HID::VibrationGcErmCommand::StopHard;
} }
return VibrationGcErmCommand::Stop; return Core::HID::VibrationGcErmCommand::Stop;
}(); }();
LOG_DEBUG(Service_HID, LOG_DEBUG(Service_HID,
@ -1401,10 +1453,11 @@ void Hid::EndPermitVibrationSession(Kernel::HLERequestContext& ctx) {
void Hid::IsVibrationDeviceMounted(Kernel::HLERequestContext& ctx) { void Hid::IsVibrationDeviceMounted(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx}; IPC::RequestParser rp{ctx};
struct Parameters { struct Parameters {
Controller_NPad::DeviceHandle vibration_device_handle; Core::HID::VibrationDeviceHandle vibration_device_handle;
INSERT_PADDING_WORDS_NOINIT(1); INSERT_PADDING_WORDS_NOINIT(1);
u64 applet_resource_user_id; u64 applet_resource_user_id;
}; };
static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
const auto parameters{rp.PopRaw<Parameters>()}; const auto parameters{rp.PopRaw<Parameters>()};
@ -1435,18 +1488,18 @@ void Hid::ActivateConsoleSixAxisSensor(Kernel::HLERequestContext& ctx) {
void Hid::StartConsoleSixAxisSensor(Kernel::HLERequestContext& ctx) { void Hid::StartConsoleSixAxisSensor(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx}; IPC::RequestParser rp{ctx};
struct Parameters { struct Parameters {
Controller_NPad::DeviceHandle sixaxis_handle; Core::HID::ConsoleSixAxisSensorHandle console_sixaxis_handle;
INSERT_PADDING_WORDS_NOINIT(1); INSERT_PADDING_WORDS_NOINIT(1);
u64 applet_resource_user_id; u64 applet_resource_user_id;
}; };
static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
const auto parameters{rp.PopRaw<Parameters>()}; const auto parameters{rp.PopRaw<Parameters>()};
LOG_WARNING( LOG_WARNING(Service_HID,
Service_HID, "(STUBBED) called, unknown_1={}, unknown_2={}, applet_resource_user_id={}",
"(STUBBED) called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}", parameters.console_sixaxis_handle.unknown_1,
parameters.sixaxis_handle.npad_type, parameters.sixaxis_handle.npad_id, parameters.console_sixaxis_handle.unknown_2, parameters.applet_resource_user_id);
parameters.sixaxis_handle.device_index, parameters.applet_resource_user_id);
IPC::ResponseBuilder rb{ctx, 2}; IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess); rb.Push(ResultSuccess);
@ -1455,18 +1508,18 @@ void Hid::StartConsoleSixAxisSensor(Kernel::HLERequestContext& ctx) {
void Hid::StopConsoleSixAxisSensor(Kernel::HLERequestContext& ctx) { void Hid::StopConsoleSixAxisSensor(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx}; IPC::RequestParser rp{ctx};
struct Parameters { struct Parameters {
Controller_NPad::DeviceHandle sixaxis_handle; Core::HID::ConsoleSixAxisSensorHandle console_sixaxis_handle;
INSERT_PADDING_WORDS_NOINIT(1); INSERT_PADDING_WORDS_NOINIT(1);
u64 applet_resource_user_id; u64 applet_resource_user_id;
}; };
static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
const auto parameters{rp.PopRaw<Parameters>()}; const auto parameters{rp.PopRaw<Parameters>()};
LOG_WARNING( LOG_WARNING(Service_HID,
Service_HID, "(STUBBED) called, unknown_1={}, unknown_2={}, applet_resource_user_id={}",
"(STUBBED) called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}", parameters.console_sixaxis_handle.unknown_1,
parameters.sixaxis_handle.npad_type, parameters.sixaxis_handle.npad_id, parameters.console_sixaxis_handle.unknown_2, parameters.applet_resource_user_id);
parameters.sixaxis_handle.device_index, parameters.applet_resource_user_id);
IPC::ResponseBuilder rb{ctx, 2}; IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess); rb.Push(ResultSuccess);
@ -1620,10 +1673,8 @@ void Hid::SetNpadCommunicationMode(Kernel::HLERequestContext& ctx) {
void Hid::GetNpadCommunicationMode(Kernel::HLERequestContext& ctx) { void Hid::GetNpadCommunicationMode(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx}; IPC::RequestParser rp{ctx};
const auto applet_resource_user_id{rp.Pop<u64>()};
LOG_WARNING(Service_HID, "(STUBBED) called, applet_resource_user_id={}", LOG_WARNING(Service_HID, "(STUBBED) called");
applet_resource_user_id);
IPC::ResponseBuilder rb{ctx, 4}; IPC::ResponseBuilder rb{ctx, 4};
rb.Push(ResultSuccess); rb.Push(ResultSuccess);
@ -2037,10 +2088,6 @@ public:
} }
}; };
void ReloadInputDevices() {
Settings::values.is_device_reload_pending.store(true);
}
void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system) { void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system) {
std::make_shared<Hid>(system)->InstallAsService(service_manager); std::make_shared<Hid>(system)->InstallAsService(service_manager);
std::make_shared<HidBus>(system)->InstallAsService(service_manager); std::make_shared<HidBus>(system)->InstallAsService(service_manager);

View file

@ -60,21 +60,23 @@ public:
private: private:
template <typename T> template <typename T>
void MakeController(HidController controller) { void MakeController(HidController controller) {
controllers[static_cast<std::size_t>(controller)] = std::make_unique<T>(system); controllers[static_cast<std::size_t>(controller)] = std::make_unique<T>(system.HIDCore());
} }
template <typename T> template <typename T>
void MakeControllerWithServiceContext(HidController controller) { void MakeControllerWithServiceContext(HidController controller) {
controllers[static_cast<std::size_t>(controller)] = controllers[static_cast<std::size_t>(controller)] =
std::make_unique<T>(system, service_context); std::make_unique<T>(system.HIDCore(), service_context);
} }
void GetSharedMemoryHandle(Kernel::HLERequestContext& ctx); void GetSharedMemoryHandle(Kernel::HLERequestContext& ctx);
void UpdateControllers(std::uintptr_t user_data, std::chrono::nanoseconds ns_late); void UpdateControllers(std::uintptr_t user_data, std::chrono::nanoseconds ns_late);
void UpdateKeyboard(std::uintptr_t user_data, std::chrono::nanoseconds ns_late);
void UpdateMotion(std::uintptr_t user_data, std::chrono::nanoseconds ns_late); void UpdateMotion(std::uintptr_t user_data, std::chrono::nanoseconds ns_late);
KernelHelpers::ServiceContext& service_context; KernelHelpers::ServiceContext& service_context;
std::shared_ptr<Core::Timing::EventType> pad_update_event; std::shared_ptr<Core::Timing::EventType> pad_update_event;
std::shared_ptr<Core::Timing::EventType> keyboard_update_event;
std::shared_ptr<Core::Timing::EventType> motion_update_event; std::shared_ptr<Core::Timing::EventType> motion_update_event;
std::array<std::unique_ptr<ControllerBase>, static_cast<size_t>(HidController::MaxControllers)> std::array<std::unique_ptr<ControllerBase>, static_cast<size_t>(HidController::MaxControllers)>
@ -161,38 +163,11 @@ private:
void GetNpadCommunicationMode(Kernel::HLERequestContext& ctx); void GetNpadCommunicationMode(Kernel::HLERequestContext& ctx);
void SetTouchScreenConfiguration(Kernel::HLERequestContext& ctx); void SetTouchScreenConfiguration(Kernel::HLERequestContext& ctx);
enum class VibrationDeviceType : u32 {
Unknown = 0,
LinearResonantActuator = 1,
GcErm = 2,
};
enum class VibrationDevicePosition : u32 {
None = 0,
Left = 1,
Right = 2,
};
enum class VibrationGcErmCommand : u64 {
Stop = 0,
Start = 1,
StopHard = 2,
};
struct VibrationDeviceInfo {
VibrationDeviceType type{};
VibrationDevicePosition position{};
};
static_assert(sizeof(VibrationDeviceInfo) == 0x8, "VibrationDeviceInfo has incorrect size.");
std::shared_ptr<IAppletResource> applet_resource; std::shared_ptr<IAppletResource> applet_resource;
KernelHelpers::ServiceContext service_context; KernelHelpers::ServiceContext service_context;
}; };
/// Reload input devices. Used when input configuration changed
void ReloadInputDevices();
/// Registers all HID services with the specified service manager. /// Registers all HID services with the specified service manager.
void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system); void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system);

View file

@ -1,36 +1,32 @@
add_library(input_common STATIC add_library(input_common STATIC
analog_from_button.cpp drivers/gc_adapter.cpp
analog_from_button.h drivers/gc_adapter.h
keyboard.cpp drivers/keyboard.cpp
keyboard.h drivers/keyboard.h
drivers/mouse.cpp
drivers/mouse.h
drivers/sdl_driver.cpp
drivers/sdl_driver.h
drivers/tas_input.cpp
drivers/tas_input.h
drivers/touch_screen.cpp
drivers/touch_screen.h
drivers/udp_client.cpp
drivers/udp_client.h
helpers/stick_from_buttons.cpp
helpers/stick_from_buttons.h
helpers/touch_from_buttons.cpp
helpers/touch_from_buttons.h
helpers/udp_protocol.cpp
helpers/udp_protocol.h
input_engine.cpp
input_engine.h
input_mapping.cpp
input_mapping.h
input_poller.cpp
input_poller.h
main.cpp main.cpp
main.h main.h
motion_from_button.cpp
motion_from_button.h
motion_input.cpp
motion_input.h
touch_from_button.cpp
touch_from_button.h
gcadapter/gc_adapter.cpp
gcadapter/gc_adapter.h
gcadapter/gc_poller.cpp
gcadapter/gc_poller.h
mouse/mouse_input.cpp
mouse/mouse_input.h
mouse/mouse_poller.cpp
mouse/mouse_poller.h
sdl/sdl.cpp
sdl/sdl.h
tas/tas_input.cpp
tas/tas_input.h
tas/tas_poller.cpp
tas/tas_poller.h
udp/client.cpp
udp/client.h
udp/protocol.cpp
udp/protocol.h
udp/udp.cpp
udp/udp.h
) )
if (MSVC) if (MSVC)
@ -57,8 +53,8 @@ endif()
if (ENABLE_SDL2) if (ENABLE_SDL2)
target_sources(input_common PRIVATE target_sources(input_common PRIVATE
sdl/sdl_impl.cpp drivers/sdl_driver.cpp
sdl/sdl_impl.h drivers/sdl_driver.h
) )
target_link_libraries(input_common PRIVATE SDL2) target_link_libraries(input_common PRIVATE SDL2)
target_compile_definitions(input_common PRIVATE HAVE_SDL2) target_compile_definitions(input_common PRIVATE HAVE_SDL2)

View file

@ -13,15 +13,26 @@ constexpr PadIdentifier key_identifier = {
.port = 0, .port = 0,
.pad = 0, .pad = 0,
}; };
constexpr PadIdentifier modifier_identifier = { constexpr PadIdentifier keyboard_key_identifier = {
.guid = Common::UUID{Common::INVALID_UUID}, .guid = Common::UUID{Common::INVALID_UUID},
.port = 0, .port = 1,
.pad = 0,
};
constexpr PadIdentifier keyboard_modifier_identifier = {
.guid = Common::UUID{Common::INVALID_UUID},
.port = 1,
.pad = 1, .pad = 1,
}; };
Keyboard::Keyboard(const std::string& input_engine_) : InputEngine(input_engine_) { Keyboard::Keyboard(const std::string& input_engine_) : InputEngine(input_engine_) {
// Keyboard is broken into 3 diferent sets:
// key: Unfiltered intended for controllers.
// keyboard_key: Allows only Settings::NativeKeyboard::Keys intended for keyboard emulation.
// keyboard_modifier: Allows only Settings::NativeKeyboard::Modifiers intended for keyboard
// emulation.
PreSetController(key_identifier); PreSetController(key_identifier);
PreSetController(modifier_identifier); PreSetController(keyboard_key_identifier);
PreSetController(keyboard_modifier_identifier);
} }
void Keyboard::PressKey(int key_code) { void Keyboard::PressKey(int key_code) {
@ -32,35 +43,50 @@ void Keyboard::ReleaseKey(int key_code) {
SetButton(key_identifier, key_code, false); SetButton(key_identifier, key_code, false);
} }
void Keyboard::SetModifiers(int key_modifiers) { void Keyboard::PressKeyboardKey(int key_index) {
if (key_index == Settings::NativeKeyboard::None) {
return;
}
SetButton(keyboard_key_identifier, key_index, true);
}
void Keyboard::ReleaseKeyboardKey(int key_index) {
if (key_index == Settings::NativeKeyboard::None) {
return;
}
SetButton(keyboard_key_identifier, key_index, false);
}
void Keyboard::SetKeyboardModifiers(int key_modifiers) {
for (int i = 0; i < 32; ++i) { for (int i = 0; i < 32; ++i) {
bool key_value = ((key_modifiers >> i) & 0x1) != 0; bool key_value = ((key_modifiers >> i) & 0x1) != 0;
SetButton(modifier_identifier, i, key_value); SetButton(keyboard_modifier_identifier, i, key_value);
// Use the modifier to press the key button equivalent // Use the modifier to press the key button equivalent
switch (i) { switch (i) {
case Settings::NativeKeyboard::LeftControl: case Settings::NativeKeyboard::LeftControl:
SetButton(key_identifier, Settings::NativeKeyboard::LeftControlKey, key_value); SetButton(keyboard_key_identifier, Settings::NativeKeyboard::LeftControlKey, key_value);
break; break;
case Settings::NativeKeyboard::LeftShift: case Settings::NativeKeyboard::LeftShift:
SetButton(key_identifier, Settings::NativeKeyboard::LeftShiftKey, key_value); SetButton(keyboard_key_identifier, Settings::NativeKeyboard::LeftShiftKey, key_value);
break; break;
case Settings::NativeKeyboard::LeftAlt: case Settings::NativeKeyboard::LeftAlt:
SetButton(key_identifier, Settings::NativeKeyboard::LeftAltKey, key_value); SetButton(keyboard_key_identifier, Settings::NativeKeyboard::LeftAltKey, key_value);
break; break;
case Settings::NativeKeyboard::LeftMeta: case Settings::NativeKeyboard::LeftMeta:
SetButton(key_identifier, Settings::NativeKeyboard::LeftMetaKey, key_value); SetButton(keyboard_key_identifier, Settings::NativeKeyboard::LeftMetaKey, key_value);
break; break;
case Settings::NativeKeyboard::RightControl: case Settings::NativeKeyboard::RightControl:
SetButton(key_identifier, Settings::NativeKeyboard::RightControlKey, key_value); SetButton(keyboard_key_identifier, Settings::NativeKeyboard::RightControlKey,
key_value);
break; break;
case Settings::NativeKeyboard::RightShift: case Settings::NativeKeyboard::RightShift:
SetButton(key_identifier, Settings::NativeKeyboard::RightShiftKey, key_value); SetButton(keyboard_key_identifier, Settings::NativeKeyboard::RightShiftKey, key_value);
break; break;
case Settings::NativeKeyboard::RightAlt: case Settings::NativeKeyboard::RightAlt:
SetButton(key_identifier, Settings::NativeKeyboard::RightAltKey, key_value); SetButton(keyboard_key_identifier, Settings::NativeKeyboard::RightAltKey, key_value);
break; break;
case Settings::NativeKeyboard::RightMeta: case Settings::NativeKeyboard::RightMeta:
SetButton(key_identifier, Settings::NativeKeyboard::RightMetaKey, key_value); SetButton(keyboard_key_identifier, Settings::NativeKeyboard::RightMetaKey, key_value);
break; break;
default: default:
// Other modifier keys should be pressed with PressKey since they stay enabled until // Other modifier keys should be pressed with PressKey since they stay enabled until

View file

@ -28,11 +28,23 @@ public:
*/ */
void ReleaseKey(int key_code); void ReleaseKey(int key_code);
/**
* Sets the status of the keyboard key to pressed
* @param key_index index of the key to press
*/
void PressKeyboardKey(int key_index);
/**
* Sets the status of the keyboard key to released
* @param key_index index of the key to release
*/
void ReleaseKeyboardKey(int key_index);
/** /**
* Sets the status of all keyboard modifier keys * Sets the status of all keyboard modifier keys
* @param key_modifiers the code of the key to release * @param key_modifiers the code of the key to release
*/ */
void SetModifiers(int key_modifiers); void SetKeyboardModifiers(int key_modifiers);
/// Sets all keys to the non pressed state /// Sets all keys to the non pressed state
void ReleaseAllKeys(); void ReleaseAllKeys();

View file

@ -12,6 +12,10 @@
#include "input_common/drivers/mouse.h" #include "input_common/drivers/mouse.h"
namespace InputCommon { namespace InputCommon {
constexpr int mouse_axis_x = 0;
constexpr int mouse_axis_y = 1;
constexpr int wheel_axis_x = 2;
constexpr int wheel_axis_y = 3;
constexpr int touch_axis_x = 10; constexpr int touch_axis_x = 10;
constexpr int touch_axis_y = 11; constexpr int touch_axis_y = 11;
constexpr PadIdentifier identifier = { constexpr PadIdentifier identifier = {
@ -34,14 +38,18 @@ void Mouse::UpdateThread(std::stop_token stop_token) {
last_mouse_change *= 0.96f; last_mouse_change *= 0.96f;
const float sensitivity = const float sensitivity =
Settings::values.mouse_panning_sensitivity.GetValue() * 0.022f; Settings::values.mouse_panning_sensitivity.GetValue() * 0.022f;
SetAxis(identifier, 0, last_mouse_change.x * sensitivity); SetAxis(identifier, mouse_axis_x, last_mouse_change.x * sensitivity);
SetAxis(identifier, 1, -last_mouse_change.y * sensitivity); SetAxis(identifier, mouse_axis_y, -last_mouse_change.y * sensitivity);
} }
if (mouse_panning_timout++ > 20) { if (mouse_panning_timout++ > 20) {
StopPanning(); StopPanning();
} }
std::this_thread::sleep_for(std::chrono::milliseconds(update_time)); std::this_thread::sleep_for(std::chrono::milliseconds(update_time));
// Reset wheel position
SetAxis(identifier, wheel_axis_x, 0);
SetAxis(identifier, wheel_axis_y, 0);
} }
} }
@ -89,8 +97,8 @@ void Mouse::MouseMove(int x, int y, f32 touch_x, f32 touch_y, int center_x, int
if (button_pressed) { if (button_pressed) {
const auto mouse_move = Common::MakeVec<int>(x, y) - mouse_origin; const auto mouse_move = Common::MakeVec<int>(x, y) - mouse_origin;
const float sensitivity = Settings::values.mouse_panning_sensitivity.GetValue() * 0.0012f; const float sensitivity = Settings::values.mouse_panning_sensitivity.GetValue() * 0.0012f;
SetAxis(identifier, 0, static_cast<float>(mouse_move.x) * sensitivity); SetAxis(identifier, mouse_axis_x, static_cast<float>(mouse_move.x) * sensitivity);
SetAxis(identifier, 1, static_cast<float>(-mouse_move.y) * sensitivity); SetAxis(identifier, mouse_axis_y, static_cast<float>(-mouse_move.y) * sensitivity);
} }
} }
@ -108,12 +116,17 @@ void Mouse::ReleaseButton(MouseButton button) {
SetButton(identifier, static_cast<int>(button), false); SetButton(identifier, static_cast<int>(button), false);
if (!Settings::values.mouse_panning) { if (!Settings::values.mouse_panning) {
SetAxis(identifier, 0, 0); SetAxis(identifier, mouse_axis_x, 0);
SetAxis(identifier, 1, 0); SetAxis(identifier, mouse_axis_y, 0);
} }
button_pressed = false; button_pressed = false;
} }
void Mouse::MouseWheelChange(int x, int y) {
SetAxis(identifier, wheel_axis_x, static_cast<f32>(x));
SetAxis(identifier, wheel_axis_y, static_cast<f32>(y));
}
void Mouse::ReleaseAllButtons() { void Mouse::ReleaseAllButtons() {
ResetButtonState(); ResetButtonState();
button_pressed = false; button_pressed = false;

View file

@ -52,6 +52,13 @@ public:
*/ */
void ReleaseButton(MouseButton button); void ReleaseButton(MouseButton button);
/**
* Sets the status of the mouse wheel
* @param x delta movement in the x direction
* @param y delta movement in the y direction
*/
void MouseWheelChange(int x, int y);
void ReleaseAllButtons(); void ReleaseAllButtons();
std::vector<Common::ParamPackage> GetInputDevices() const override; std::vector<Common::ParamPackage> GetInputDevices() const override;

View file

@ -28,6 +28,10 @@ void MappingFactory::RegisterInput(const MappingData& data) {
if (!is_enabled) { if (!is_enabled) {
return; return;
} }
if (!IsDriverValid(data)) {
return;
}
switch (input_type) { switch (input_type) {
case Polling::InputType::Button: case Polling::InputType::Button:
RegisterButton(data); RegisterButton(data);
@ -168,4 +172,25 @@ void MappingFactory::RegisterMotion(const MappingData& data) {
input_queue.Push(new_input); input_queue.Push(new_input);
} }
bool MappingFactory::IsDriverValid(const MappingData& data) const {
// Only port 0 can be mapped on the keyboard
if (data.engine == "keyboard" && data.pad.port != 0) {
return false;
}
// The following drivers don't need to be mapped
if (data.engine == "tas") {
return false;
}
if (data.engine == "touch") {
return false;
}
if (data.engine == "touch_from_button") {
return false;
}
if (data.engine == "analog_from_button") {
return false;
}
return true;
}
} // namespace InputCommon } // namespace InputCommon

View file

@ -66,6 +66,13 @@ private:
*/ */
void RegisterMotion(const MappingData& data); void RegisterMotion(const MappingData& data);
/**
* Returns true if driver can be mapped
* @param "data": An struct containing all the information needed to create a proper
* ParamPackage
*/
bool IsDriverValid(const MappingData& data) const;
Common::SPSCQueue<Common::ParamPackage> input_queue; Common::SPSCQueue<Common::ParamPackage> input_queue;
Polling::InputType input_type{Polling::InputType::None}; Polling::InputType input_type{Polling::InputType::None};
bool is_enabled{}; bool is_enabled{};

View file

@ -4,146 +4,164 @@
#include <memory> #include <memory>
#include <thread> #include <thread>
#include "common/input.h"
#include "common/param_package.h" #include "common/param_package.h"
#include "common/settings.h" #include "input_common/drivers/gc_adapter.h"
#include "input_common/analog_from_button.h" #include "input_common/drivers/keyboard.h"
#include "input_common/gcadapter/gc_adapter.h" #include "input_common/drivers/mouse.h"
#include "input_common/gcadapter/gc_poller.h" #include "input_common/drivers/tas_input.h"
#include "input_common/keyboard.h" #include "input_common/drivers/touch_screen.h"
#include "input_common/drivers/udp_client.h"
#include "input_common/helpers/stick_from_buttons.h"
#include "input_common/helpers/touch_from_buttons.h"
#include "input_common/input_engine.h"
#include "input_common/input_mapping.h"
#include "input_common/input_poller.h"
#include "input_common/main.h" #include "input_common/main.h"
#include "input_common/motion_from_button.h"
#include "input_common/mouse/mouse_input.h"
#include "input_common/mouse/mouse_poller.h"
#include "input_common/tas/tas_input.h"
#include "input_common/tas/tas_poller.h"
#include "input_common/touch_from_button.h"
#include "input_common/udp/client.h"
#include "input_common/udp/udp.h"
#ifdef HAVE_SDL2 #ifdef HAVE_SDL2
#include "input_common/sdl/sdl.h" #include "input_common/drivers/sdl_driver.h"
#endif #endif
namespace InputCommon { namespace InputCommon {
struct InputSubsystem::Impl { struct InputSubsystem::Impl {
void Initialize() { void Initialize() {
gcadapter = std::make_shared<GCAdapter::Adapter>(); mapping_factory = std::make_shared<MappingFactory>();
gcbuttons = std::make_shared<GCButtonFactory>(gcadapter); MappingCallback mapping_callback{[this](MappingData data) { RegisterInput(data); }};
Input::RegisterFactory<Input::ButtonDevice>("gcpad", gcbuttons);
gcanalog = std::make_shared<GCAnalogFactory>(gcadapter);
Input::RegisterFactory<Input::AnalogDevice>("gcpad", gcanalog);
gcvibration = std::make_shared<GCVibrationFactory>(gcadapter);
Input::RegisterFactory<Input::VibrationDevice>("gcpad", gcvibration);
keyboard = std::make_shared<Keyboard>(); keyboard = std::make_shared<Keyboard>("keyboard");
Input::RegisterFactory<Input::ButtonDevice>("keyboard", keyboard); keyboard->SetMappingCallback(mapping_callback);
Input::RegisterFactory<Input::AnalogDevice>("analog_from_button", keyboard_factory = std::make_shared<InputFactory>(keyboard);
std::make_shared<AnalogFromButton>()); keyboard_output_factory = std::make_shared<OutputFactory>(keyboard);
Input::RegisterFactory<Input::MotionDevice>("keyboard", Common::Input::RegisterFactory<Common::Input::InputDevice>(keyboard->GetEngineName(),
std::make_shared<MotionFromButton>()); keyboard_factory);
Input::RegisterFactory<Input::TouchDevice>("touch_from_button", Common::Input::RegisterFactory<Common::Input::OutputDevice>(keyboard->GetEngineName(),
std::make_shared<TouchFromButtonFactory>()); keyboard_output_factory);
mouse = std::make_shared<Mouse>("mouse");
mouse->SetMappingCallback(mapping_callback);
mouse_factory = std::make_shared<InputFactory>(mouse);
mouse_output_factory = std::make_shared<OutputFactory>(mouse);
Common::Input::RegisterFactory<Common::Input::InputDevice>(mouse->GetEngineName(),
mouse_factory);
Common::Input::RegisterFactory<Common::Input::OutputDevice>(mouse->GetEngineName(),
mouse_output_factory);
touch_screen = std::make_shared<TouchScreen>("touch");
touch_screen_factory = std::make_shared<InputFactory>(touch_screen);
Common::Input::RegisterFactory<Common::Input::InputDevice>(touch_screen->GetEngineName(),
touch_screen_factory);
gcadapter = std::make_shared<GCAdapter>("gcpad");
gcadapter->SetMappingCallback(mapping_callback);
gcadapter_input_factory = std::make_shared<InputFactory>(gcadapter);
gcadapter_output_factory = std::make_shared<OutputFactory>(gcadapter);
Common::Input::RegisterFactory<Common::Input::InputDevice>(gcadapter->GetEngineName(),
gcadapter_input_factory);
Common::Input::RegisterFactory<Common::Input::OutputDevice>(gcadapter->GetEngineName(),
gcadapter_output_factory);
udp_client = std::make_shared<CemuhookUDP::UDPClient>("cemuhookudp");
udp_client->SetMappingCallback(mapping_callback);
udp_client_factory = std::make_shared<InputFactory>(udp_client);
Common::Input::RegisterFactory<Common::Input::InputDevice>(udp_client->GetEngineName(),
udp_client_factory);
tas_input = std::make_shared<TasInput::Tas>("tas");
tas_input->SetMappingCallback(mapping_callback);
tas_input_factory = std::make_shared<InputFactory>(tas_input);
tas_output_factory = std::make_shared<OutputFactory>(tas_input);
Common::Input::RegisterFactory<Common::Input::InputDevice>(tas_input->GetEngineName(),
tas_input_factory);
Common::Input::RegisterFactory<Common::Input::OutputDevice>(tas_input->GetEngineName(),
tas_output_factory);
#ifdef HAVE_SDL2 #ifdef HAVE_SDL2
sdl = SDL::Init(); sdl = std::make_shared<SDLDriver>("sdl");
sdl->SetMappingCallback(mapping_callback);
sdl_input_factory = std::make_shared<InputFactory>(sdl);
sdl_output_factory = std::make_shared<OutputFactory>(sdl);
Common::Input::RegisterFactory<Common::Input::InputDevice>(sdl->GetEngineName(),
sdl_input_factory);
Common::Input::RegisterFactory<Common::Input::OutputDevice>(sdl->GetEngineName(),
sdl_output_factory);
#endif #endif
udp = std::make_shared<InputCommon::CemuhookUDP::Client>(); Common::Input::RegisterFactory<Common::Input::InputDevice>(
udpmotion = std::make_shared<UDPMotionFactory>(udp); "touch_from_button", std::make_shared<TouchFromButton>());
Input::RegisterFactory<Input::MotionDevice>("cemuhookudp", udpmotion); Common::Input::RegisterFactory<Common::Input::InputDevice>(
udptouch = std::make_shared<UDPTouchFactory>(udp); "analog_from_button", std::make_shared<StickFromButton>());
Input::RegisterFactory<Input::TouchDevice>("cemuhookudp", udptouch);
mouse = std::make_shared<MouseInput::Mouse>();
mousebuttons = std::make_shared<MouseButtonFactory>(mouse);
Input::RegisterFactory<Input::ButtonDevice>("mouse", mousebuttons);
mouseanalog = std::make_shared<MouseAnalogFactory>(mouse);
Input::RegisterFactory<Input::AnalogDevice>("mouse", mouseanalog);
mousemotion = std::make_shared<MouseMotionFactory>(mouse);
Input::RegisterFactory<Input::MotionDevice>("mouse", mousemotion);
mousetouch = std::make_shared<MouseTouchFactory>(mouse);
Input::RegisterFactory<Input::TouchDevice>("mouse", mousetouch);
tas = std::make_shared<TasInput::Tas>();
tasbuttons = std::make_shared<TasButtonFactory>(tas);
Input::RegisterFactory<Input::ButtonDevice>("tas", tasbuttons);
tasanalog = std::make_shared<TasAnalogFactory>(tas);
Input::RegisterFactory<Input::AnalogDevice>("tas", tasanalog);
} }
void Shutdown() { void Shutdown() {
Input::UnregisterFactory<Input::ButtonDevice>("keyboard"); Common::Input::UnregisterFactory<Common::Input::InputDevice>(keyboard->GetEngineName());
Input::UnregisterFactory<Input::MotionDevice>("keyboard"); Common::Input::UnregisterFactory<Common::Input::OutputDevice>(keyboard->GetEngineName());
keyboard.reset(); keyboard.reset();
Input::UnregisterFactory<Input::AnalogDevice>("analog_from_button");
Input::UnregisterFactory<Input::TouchDevice>("touch_from_button"); Common::Input::UnregisterFactory<Common::Input::InputDevice>(mouse->GetEngineName());
Common::Input::UnregisterFactory<Common::Input::OutputDevice>(mouse->GetEngineName());
mouse.reset();
Common::Input::UnregisterFactory<Common::Input::InputDevice>(touch_screen->GetEngineName());
touch_screen.reset();
Common::Input::UnregisterFactory<Common::Input::InputDevice>(gcadapter->GetEngineName());
Common::Input::UnregisterFactory<Common::Input::OutputDevice>(gcadapter->GetEngineName());
gcadapter.reset();
Common::Input::UnregisterFactory<Common::Input::InputDevice>(udp_client->GetEngineName());
udp_client.reset();
Common::Input::UnregisterFactory<Common::Input::InputDevice>(tas_input->GetEngineName());
Common::Input::UnregisterFactory<Common::Input::OutputDevice>(tas_input->GetEngineName());
tas_input.reset();
#ifdef HAVE_SDL2 #ifdef HAVE_SDL2
Common::Input::UnregisterFactory<Common::Input::InputDevice>(sdl->GetEngineName());
Common::Input::UnregisterFactory<Common::Input::OutputDevice>(sdl->GetEngineName());
sdl.reset(); sdl.reset();
#endif #endif
Input::UnregisterFactory<Input::ButtonDevice>("gcpad");
Input::UnregisterFactory<Input::AnalogDevice>("gcpad");
Input::UnregisterFactory<Input::VibrationDevice>("gcpad");
gcbuttons.reset(); Common::Input::UnregisterFactory<Common::Input::InputDevice>("touch_from_button");
gcanalog.reset(); Common::Input::UnregisterFactory<Common::Input::InputDevice>("analog_from_button");
gcvibration.reset();
Input::UnregisterFactory<Input::MotionDevice>("cemuhookudp");
Input::UnregisterFactory<Input::TouchDevice>("cemuhookudp");
udpmotion.reset();
udptouch.reset();
Input::UnregisterFactory<Input::ButtonDevice>("mouse");
Input::UnregisterFactory<Input::AnalogDevice>("mouse");
Input::UnregisterFactory<Input::MotionDevice>("mouse");
Input::UnregisterFactory<Input::TouchDevice>("mouse");
mousebuttons.reset();
mouseanalog.reset();
mousemotion.reset();
mousetouch.reset();
Input::UnregisterFactory<Input::ButtonDevice>("tas");
Input::UnregisterFactory<Input::AnalogDevice>("tas");
tasbuttons.reset();
tasanalog.reset();
} }
[[nodiscard]] std::vector<Common::ParamPackage> GetInputDevices() const { [[nodiscard]] std::vector<Common::ParamPackage> GetInputDevices() const {
std::vector<Common::ParamPackage> devices = { std::vector<Common::ParamPackage> devices = {
Common::ParamPackage{{"display", "Any"}, {"class", "any"}}, Common::ParamPackage{{"display", "Any"}, {"engine", "any"}},
Common::ParamPackage{{"display", "Keyboard/Mouse"}, {"class", "keyboard"}},
}; };
if (Settings::values.tas_enable) {
devices.emplace_back( auto keyboard_devices = keyboard->GetInputDevices();
Common::ParamPackage{{"display", "TAS Controller"}, {"class", "tas"}}); devices.insert(devices.end(), keyboard_devices.begin(), keyboard_devices.end());
} auto mouse_devices = mouse->GetInputDevices();
devices.insert(devices.end(), mouse_devices.begin(), mouse_devices.end());
auto gcadapter_devices = gcadapter->GetInputDevices();
devices.insert(devices.end(), gcadapter_devices.begin(), gcadapter_devices.end());
#ifdef HAVE_SDL2 #ifdef HAVE_SDL2
auto sdl_devices = sdl->GetInputDevices(); auto sdl_devices = sdl->GetInputDevices();
devices.insert(devices.end(), sdl_devices.begin(), sdl_devices.end()); devices.insert(devices.end(), sdl_devices.begin(), sdl_devices.end());
#endif #endif
auto udp_devices = udp->GetInputDevices();
devices.insert(devices.end(), udp_devices.begin(), udp_devices.end());
auto gcpad_devices = gcadapter->GetInputDevices();
devices.insert(devices.end(), gcpad_devices.begin(), gcpad_devices.end());
return devices; return devices;
} }
[[nodiscard]] AnalogMapping GetAnalogMappingForDevice( [[nodiscard]] AnalogMapping GetAnalogMappingForDevice(
const Common::ParamPackage& params) const { const Common::ParamPackage& params) const {
if (!params.Has("class") || params.Get("class", "") == "any") { if (!params.Has("engine") || params.Get("engine", "") == "any") {
return {}; return {};
} }
if (params.Get("class", "") == "gcpad") { const std::string engine = params.Get("engine", "");
if (engine == mouse->GetEngineName()) {
return mouse->GetAnalogMappingForDevice(params);
}
if (engine == gcadapter->GetEngineName()) {
return gcadapter->GetAnalogMappingForDevice(params); return gcadapter->GetAnalogMappingForDevice(params);
} }
if (params.Get("class", "") == "tas") { if (engine == tas_input->GetEngineName()) {
return tas->GetAnalogMappingForDevice(params); return tas_input->GetAnalogMappingForDevice(params);
} }
#ifdef HAVE_SDL2 #ifdef HAVE_SDL2
if (params.Get("class", "") == "sdl") { if (engine == sdl->GetEngineName()) {
return sdl->GetAnalogMappingForDevice(params); return sdl->GetAnalogMappingForDevice(params);
} }
#endif #endif
@ -152,17 +170,18 @@ struct InputSubsystem::Impl {
[[nodiscard]] ButtonMapping GetButtonMappingForDevice( [[nodiscard]] ButtonMapping GetButtonMappingForDevice(
const Common::ParamPackage& params) const { const Common::ParamPackage& params) const {
if (!params.Has("class") || params.Get("class", "") == "any") { if (!params.Has("engine") || params.Get("engine", "") == "any") {
return {}; return {};
} }
if (params.Get("class", "") == "gcpad") { const std::string engine = params.Get("engine", "");
if (engine == gcadapter->GetEngineName()) {
return gcadapter->GetButtonMappingForDevice(params); return gcadapter->GetButtonMappingForDevice(params);
} }
if (params.Get("class", "") == "tas") { if (engine == tas_input->GetEngineName()) {
return tas->GetButtonMappingForDevice(params); return tas_input->GetButtonMappingForDevice(params);
} }
#ifdef HAVE_SDL2 #ifdef HAVE_SDL2
if (params.Get("class", "") == "sdl") { if (engine == sdl->GetEngineName()) {
return sdl->GetButtonMappingForDevice(params); return sdl->GetButtonMappingForDevice(params);
} }
#endif #endif
@ -171,40 +190,115 @@ struct InputSubsystem::Impl {
[[nodiscard]] MotionMapping GetMotionMappingForDevice( [[nodiscard]] MotionMapping GetMotionMappingForDevice(
const Common::ParamPackage& params) const { const Common::ParamPackage& params) const {
if (!params.Has("class") || params.Get("class", "") == "any") { if (!params.Has("engine") || params.Get("engine", "") == "any") {
return {}; return {};
} }
if (params.Get("class", "") == "cemuhookudp") { const std::string engine = params.Get("engine", "");
// TODO return the correct motion device if (engine == gcadapter->GetEngineName()) {
return {}; return gcadapter->GetMotionMappingForDevice(params);
} }
#ifdef HAVE_SDL2 #ifdef HAVE_SDL2
if (params.Get("class", "") == "sdl") { if (engine == sdl->GetEngineName()) {
return sdl->GetMotionMappingForDevice(params); return sdl->GetMotionMappingForDevice(params);
} }
#endif #endif
return {}; return {};
} }
std::shared_ptr<Keyboard> keyboard; std::string GetButtonName(const Common::ParamPackage& params) const {
if (!params.Has("engine") || params.Get("engine", "") == "any") {
return "Unknown";
}
const std::string engine = params.Get("engine", "");
if (engine == mouse->GetEngineName()) {
return mouse->GetUIName(params);
}
if (engine == gcadapter->GetEngineName()) {
return gcadapter->GetUIName(params);
}
if (engine == udp_client->GetEngineName()) {
return udp_client->GetUIName(params);
}
if (engine == tas_input->GetEngineName()) {
return tas_input->GetUIName(params);
}
#ifdef HAVE_SDL2 #ifdef HAVE_SDL2
std::unique_ptr<SDL::State> sdl; if (engine == sdl->GetEngineName()) {
return sdl->GetUIName(params);
}
#endif
return "Bad engine";
}
bool IsController(const Common::ParamPackage& params) {
const std::string engine = params.Get("engine", "");
if (engine == mouse->GetEngineName()) {
return true;
}
if (engine == gcadapter->GetEngineName()) {
return true;
}
if (engine == tas_input->GetEngineName()) {
return true;
}
#ifdef HAVE_SDL2
if (engine == sdl->GetEngineName()) {
return true;
}
#endif
return false;
}
void BeginConfiguration() {
keyboard->BeginConfiguration();
mouse->BeginConfiguration();
gcadapter->BeginConfiguration();
udp_client->BeginConfiguration();
#ifdef HAVE_SDL2
sdl->BeginConfiguration();
#endif
}
void EndConfiguration() {
keyboard->EndConfiguration();
mouse->EndConfiguration();
gcadapter->EndConfiguration();
udp_client->EndConfiguration();
#ifdef HAVE_SDL2
sdl->EndConfiguration();
#endif
}
void RegisterInput(MappingData data) {
mapping_factory->RegisterInput(data);
}
std::shared_ptr<MappingFactory> mapping_factory;
std::shared_ptr<Keyboard> keyboard;
std::shared_ptr<Mouse> mouse;
std::shared_ptr<GCAdapter> gcadapter;
std::shared_ptr<TouchScreen> touch_screen;
std::shared_ptr<TasInput::Tas> tas_input;
std::shared_ptr<CemuhookUDP::UDPClient> udp_client;
std::shared_ptr<InputFactory> keyboard_factory;
std::shared_ptr<InputFactory> mouse_factory;
std::shared_ptr<InputFactory> gcadapter_input_factory;
std::shared_ptr<InputFactory> touch_screen_factory;
std::shared_ptr<InputFactory> udp_client_factory;
std::shared_ptr<InputFactory> tas_input_factory;
std::shared_ptr<OutputFactory> keyboard_output_factory;
std::shared_ptr<OutputFactory> mouse_output_factory;
std::shared_ptr<OutputFactory> gcadapter_output_factory;
std::shared_ptr<OutputFactory> tas_output_factory;
#ifdef HAVE_SDL2
std::shared_ptr<SDLDriver> sdl;
std::shared_ptr<InputFactory> sdl_input_factory;
std::shared_ptr<OutputFactory> sdl_output_factory;
#endif #endif
std::shared_ptr<GCButtonFactory> gcbuttons;
std::shared_ptr<GCAnalogFactory> gcanalog;
std::shared_ptr<GCVibrationFactory> gcvibration;
std::shared_ptr<UDPMotionFactory> udpmotion;
std::shared_ptr<UDPTouchFactory> udptouch;
std::shared_ptr<MouseButtonFactory> mousebuttons;
std::shared_ptr<MouseAnalogFactory> mouseanalog;
std::shared_ptr<MouseMotionFactory> mousemotion;
std::shared_ptr<MouseTouchFactory> mousetouch;
std::shared_ptr<TasButtonFactory> tasbuttons;
std::shared_ptr<TasAnalogFactory> tasanalog;
std::shared_ptr<CemuhookUDP::Client> udp;
std::shared_ptr<GCAdapter::Adapter> gcadapter;
std::shared_ptr<MouseInput::Mouse> mouse;
std::shared_ptr<TasInput::Tas> tas;
}; };
InputSubsystem::InputSubsystem() : impl{std::make_unique<Impl>()} {} InputSubsystem::InputSubsystem() : impl{std::make_unique<Impl>()} {}
@ -227,20 +321,28 @@ const Keyboard* InputSubsystem::GetKeyboard() const {
return impl->keyboard.get(); return impl->keyboard.get();
} }
MouseInput::Mouse* InputSubsystem::GetMouse() { Mouse* InputSubsystem::GetMouse() {
return impl->mouse.get(); return impl->mouse.get();
} }
const MouseInput::Mouse* InputSubsystem::GetMouse() const { const Mouse* InputSubsystem::GetMouse() const {
return impl->mouse.get(); return impl->mouse.get();
} }
TouchScreen* InputSubsystem::GetTouchScreen() {
return impl->touch_screen.get();
}
const TouchScreen* InputSubsystem::GetTouchScreen() const {
return impl->touch_screen.get();
}
TasInput::Tas* InputSubsystem::GetTas() { TasInput::Tas* InputSubsystem::GetTas() {
return impl->tas.get(); return impl->tas_input.get();
} }
const TasInput::Tas* InputSubsystem::GetTas() const { const TasInput::Tas* InputSubsystem::GetTas() const {
return impl->tas.get(); return impl->tas_input.get();
} }
std::vector<Common::ParamPackage> InputSubsystem::GetInputDevices() const { std::vector<Common::ParamPackage> InputSubsystem::GetInputDevices() const {
@ -259,100 +361,37 @@ MotionMapping InputSubsystem::GetMotionMappingForDevice(const Common::ParamPacka
return impl->GetMotionMappingForDevice(device); return impl->GetMotionMappingForDevice(device);
} }
GCAnalogFactory* InputSubsystem::GetGCAnalogs() { std::string InputSubsystem::GetButtonName(const Common::ParamPackage& params) const {
return impl->gcanalog.get(); const std::string toggle = params.Get("toggle", false) ? "~" : "";
const std::string inverted = params.Get("inverted", false) ? "!" : "";
const std::string button_name = impl->GetButtonName(params);
std::string axis_direction = "";
if (params.Has("axis")) {
axis_direction = params.Get("invert", "+");
}
return fmt::format("{}{}{}{}", toggle, inverted, button_name, axis_direction);
} }
const GCAnalogFactory* InputSubsystem::GetGCAnalogs() const { bool InputSubsystem::IsController(const Common::ParamPackage& params) const {
return impl->gcanalog.get(); return impl->IsController(params);
}
GCButtonFactory* InputSubsystem::GetGCButtons() {
return impl->gcbuttons.get();
}
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();
}
MouseButtonFactory* InputSubsystem::GetMouseButtons() {
return impl->mousebuttons.get();
}
const MouseButtonFactory* InputSubsystem::GetMouseButtons() const {
return impl->mousebuttons.get();
}
MouseAnalogFactory* InputSubsystem::GetMouseAnalogs() {
return impl->mouseanalog.get();
}
const MouseAnalogFactory* InputSubsystem::GetMouseAnalogs() const {
return impl->mouseanalog.get();
}
MouseMotionFactory* InputSubsystem::GetMouseMotions() {
return impl->mousemotion.get();
}
const MouseMotionFactory* InputSubsystem::GetMouseMotions() const {
return impl->mousemotion.get();
}
MouseTouchFactory* InputSubsystem::GetMouseTouch() {
return impl->mousetouch.get();
}
const MouseTouchFactory* InputSubsystem::GetMouseTouch() const {
return impl->mousetouch.get();
}
TasButtonFactory* InputSubsystem::GetTasButtons() {
return impl->tasbuttons.get();
}
const TasButtonFactory* InputSubsystem::GetTasButtons() const {
return impl->tasbuttons.get();
}
TasAnalogFactory* InputSubsystem::GetTasAnalogs() {
return impl->tasanalog.get();
}
const TasAnalogFactory* InputSubsystem::GetTasAnalogs() const {
return impl->tasanalog.get();
} }
void InputSubsystem::ReloadInputDevices() { void InputSubsystem::ReloadInputDevices() {
if (!impl->udp) { impl->udp_client.get()->ReloadSockets();
return;
}
impl->udp->ReloadSockets();
} }
std::vector<std::unique_ptr<Polling::DevicePoller>> InputSubsystem::GetPollers( void InputSubsystem::BeginMapping(Polling::InputType type) {
[[maybe_unused]] Polling::DeviceType type) const { impl->BeginConfiguration();
#ifdef HAVE_SDL2 impl->mapping_factory->BeginMapping(type);
return impl->sdl->GetPollers(type); }
#else
return {}; const Common::ParamPackage InputSubsystem::GetNextInput() const {
#endif return impl->mapping_factory->GetNextInput();
}
void InputSubsystem::StopMapping() const {
impl->EndConfiguration();
impl->mapping_factory->StopMapping();
} }
std::string GenerateKeyboardParam(int key_code) { std::string GenerateKeyboardParam(int key_code) {

View file

@ -25,56 +25,26 @@ namespace Settings::NativeMotion {
enum Values : int; enum Values : int;
} }
namespace MouseInput { namespace InputCommon {
class Keyboard;
class Mouse; class Mouse;
} class TouchScreen;
struct MappingData;
} // namespace InputCommon
namespace TasInput { namespace InputCommon::TasInput {
class Tas; class Tas;
} } // namespace InputCommon::TasInput
namespace InputCommon { namespace InputCommon {
namespace Polling { namespace Polling {
/// Type of input desired for mapping purposes
enum class DeviceType { Button, AnalogPreferred, Motion }; enum class InputType { None, Button, Stick, Motion, Touch };
/**
* A class that can be used to get inputs from an input device like controllers without having to
* poll the device's status yourself
*/
class DevicePoller {
public:
virtual ~DevicePoller() = default;
/// Setup and start polling for inputs, should be called before GetNextInput
/// If a device_id is provided, events should be filtered to only include events from this
/// device id
virtual void Start(const std::string& device_id = "") = 0;
/// Stop polling
virtual void Stop() = 0;
/**
* Every call to this function returns the next input recorded since calling Start
* @return A ParamPackage of the recorded input, which can be used to create an InputDevice.
* If there has been no input, the package is empty
*/
virtual Common::ParamPackage GetNextInput() = 0;
};
} // namespace Polling } // namespace Polling
class GCAnalogFactory;
class GCButtonFactory;
class UDPMotionFactory;
class UDPTouchFactory;
class MouseButtonFactory;
class MouseAnalogFactory;
class MouseMotionFactory;
class MouseTouchFactory;
class TasButtonFactory;
class TasAnalogFactory;
class Keyboard;
/** /**
* Given a ParamPackage for a Device returned from `GetInputDevices`, attempt to get the default * Given a ParamPackage for a Device returned from `GetInputDevices`, attempt to get the default
* mapping for the device. This is currently only implemented for the SDL backend devices. * mapping for the device.
*/ */
using AnalogMapping = std::unordered_map<Settings::NativeAnalog::Values, Common::ParamPackage>; using AnalogMapping = std::unordered_map<Settings::NativeAnalog::Values, Common::ParamPackage>;
using ButtonMapping = std::unordered_map<Settings::NativeButton::Values, Common::ParamPackage>; using ButtonMapping = std::unordered_map<Settings::NativeButton::Values, Common::ParamPackage>;
@ -104,20 +74,27 @@ public:
[[nodiscard]] const Keyboard* GetKeyboard() const; [[nodiscard]] const Keyboard* GetKeyboard() const;
/// Retrieves the underlying mouse device. /// Retrieves the underlying mouse device.
[[nodiscard]] MouseInput::Mouse* GetMouse(); [[nodiscard]] Mouse* GetMouse();
/// Retrieves the underlying mouse device. /// Retrieves the underlying mouse device.
[[nodiscard]] const MouseInput::Mouse* GetMouse() const; [[nodiscard]] const Mouse* GetMouse() const;
/// Retrieves the underlying tas device. /// Retrieves the underlying touch screen device.
[[nodiscard]] TouchScreen* GetTouchScreen();
/// Retrieves the underlying touch screen device.
[[nodiscard]] const TouchScreen* GetTouchScreen() const;
/// Retrieves the underlying tas input device.
[[nodiscard]] TasInput::Tas* GetTas(); [[nodiscard]] TasInput::Tas* GetTas();
/// Retrieves the underlying tas device. /// Retrieves the underlying tas input device.
[[nodiscard]] const TasInput::Tas* GetTas() const; [[nodiscard]] const TasInput::Tas* GetTas() const;
/** /**
* Returns all available input devices that this Factory can create a new device with. * Returns all available input devices that this Factory can create a new device with.
* Each returned ParamPackage should have a `display` field used for display, a class field for * Each returned ParamPackage should have a `display` field used for display, a `engine` field
* backends to determine if this backend is meant to service the request and any other * for backends to determine if this backend is meant to service the request and any other
* information needed to identify this in the backend later. * information needed to identify this in the backend later.
*/ */
[[nodiscard]] std::vector<Common::ParamPackage> GetInputDevices() const; [[nodiscard]] std::vector<Common::ParamPackage> GetInputDevices() const;
@ -131,83 +108,33 @@ public:
/// Retrieves the motion mappings for the given device. /// Retrieves the motion mappings for the given device.
[[nodiscard]] MotionMapping GetMotionMappingForDevice(const Common::ParamPackage& device) const; [[nodiscard]] MotionMapping GetMotionMappingForDevice(const Common::ParamPackage& device) const;
/// Retrieves the underlying GameCube analog handler. /// Returns a string contaning the name of the button from the input engine.
[[nodiscard]] GCAnalogFactory* GetGCAnalogs(); [[nodiscard]] std::string GetButtonName(const Common::ParamPackage& params) const;
/// Retrieves the underlying GameCube analog handler. /// Returns true if device is a controller.
[[nodiscard]] const GCAnalogFactory* GetGCAnalogs() const; [[nodiscard]] bool IsController(const Common::ParamPackage& params) const;
/// Retrieves the underlying GameCube button handler. /// Reloads the input devices.
[[nodiscard]] GCButtonFactory* GetGCButtons();
/// 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;
/// Retrieves the underlying mouse button handler.
[[nodiscard]] MouseButtonFactory* GetMouseButtons();
/// Retrieves the underlying mouse button handler.
[[nodiscard]] const MouseButtonFactory* GetMouseButtons() const;
/// Retrieves the underlying mouse analog handler.
[[nodiscard]] MouseAnalogFactory* GetMouseAnalogs();
/// Retrieves the underlying mouse analog handler.
[[nodiscard]] const MouseAnalogFactory* GetMouseAnalogs() const;
/// Retrieves the underlying mouse motion handler.
[[nodiscard]] MouseMotionFactory* GetMouseMotions();
/// Retrieves the underlying mouse motion handler.
[[nodiscard]] const MouseMotionFactory* GetMouseMotions() const;
/// Retrieves the underlying mouse touch handler.
[[nodiscard]] MouseTouchFactory* GetMouseTouch();
/// Retrieves the underlying mouse touch handler.
[[nodiscard]] const MouseTouchFactory* GetMouseTouch() const;
/// Retrieves the underlying tas button handler.
[[nodiscard]] TasButtonFactory* GetTasButtons();
/// Retrieves the underlying tas button handler.
[[nodiscard]] const TasButtonFactory* GetTasButtons() const;
/// Retrieves the underlying tas analogs handler.
[[nodiscard]] TasAnalogFactory* GetTasAnalogs();
/// Retrieves the underlying tas analogs handler.
[[nodiscard]] const TasAnalogFactory* GetTasAnalogs() const;
/// Reloads the input devices
void ReloadInputDevices(); void ReloadInputDevices();
/// Get all DevicePoller from all backends for a specific device type /// Start polling from all backends for a desired input type.
[[nodiscard]] std::vector<std::unique_ptr<Polling::DevicePoller>> GetPollers( void BeginMapping(Polling::InputType type);
Polling::DeviceType type) const;
/// Returns an input event with mapping information.
[[nodiscard]] const Common::ParamPackage GetNextInput() const;
/// Stop polling from all backends.
void StopMapping() const;
private: private:
struct Impl; struct Impl;
std::unique_ptr<Impl> impl; std::unique_ptr<Impl> impl;
}; };
/// Generates a serialized param package for creating a keyboard button device /// Generates a serialized param package for creating a keyboard button device.
std::string GenerateKeyboardParam(int key_code); std::string GenerateKeyboardParam(int key_code);
/// Generates a serialized param package for creating an analog device taking input from keyboard /// Generates a serialized param package for creating an analog device taking input from keyboard.
std::string GenerateAnalogParamFromKeys(int key_up, int key_down, int key_left, int key_right, std::string GenerateAnalogParamFromKeys(int key_up, int key_down, int key_left, int key_right,
int key_modifier, float modifier_scale); int key_modifier, float modifier_scale);
} // namespace InputCommon } // namespace InputCommon

View file

@ -90,9 +90,6 @@ add_executable(yuzu
configuration/configure_motion_touch.cpp configuration/configure_motion_touch.cpp
configuration/configure_motion_touch.h configuration/configure_motion_touch.h
configuration/configure_motion_touch.ui configuration/configure_motion_touch.ui
configuration/configure_mouse_advanced.cpp
configuration/configure_mouse_advanced.h
configuration/configure_mouse_advanced.ui
configuration/configure_per_game.cpp configuration/configure_per_game.cpp
configuration/configure_per_game.h configuration/configure_per_game.h
configuration/configure_per_game.ui configuration/configure_per_game.ui

View file

@ -6,8 +6,12 @@
#include <thread> #include <thread>
#include "common/assert.h" #include "common/assert.h"
#include "common/param_package.h"
#include "common/string_util.h" #include "common/string_util.h"
#include "core/core.h" #include "core/core.h"
#include "core/hid/emulated_controller.h"
#include "core/hid/hid_core.h"
#include "core/hid/hid_types.h"
#include "core/hle/lock.h" #include "core/hle/lock.h"
#include "core/hle/service/hid/controllers/npad.h" #include "core/hle/service/hid/controllers/npad.h"
#include "core/hle/service/hid/hid.h" #include "core/hle/service/hid/hid.h"
@ -23,49 +27,32 @@
namespace { namespace {
constexpr std::size_t HANDHELD_INDEX = 8; void UpdateController(Core::HID::EmulatedController* controller,
Core::HID::NpadStyleIndex controller_type, bool connected) {
constexpr std::array<std::array<bool, 4>, 8> led_patterns{{ if (controller->IsConnected()) {
{true, false, false, false}, controller->Disconnect();
{true, true, false, false}, }
{true, true, true, false}, controller->SetNpadStyleIndex(controller_type);
{true, true, true, true}, if (connected) {
{true, false, false, true}, controller->Connect();
{true, false, true, false},
{true, false, true, true},
{false, true, true, false},
}};
void UpdateController(Settings::ControllerType controller_type, std::size_t npad_index,
bool connected, Core::System& system) {
if (!system.IsPoweredOn()) {
return;
} }
auto& npad =
system.ServiceManager()
.GetService<Service::HID::Hid>("hid")
->GetAppletResource()
->GetController<Service::HID::Controller_NPad>(Service::HID::HidController::NPad);
npad.UpdateControllerAt(npad.MapSettingsTypeToNPad(controller_type), npad_index, connected);
} }
// Returns true if the given controller type is compatible with the given parameters. // Returns true if the given controller type is compatible with the given parameters.
bool IsControllerCompatible(Settings::ControllerType controller_type, bool IsControllerCompatible(Core::HID::NpadStyleIndex controller_type,
Core::Frontend::ControllerParameters parameters) { Core::Frontend::ControllerParameters parameters) {
switch (controller_type) { switch (controller_type) {
case Settings::ControllerType::ProController: case Core::HID::NpadStyleIndex::ProController:
return parameters.allow_pro_controller; return parameters.allow_pro_controller;
case Settings::ControllerType::DualJoyconDetached: case Core::HID::NpadStyleIndex::JoyconDual:
return parameters.allow_dual_joycons; return parameters.allow_dual_joycons;
case Settings::ControllerType::LeftJoycon: case Core::HID::NpadStyleIndex::JoyconLeft:
return parameters.allow_left_joycon; return parameters.allow_left_joycon;
case Settings::ControllerType::RightJoycon: case Core::HID::NpadStyleIndex::JoyconRight:
return parameters.allow_right_joycon; return parameters.allow_right_joycon;
case Settings::ControllerType::Handheld: case Core::HID::NpadStyleIndex::Handheld:
return parameters.enable_single_mode && parameters.allow_handheld; return parameters.enable_single_mode && parameters.allow_handheld;
case Settings::ControllerType::GameCube: case Core::HID::NpadStyleIndex::GameCube:
return parameters.allow_gamecube_controller; return parameters.allow_gamecube_controller;
default: default:
return false; return false;
@ -196,7 +183,7 @@ QtControllerSelectorDialog::QtControllerSelectorDialog(
connect(emulated_controllers[i], qOverload<int>(&QComboBox::currentIndexChanged), connect(emulated_controllers[i], qOverload<int>(&QComboBox::currentIndexChanged),
[this, i](int index) { [this, i](int index) {
UpdateDockedState(GetControllerTypeFromIndex(index, i) == UpdateDockedState(GetControllerTypeFromIndex(index, i) ==
Settings::ControllerType::Handheld); Core::HID::NpadStyleIndex::Handheld);
}); });
} }
} }
@ -249,17 +236,17 @@ void QtControllerSelectorDialog::ApplyConfiguration() {
} }
void QtControllerSelectorDialog::LoadConfiguration() { void QtControllerSelectorDialog::LoadConfiguration() {
const auto* handheld = system.HIDCore().GetEmulatedController(Core::HID::NpadIdType::Handheld);
for (std::size_t index = 0; index < NUM_PLAYERS; ++index) { for (std::size_t index = 0; index < NUM_PLAYERS; ++index) {
const auto connected = const auto* controller = system.HIDCore().GetEmulatedControllerByIndex(index);
Settings::values.players.GetValue()[index].connected || const auto connected = controller->IsConnected() || (index == 0 && handheld->IsConnected());
(index == 0 && Settings::values.players.GetValue()[HANDHELD_INDEX].connected);
player_groupboxes[index]->setChecked(connected); player_groupboxes[index]->setChecked(connected);
connected_controller_checkboxes[index]->setChecked(connected); connected_controller_checkboxes[index]->setChecked(connected);
emulated_controllers[index]->setCurrentIndex(GetIndexFromControllerType( emulated_controllers[index]->setCurrentIndex(
Settings::values.players.GetValue()[index].controller_type, index)); GetIndexFromControllerType(controller->GetNpadStyleIndex(), index));
} }
UpdateDockedState(Settings::values.players.GetValue()[HANDHELD_INDEX].connected); UpdateDockedState(handheld->IsConnected());
ui->vibrationGroup->setChecked(Settings::values.vibration_enabled.GetValue()); ui->vibrationGroup->setChecked(Settings::values.vibration_enabled.GetValue());
ui->motionGroup->setChecked(Settings::values.motion_enabled.GetValue()); ui->motionGroup->setChecked(Settings::values.motion_enabled.GetValue());
@ -415,33 +402,33 @@ void QtControllerSelectorDialog::SetEmulatedControllers(std::size_t player_index
emulated_controllers[player_index]->clear(); emulated_controllers[player_index]->clear();
pairs.emplace_back(emulated_controllers[player_index]->count(), pairs.emplace_back(emulated_controllers[player_index]->count(),
Settings::ControllerType::ProController); Core::HID::NpadStyleIndex::ProController);
emulated_controllers[player_index]->addItem(tr("Pro Controller")); emulated_controllers[player_index]->addItem(tr("Pro Controller"));
pairs.emplace_back(emulated_controllers[player_index]->count(), pairs.emplace_back(emulated_controllers[player_index]->count(),
Settings::ControllerType::DualJoyconDetached); Core::HID::NpadStyleIndex::JoyconDual);
emulated_controllers[player_index]->addItem(tr("Dual Joycons")); emulated_controllers[player_index]->addItem(tr("Dual Joycons"));
pairs.emplace_back(emulated_controllers[player_index]->count(), pairs.emplace_back(emulated_controllers[player_index]->count(),
Settings::ControllerType::LeftJoycon); Core::HID::NpadStyleIndex::JoyconLeft);
emulated_controllers[player_index]->addItem(tr("Left Joycon")); emulated_controllers[player_index]->addItem(tr("Left Joycon"));
pairs.emplace_back(emulated_controllers[player_index]->count(), pairs.emplace_back(emulated_controllers[player_index]->count(),
Settings::ControllerType::RightJoycon); Core::HID::NpadStyleIndex::JoyconRight);
emulated_controllers[player_index]->addItem(tr("Right Joycon")); emulated_controllers[player_index]->addItem(tr("Right Joycon"));
if (player_index == 0) { if (player_index == 0) {
pairs.emplace_back(emulated_controllers[player_index]->count(), pairs.emplace_back(emulated_controllers[player_index]->count(),
Settings::ControllerType::Handheld); Core::HID::NpadStyleIndex::Handheld);
emulated_controllers[player_index]->addItem(tr("Handheld")); emulated_controllers[player_index]->addItem(tr("Handheld"));
} }
pairs.emplace_back(emulated_controllers[player_index]->count(), pairs.emplace_back(emulated_controllers[player_index]->count(),
Settings::ControllerType::GameCube); Core::HID::NpadStyleIndex::GameCube);
emulated_controllers[player_index]->addItem(tr("GameCube Controller")); emulated_controllers[player_index]->addItem(tr("GameCube Controller"));
} }
Settings::ControllerType QtControllerSelectorDialog::GetControllerTypeFromIndex( Core::HID::NpadStyleIndex QtControllerSelectorDialog::GetControllerTypeFromIndex(
int index, std::size_t player_index) const { int index, std::size_t player_index) const {
const auto& pairs = index_controller_type_pairs[player_index]; const auto& pairs = index_controller_type_pairs[player_index];
@ -449,13 +436,13 @@ Settings::ControllerType QtControllerSelectorDialog::GetControllerTypeFromIndex(
[index](const auto& pair) { return pair.first == index; }); [index](const auto& pair) { return pair.first == index; });
if (it == pairs.end()) { if (it == pairs.end()) {
return Settings::ControllerType::ProController; return Core::HID::NpadStyleIndex::ProController;
} }
return it->second; return it->second;
} }
int QtControllerSelectorDialog::GetIndexFromControllerType(Settings::ControllerType type, int QtControllerSelectorDialog::GetIndexFromControllerType(Core::HID::NpadStyleIndex type,
std::size_t player_index) const { std::size_t player_index) const {
const auto& pairs = index_controller_type_pairs[player_index]; const auto& pairs = index_controller_type_pairs[player_index];
@ -479,16 +466,16 @@ void QtControllerSelectorDialog::UpdateControllerIcon(std::size_t player_index)
const QString stylesheet = [this, player_index] { const QString stylesheet = [this, player_index] {
switch (GetControllerTypeFromIndex(emulated_controllers[player_index]->currentIndex(), switch (GetControllerTypeFromIndex(emulated_controllers[player_index]->currentIndex(),
player_index)) { player_index)) {
case Settings::ControllerType::ProController: case Core::HID::NpadStyleIndex::ProController:
case Settings::ControllerType::GameCube: case Core::HID::NpadStyleIndex::GameCube:
return QStringLiteral("image: url(:/controller/applet_pro_controller%0); "); return QStringLiteral("image: url(:/controller/applet_pro_controller%0); ");
case Settings::ControllerType::DualJoyconDetached: case Core::HID::NpadStyleIndex::JoyconDual:
return QStringLiteral("image: url(:/controller/applet_dual_joycon%0); "); return QStringLiteral("image: url(:/controller/applet_dual_joycon%0); ");
case Settings::ControllerType::LeftJoycon: case Core::HID::NpadStyleIndex::JoyconLeft:
return QStringLiteral("image: url(:/controller/applet_joycon_left%0); "); return QStringLiteral("image: url(:/controller/applet_joycon_left%0); ");
case Settings::ControllerType::RightJoycon: case Core::HID::NpadStyleIndex::JoyconRight:
return QStringLiteral("image: url(:/controller/applet_joycon_right%0); "); return QStringLiteral("image: url(:/controller/applet_joycon_right%0); ");
case Settings::ControllerType::Handheld: case Core::HID::NpadStyleIndex::Handheld:
return QStringLiteral("image: url(:/controller/applet_handheld%0); "); return QStringLiteral("image: url(:/controller/applet_handheld%0); ");
default: default:
return QString{}; return QString{};
@ -516,54 +503,42 @@ void QtControllerSelectorDialog::UpdateControllerIcon(std::size_t player_index)
} }
void QtControllerSelectorDialog::UpdateControllerState(std::size_t player_index) { void QtControllerSelectorDialog::UpdateControllerState(std::size_t player_index) {
auto& player = Settings::values.players.GetValue()[player_index]; auto* controller = system.HIDCore().GetEmulatedControllerByIndex(player_index);
const auto controller_type = GetControllerTypeFromIndex( const auto controller_type = GetControllerTypeFromIndex(
emulated_controllers[player_index]->currentIndex(), player_index); emulated_controllers[player_index]->currentIndex(), player_index);
const auto player_connected = player_groupboxes[player_index]->isChecked() && const auto player_connected = player_groupboxes[player_index]->isChecked() &&
controller_type != Settings::ControllerType::Handheld; controller_type != Core::HID::NpadStyleIndex::Handheld;
if (player.controller_type == controller_type && player.connected == player_connected) { if (controller->GetNpadStyleIndex() == controller_type &&
controller->IsConnected() == player_connected) {
// Set vibration devices in the event that the input device has changed. // Set vibration devices in the event that the input device has changed.
ConfigureVibration::SetVibrationDevices(player_index); ConfigureVibration::SetVibrationDevices(player_index);
return; return;
} }
// Disconnect the controller first. // Disconnect the controller first.
UpdateController(controller_type, player_index, false, system); UpdateController(controller, controller_type, false);
player.controller_type = controller_type;
player.connected = player_connected;
ConfigureVibration::SetVibrationDevices(player_index); ConfigureVibration::SetVibrationDevices(player_index);
// Handheld // Handheld
if (player_index == 0) { if (player_index == 0) {
auto& handheld = Settings::values.players.GetValue()[HANDHELD_INDEX]; if (controller_type == Core::HID::NpadStyleIndex::Handheld) {
if (controller_type == Settings::ControllerType::Handheld) { auto* handheld =
handheld = player; system.HIDCore().GetEmulatedController(Core::HID::NpadIdType::Handheld);
UpdateController(handheld, Core::HID::NpadStyleIndex::Handheld,
player_groupboxes[player_index]->isChecked());
} }
handheld.connected = player_groupboxes[player_index]->isChecked() &&
controller_type == Settings::ControllerType::Handheld;
UpdateController(Settings::ControllerType::Handheld, 8, handheld.connected, system);
} }
if (!player.connected) { UpdateController(controller, controller_type, player_connected);
return;
}
// This emulates a delay between disconnecting and reconnecting controllers as some games
// do not respond to a change in controller type if it was instantaneous.
using namespace std::chrono_literals;
std::this_thread::sleep_for(60ms);
UpdateController(controller_type, player_index, player_connected, system);
} }
void QtControllerSelectorDialog::UpdateLEDPattern(std::size_t player_index) { void QtControllerSelectorDialog::UpdateLEDPattern(std::size_t player_index) {
if (!player_groupboxes[player_index]->isChecked() || if (!player_groupboxes[player_index]->isChecked() ||
GetControllerTypeFromIndex(emulated_controllers[player_index]->currentIndex(), GetControllerTypeFromIndex(emulated_controllers[player_index]->currentIndex(),
player_index) == Settings::ControllerType::Handheld) { player_index) == Core::HID::NpadStyleIndex::Handheld) {
led_patterns_boxes[player_index][0]->setChecked(false); led_patterns_boxes[player_index][0]->setChecked(false);
led_patterns_boxes[player_index][1]->setChecked(false); led_patterns_boxes[player_index][1]->setChecked(false);
led_patterns_boxes[player_index][2]->setChecked(false); led_patterns_boxes[player_index][2]->setChecked(false);
@ -571,10 +546,12 @@ void QtControllerSelectorDialog::UpdateLEDPattern(std::size_t player_index) {
return; return;
} }
led_patterns_boxes[player_index][0]->setChecked(led_patterns[player_index][0]); const auto* controller = system.HIDCore().GetEmulatedControllerByIndex(player_index);
led_patterns_boxes[player_index][1]->setChecked(led_patterns[player_index][1]); const auto led_pattern = controller->GetLedPattern();
led_patterns_boxes[player_index][2]->setChecked(led_patterns[player_index][2]); led_patterns_boxes[player_index][0]->setChecked(led_pattern.position1);
led_patterns_boxes[player_index][3]->setChecked(led_patterns[player_index][3]); led_patterns_boxes[player_index][1]->setChecked(led_pattern.position2);
led_patterns_boxes[player_index][2]->setChecked(led_pattern.position3);
led_patterns_boxes[player_index][3]->setChecked(led_pattern.position4);
} }
void QtControllerSelectorDialog::UpdateBorderColor(std::size_t player_index) { void QtControllerSelectorDialog::UpdateBorderColor(std::size_t player_index) {
@ -654,10 +631,9 @@ void QtControllerSelectorDialog::DisableUnsupportedPlayers() {
} }
for (std::size_t index = max_supported_players; index < NUM_PLAYERS; ++index) { for (std::size_t index = max_supported_players; index < NUM_PLAYERS; ++index) {
auto* controller = system.HIDCore().GetEmulatedControllerByIndex(index);
// Disconnect any unsupported players here and disable or hide them if applicable. // Disconnect any unsupported players here and disable or hide them if applicable.
Settings::values.players.GetValue()[index].connected = false; UpdateController(controller, controller->GetNpadStyleIndex(), false);
UpdateController(Settings::values.players.GetValue()[index].controller_type, index, false,
system);
// Hide the player widgets when max_supported_controllers is less than or equal to 4. // Hide the player widgets when max_supported_controllers is less than or equal to 4.
if (max_supported_players <= 4) { if (max_supported_players <= 4) {
player_widgets[index]->hide(); player_widgets[index]->hide();

View file

@ -23,14 +23,18 @@ namespace InputCommon {
class InputSubsystem; class InputSubsystem;
} }
namespace Settings {
enum class ControllerType;
}
namespace Ui { namespace Ui {
class QtControllerSelectorDialog; class QtControllerSelectorDialog;
} }
namespace Core {
class System;
}
namespace Core::HID {
enum class NpadStyleIndex : u8;
}
class QtControllerSelectorDialog final : public QDialog { class QtControllerSelectorDialog final : public QDialog {
Q_OBJECT Q_OBJECT
@ -70,10 +74,10 @@ private:
void SetEmulatedControllers(std::size_t player_index); void SetEmulatedControllers(std::size_t player_index);
// Gets the Controller Type for a given controller combobox index per player. // Gets the Controller Type for a given controller combobox index per player.
Settings::ControllerType GetControllerTypeFromIndex(int index, std::size_t player_index) const; Core::HID::NpadStyleIndex GetControllerTypeFromIndex(int index, std::size_t player_index) const;
// Gets the controller combobox index for a given Controller Type per player. // Gets the controller combobox index for a given Controller Type per player.
int GetIndexFromControllerType(Settings::ControllerType type, std::size_t player_index) const; int GetIndexFromControllerType(Core::HID::NpadStyleIndex type, std::size_t player_index) const;
// Updates the controller icons per player. // Updates the controller icons per player.
void UpdateControllerIcon(std::size_t player_index); void UpdateControllerIcon(std::size_t player_index);
@ -135,7 +139,7 @@ private:
std::array<QComboBox*, NUM_PLAYERS> emulated_controllers; std::array<QComboBox*, NUM_PLAYERS> emulated_controllers;
/// Pairs of emulated controller index and Controller Type enum per player. /// Pairs of emulated controller index and Controller Type enum per player.
std::array<std::vector<std::pair<int, Settings::ControllerType>>, NUM_PLAYERS> std::array<std::vector<std::pair<int, Core::HID::NpadStyleIndex>>, NUM_PLAYERS>
index_controller_type_pairs; index_controller_type_pairs;
// Labels representing the number of connected controllers // Labels representing the number of connected controllers

View file

@ -10,7 +10,10 @@
#include "common/settings.h" #include "common/settings.h"
#include "common/string_util.h" #include "common/string_util.h"
#include "core/core.h" #include "core/core.h"
#include "core/frontend/input_interpreter.h" #include "core/hid/emulated_controller.h"
#include "core/hid/hid_core.h"
#include "core/hid/hid_types.h"
#include "core/hid/input_interpreter.h"
#include "ui_qt_software_keyboard.h" #include "ui_qt_software_keyboard.h"
#include "yuzu/applets/qt_software_keyboard.h" #include "yuzu/applets/qt_software_keyboard.h"
#include "yuzu/main.h" #include "yuzu/main.h"
@ -484,7 +487,7 @@ void QtSoftwareKeyboardDialog::open() {
void QtSoftwareKeyboardDialog::reject() { void QtSoftwareKeyboardDialog::reject() {
// Pressing the ESC key in a dialog calls QDialog::reject(). // Pressing the ESC key in a dialog calls QDialog::reject().
// We will override this behavior to the "Cancel" action on the software keyboard. // We will override this behavior to the "Cancel" action on the software keyboard.
TranslateButtonPress(HIDButton::X); TranslateButtonPress(Core::HID::NpadButton::X);
} }
void QtSoftwareKeyboardDialog::keyPressEvent(QKeyEvent* event) { void QtSoftwareKeyboardDialog::keyPressEvent(QKeyEvent* event) {
@ -722,7 +725,7 @@ void QtSoftwareKeyboardDialog::SetTextDrawType() {
connect( connect(
ui->line_edit_osk, &QLineEdit::returnPressed, this, ui->line_edit_osk, &QLineEdit::returnPressed, this,
[this] { TranslateButtonPress(HIDButton::Plus); }, Qt::QueuedConnection); [this] { TranslateButtonPress(Core::HID::NpadButton::Plus); }, Qt::QueuedConnection);
ui->line_edit_osk->setPlaceholderText( ui->line_edit_osk->setPlaceholderText(
QString::fromStdU16String(initialize_parameters.guide_text)); QString::fromStdU16String(initialize_parameters.guide_text));
@ -795,9 +798,10 @@ void QtSoftwareKeyboardDialog::SetTextDrawType() {
} }
void QtSoftwareKeyboardDialog::SetControllerImage() { void QtSoftwareKeyboardDialog::SetControllerImage() {
const auto controller_type = Settings::values.players.GetValue()[8].connected const auto* handheld = system.HIDCore().GetEmulatedController(Core::HID::NpadIdType::Handheld);
? Settings::values.players.GetValue()[8].controller_type const auto* player_1 = system.HIDCore().GetEmulatedController(Core::HID::NpadIdType::Player1);
: Settings::values.players.GetValue()[0].controller_type; const auto controller_type =
handheld->IsConnected() ? handheld->GetNpadStyleIndex() : player_1->GetNpadStyleIndex();
const QString theme = [] { const QString theme = [] {
if (QIcon::themeName().contains(QStringLiteral("dark")) || if (QIcon::themeName().contains(QStringLiteral("dark")) ||
@ -809,8 +813,8 @@ void QtSoftwareKeyboardDialog::SetControllerImage() {
}(); }();
switch (controller_type) { switch (controller_type) {
case Settings::ControllerType::ProController: case Core::HID::NpadStyleIndex::ProController:
case Settings::ControllerType::GameCube: case Core::HID::NpadStyleIndex::GameCube:
ui->icon_controller->setStyleSheet( ui->icon_controller->setStyleSheet(
QStringLiteral("image: url(:/overlay/controller_pro%1.png);").arg(theme)); QStringLiteral("image: url(:/overlay/controller_pro%1.png);").arg(theme));
ui->icon_controller_shift->setStyleSheet( ui->icon_controller_shift->setStyleSheet(
@ -818,7 +822,7 @@ void QtSoftwareKeyboardDialog::SetControllerImage() {
ui->icon_controller_num->setStyleSheet( ui->icon_controller_num->setStyleSheet(
QStringLiteral("image: url(:/overlay/controller_pro%1.png);").arg(theme)); QStringLiteral("image: url(:/overlay/controller_pro%1.png);").arg(theme));
break; break;
case Settings::ControllerType::DualJoyconDetached: case Core::HID::NpadStyleIndex::JoyconDual:
ui->icon_controller->setStyleSheet( ui->icon_controller->setStyleSheet(
QStringLiteral("image: url(:/overlay/controller_dual_joycon%1.png);").arg(theme)); QStringLiteral("image: url(:/overlay/controller_dual_joycon%1.png);").arg(theme));
ui->icon_controller_shift->setStyleSheet( ui->icon_controller_shift->setStyleSheet(
@ -826,7 +830,7 @@ void QtSoftwareKeyboardDialog::SetControllerImage() {
ui->icon_controller_num->setStyleSheet( ui->icon_controller_num->setStyleSheet(
QStringLiteral("image: url(:/overlay/controller_dual_joycon%1.png);").arg(theme)); QStringLiteral("image: url(:/overlay/controller_dual_joycon%1.png);").arg(theme));
break; break;
case Settings::ControllerType::LeftJoycon: case Core::HID::NpadStyleIndex::JoyconLeft:
ui->icon_controller->setStyleSheet( ui->icon_controller->setStyleSheet(
QStringLiteral("image: url(:/overlay/controller_single_joycon_left%1.png);") QStringLiteral("image: url(:/overlay/controller_single_joycon_left%1.png);")
.arg(theme)); .arg(theme));
@ -837,7 +841,7 @@ void QtSoftwareKeyboardDialog::SetControllerImage() {
QStringLiteral("image: url(:/overlay/controller_single_joycon_left%1.png);") QStringLiteral("image: url(:/overlay/controller_single_joycon_left%1.png);")
.arg(theme)); .arg(theme));
break; break;
case Settings::ControllerType::RightJoycon: case Core::HID::NpadStyleIndex::JoyconRight:
ui->icon_controller->setStyleSheet( ui->icon_controller->setStyleSheet(
QStringLiteral("image: url(:/overlay/controller_single_joycon_right%1.png);") QStringLiteral("image: url(:/overlay/controller_single_joycon_right%1.png);")
.arg(theme)); .arg(theme));
@ -848,7 +852,7 @@ void QtSoftwareKeyboardDialog::SetControllerImage() {
QStringLiteral("image: url(:/overlay/controller_single_joycon_right%1.png);") QStringLiteral("image: url(:/overlay/controller_single_joycon_right%1.png);")
.arg(theme)); .arg(theme));
break; break;
case Settings::ControllerType::Handheld: case Core::HID::NpadStyleIndex::Handheld:
ui->icon_controller->setStyleSheet( ui->icon_controller->setStyleSheet(
QStringLiteral("image: url(:/overlay/controller_handheld%1.png);").arg(theme)); QStringLiteral("image: url(:/overlay/controller_handheld%1.png);").arg(theme));
ui->icon_controller_shift->setStyleSheet( ui->icon_controller_shift->setStyleSheet(
@ -1208,9 +1212,9 @@ void QtSoftwareKeyboardDialog::SetupMouseHover() {
} }
} }
template <HIDButton... T> template <Core::HID::NpadButton... T>
void QtSoftwareKeyboardDialog::HandleButtonPressedOnce() { void QtSoftwareKeyboardDialog::HandleButtonPressedOnce() {
const auto f = [this](HIDButton button) { const auto f = [this](Core::HID::NpadButton button) {
if (input_interpreter->IsButtonPressedOnce(button)) { if (input_interpreter->IsButtonPressedOnce(button)) {
TranslateButtonPress(button); TranslateButtonPress(button);
} }
@ -1219,9 +1223,9 @@ void QtSoftwareKeyboardDialog::HandleButtonPressedOnce() {
(f(T), ...); (f(T), ...);
} }
template <HIDButton... T> template <Core::HID::NpadButton... T>
void QtSoftwareKeyboardDialog::HandleButtonHold() { void QtSoftwareKeyboardDialog::HandleButtonHold() {
const auto f = [this](HIDButton button) { const auto f = [this](Core::HID::NpadButton button) {
if (input_interpreter->IsButtonHeld(button)) { if (input_interpreter->IsButtonHeld(button)) {
TranslateButtonPress(button); TranslateButtonPress(button);
} }
@ -1230,9 +1234,9 @@ void QtSoftwareKeyboardDialog::HandleButtonHold() {
(f(T), ...); (f(T), ...);
} }
void QtSoftwareKeyboardDialog::TranslateButtonPress(HIDButton button) { void QtSoftwareKeyboardDialog::TranslateButtonPress(Core::HID::NpadButton button) {
switch (button) { switch (button) {
case HIDButton::A: case Core::HID::NpadButton::A:
switch (bottom_osk_index) { switch (bottom_osk_index) {
case BottomOSKIndex::LowerCase: case BottomOSKIndex::LowerCase:
case BottomOSKIndex::UpperCase: case BottomOSKIndex::UpperCase:
@ -1245,7 +1249,7 @@ void QtSoftwareKeyboardDialog::TranslateButtonPress(HIDButton button) {
break; break;
} }
break; break;
case HIDButton::B: case Core::HID::NpadButton::B:
switch (bottom_osk_index) { switch (bottom_osk_index) {
case BottomOSKIndex::LowerCase: case BottomOSKIndex::LowerCase:
ui->button_backspace->click(); ui->button_backspace->click();
@ -1260,7 +1264,7 @@ void QtSoftwareKeyboardDialog::TranslateButtonPress(HIDButton button) {
break; break;
} }
break; break;
case HIDButton::X: case Core::HID::NpadButton::X:
if (is_inline) { if (is_inline) {
emit SubmitInlineText(SwkbdReplyType::DecidedCancel, current_text, cursor_position); emit SubmitInlineText(SwkbdReplyType::DecidedCancel, current_text, cursor_position);
} else { } else {
@ -1271,7 +1275,7 @@ void QtSoftwareKeyboardDialog::TranslateButtonPress(HIDButton button) {
emit SubmitNormalText(SwkbdResult::Cancel, std::move(text)); emit SubmitNormalText(SwkbdResult::Cancel, std::move(text));
} }
break; break;
case HIDButton::Y: case Core::HID::NpadButton::Y:
switch (bottom_osk_index) { switch (bottom_osk_index) {
case BottomOSKIndex::LowerCase: case BottomOSKIndex::LowerCase:
ui->button_space->click(); ui->button_space->click();
@ -1284,8 +1288,8 @@ void QtSoftwareKeyboardDialog::TranslateButtonPress(HIDButton button) {
break; break;
} }
break; break;
case HIDButton::LStick: case Core::HID::NpadButton::StickL:
case HIDButton::RStick: case Core::HID::NpadButton::StickR:
switch (bottom_osk_index) { switch (bottom_osk_index) {
case BottomOSKIndex::LowerCase: case BottomOSKIndex::LowerCase:
ui->button_shift->click(); ui->button_shift->click();
@ -1298,13 +1302,13 @@ void QtSoftwareKeyboardDialog::TranslateButtonPress(HIDButton button) {
break; break;
} }
break; break;
case HIDButton::L: case Core::HID::NpadButton::L:
MoveTextCursorDirection(Direction::Left); MoveTextCursorDirection(Direction::Left);
break; break;
case HIDButton::R: case Core::HID::NpadButton::R:
MoveTextCursorDirection(Direction::Right); MoveTextCursorDirection(Direction::Right);
break; break;
case HIDButton::Plus: case Core::HID::NpadButton::Plus:
switch (bottom_osk_index) { switch (bottom_osk_index) {
case BottomOSKIndex::LowerCase: case BottomOSKIndex::LowerCase:
ui->button_ok->click(); ui->button_ok->click();
@ -1319,24 +1323,24 @@ void QtSoftwareKeyboardDialog::TranslateButtonPress(HIDButton button) {
break; break;
} }
break; break;
case HIDButton::DLeft: case Core::HID::NpadButton::Left:
case HIDButton::LStickLeft: case Core::HID::NpadButton::StickLLeft:
case HIDButton::RStickLeft: case Core::HID::NpadButton::StickRLeft:
MoveButtonDirection(Direction::Left); MoveButtonDirection(Direction::Left);
break; break;
case HIDButton::DUp: case Core::HID::NpadButton::Up:
case HIDButton::LStickUp: case Core::HID::NpadButton::StickLUp:
case HIDButton::RStickUp: case Core::HID::NpadButton::StickRUp:
MoveButtonDirection(Direction::Up); MoveButtonDirection(Direction::Up);
break; break;
case HIDButton::DRight: case Core::HID::NpadButton::Right:
case HIDButton::LStickRight: case Core::HID::NpadButton::StickLRight:
case HIDButton::RStickRight: case Core::HID::NpadButton::StickRRight:
MoveButtonDirection(Direction::Right); MoveButtonDirection(Direction::Right);
break; break;
case HIDButton::DDown: case Core::HID::NpadButton::Down:
case HIDButton::LStickDown: case Core::HID::NpadButton::StickLDown:
case HIDButton::RStickDown: case Core::HID::NpadButton::StickRDown:
MoveButtonDirection(Direction::Down); MoveButtonDirection(Direction::Down);
break; break;
default: default:
@ -1467,19 +1471,25 @@ void QtSoftwareKeyboardDialog::InputThread() {
while (input_thread_running) { while (input_thread_running) {
input_interpreter->PollInput(); input_interpreter->PollInput();
HandleButtonPressedOnce<HIDButton::A, HIDButton::B, HIDButton::X, HIDButton::Y, HandleButtonPressedOnce<
HIDButton::LStick, HIDButton::RStick, HIDButton::L, HIDButton::R, Core::HID::NpadButton::A, Core::HID::NpadButton::B, Core::HID::NpadButton::X,
HIDButton::Plus, HIDButton::DLeft, HIDButton::DUp, Core::HID::NpadButton::Y, Core::HID::NpadButton::StickL, Core::HID::NpadButton::StickR,
HIDButton::DRight, HIDButton::DDown, HIDButton::LStickLeft, Core::HID::NpadButton::L, Core::HID::NpadButton::R, Core::HID::NpadButton::Plus,
HIDButton::LStickUp, HIDButton::LStickRight, HIDButton::LStickDown, Core::HID::NpadButton::Left, Core::HID::NpadButton::Up, Core::HID::NpadButton::Right,
HIDButton::RStickLeft, HIDButton::RStickUp, HIDButton::RStickRight, Core::HID::NpadButton::Down, Core::HID::NpadButton::StickLLeft,
HIDButton::RStickDown>(); Core::HID::NpadButton::StickLUp, Core::HID::NpadButton::StickLRight,
Core::HID::NpadButton::StickLDown, Core::HID::NpadButton::StickRLeft,
Core::HID::NpadButton::StickRUp, Core::HID::NpadButton::StickRRight,
Core::HID::NpadButton::StickRDown>();
HandleButtonHold<HIDButton::B, HIDButton::L, HIDButton::R, HIDButton::DLeft, HIDButton::DUp, HandleButtonHold<Core::HID::NpadButton::B, Core::HID::NpadButton::L,
HIDButton::DRight, HIDButton::DDown, HIDButton::LStickLeft, Core::HID::NpadButton::R, Core::HID::NpadButton::Left,
HIDButton::LStickUp, HIDButton::LStickRight, HIDButton::LStickDown, Core::HID::NpadButton::Up, Core::HID::NpadButton::Right,
HIDButton::RStickLeft, HIDButton::RStickUp, HIDButton::RStickRight, Core::HID::NpadButton::Down, Core::HID::NpadButton::StickLLeft,
HIDButton::RStickDown>(); Core::HID::NpadButton::StickLUp, Core::HID::NpadButton::StickLRight,
Core::HID::NpadButton::StickLDown, Core::HID::NpadButton::StickRLeft,
Core::HID::NpadButton::StickRUp, Core::HID::NpadButton::StickRRight,
Core::HID::NpadButton::StickRDown>();
std::this_thread::sleep_for(std::chrono::milliseconds(50)); std::this_thread::sleep_for(std::chrono::milliseconds(50));
} }

View file

@ -14,14 +14,16 @@
#include "core/frontend/applets/software_keyboard.h" #include "core/frontend/applets/software_keyboard.h"
enum class HIDButton : u8;
class InputInterpreter; class InputInterpreter;
namespace Core { namespace Core {
class System; class System;
} }
namespace Core::HID {
enum class NpadButton : u64;
}
namespace Ui { namespace Ui {
class QtSoftwareKeyboardDialog; class QtSoftwareKeyboardDialog;
} }
@ -146,7 +148,7 @@ private:
* *
* @tparam HIDButton The list of buttons that can be converted into keyboard input. * @tparam HIDButton The list of buttons that can be converted into keyboard input.
*/ */
template <HIDButton... T> template <Core::HID::NpadButton... T>
void HandleButtonPressedOnce(); void HandleButtonPressedOnce();
/** /**
@ -154,7 +156,7 @@ private:
* *
* @tparam HIDButton The list of buttons that can be converted into keyboard input. * @tparam HIDButton The list of buttons that can be converted into keyboard input.
*/ */
template <HIDButton... T> template <Core::HID::NpadButton... T>
void HandleButtonHold(); void HandleButtonHold();
/** /**
@ -162,7 +164,7 @@ private:
* *
* @param button The button press to process. * @param button The button press to process.
*/ */
void TranslateButtonPress(HIDButton button); void TranslateButtonPress(Core::HID::NpadButton button);
/** /**
* Moves the focus of a button in a certain direction. * Moves the focus of a button in a certain direction.

View file

@ -14,9 +14,11 @@
#endif #endif
#include "common/fs/path_util.h" #include "common/fs/path_util.h"
#include "common/param_package.h"
#include "core/core.h" #include "core/core.h"
#include "core/frontend/input_interpreter.h" #include "core/hid/hid_types.h"
#include "input_common/keyboard.h" #include "core/hid/input_interpreter.h"
#include "input_common/drivers/keyboard.h"
#include "input_common/main.h" #include "input_common/main.h"
#include "yuzu/applets/qt_web_browser.h" #include "yuzu/applets/qt_web_browser.h"
#include "yuzu/applets/qt_web_browser_scripts.h" #include "yuzu/applets/qt_web_browser_scripts.h"
@ -27,19 +29,19 @@
namespace { namespace {
constexpr int HIDButtonToKey(HIDButton button) { constexpr int HIDButtonToKey(Core::HID::NpadButton button) {
switch (button) { switch (button) {
case HIDButton::DLeft: case Core::HID::NpadButton::Left:
case HIDButton::LStickLeft: case Core::HID::NpadButton::StickLLeft:
return Qt::Key_Left; return Qt::Key_Left;
case HIDButton::DUp: case Core::HID::NpadButton::Up:
case HIDButton::LStickUp: case Core::HID::NpadButton::StickLUp:
return Qt::Key_Up; return Qt::Key_Up;
case HIDButton::DRight: case Core::HID::NpadButton::Right:
case HIDButton::LStickRight: case Core::HID::NpadButton::StickLRight:
return Qt::Key_Right; return Qt::Key_Right;
case HIDButton::DDown: case Core::HID::NpadButton::Down:
case HIDButton::LStickDown: case Core::HID::NpadButton::StickLDown:
return Qt::Key_Down; return Qt::Key_Down;
default: default:
return 0; return 0;
@ -208,25 +210,25 @@ void QtNXWebEngineView::keyReleaseEvent(QKeyEvent* event) {
} }
} }
template <HIDButton... T> template <Core::HID::NpadButton... T>
void QtNXWebEngineView::HandleWindowFooterButtonPressedOnce() { void QtNXWebEngineView::HandleWindowFooterButtonPressedOnce() {
const auto f = [this](HIDButton button) { const auto f = [this](Core::HID::NpadButton button) {
if (input_interpreter->IsButtonPressedOnce(button)) { if (input_interpreter->IsButtonPressedOnce(button)) {
page()->runJavaScript( page()->runJavaScript(
QStringLiteral("yuzu_key_callbacks[%1] == null;").arg(static_cast<u8>(button)), QStringLiteral("yuzu_key_callbacks[%1] == null;").arg(static_cast<u8>(button)),
[this, button](const QVariant& variant) { [this, button](const QVariant& variant) {
if (variant.toBool()) { if (variant.toBool()) {
switch (button) { switch (button) {
case HIDButton::A: case Core::HID::NpadButton::A:
SendMultipleKeyPressEvents<Qt::Key_A, Qt::Key_Space, Qt::Key_Return>(); SendMultipleKeyPressEvents<Qt::Key_A, Qt::Key_Space, Qt::Key_Return>();
break; break;
case HIDButton::B: case Core::HID::NpadButton::B:
SendKeyPressEvent(Qt::Key_B); SendKeyPressEvent(Qt::Key_B);
break; break;
case HIDButton::X: case Core::HID::NpadButton::X:
SendKeyPressEvent(Qt::Key_X); SendKeyPressEvent(Qt::Key_X);
break; break;
case HIDButton::Y: case Core::HID::NpadButton::Y:
SendKeyPressEvent(Qt::Key_Y); SendKeyPressEvent(Qt::Key_Y);
break; break;
default: default:
@ -244,9 +246,9 @@ void QtNXWebEngineView::HandleWindowFooterButtonPressedOnce() {
(f(T), ...); (f(T), ...);
} }
template <HIDButton... T> template <Core::HID::NpadButton... T>
void QtNXWebEngineView::HandleWindowKeyButtonPressedOnce() { void QtNXWebEngineView::HandleWindowKeyButtonPressedOnce() {
const auto f = [this](HIDButton button) { const auto f = [this](Core::HID::NpadButton button) {
if (input_interpreter->IsButtonPressedOnce(button)) { if (input_interpreter->IsButtonPressedOnce(button)) {
SendKeyPressEvent(HIDButtonToKey(button)); SendKeyPressEvent(HIDButtonToKey(button));
} }
@ -255,9 +257,9 @@ void QtNXWebEngineView::HandleWindowKeyButtonPressedOnce() {
(f(T), ...); (f(T), ...);
} }
template <HIDButton... T> template <Core::HID::NpadButton... T>
void QtNXWebEngineView::HandleWindowKeyButtonHold() { void QtNXWebEngineView::HandleWindowKeyButtonHold() {
const auto f = [this](HIDButton button) { const auto f = [this](Core::HID::NpadButton button) {
if (input_interpreter->IsButtonHeld(button)) { if (input_interpreter->IsButtonHeld(button)) {
SendKeyPressEvent(HIDButtonToKey(button)); SendKeyPressEvent(HIDButtonToKey(button));
} }
@ -308,17 +310,21 @@ void QtNXWebEngineView::InputThread() {
while (input_thread_running) { while (input_thread_running) {
input_interpreter->PollInput(); input_interpreter->PollInput();
HandleWindowFooterButtonPressedOnce<HIDButton::A, HIDButton::B, HIDButton::X, HIDButton::Y, HandleWindowFooterButtonPressedOnce<Core::HID::NpadButton::A, Core::HID::NpadButton::B,
HIDButton::L, HIDButton::R>(); Core::HID::NpadButton::X, Core::HID::NpadButton::Y,
Core::HID::NpadButton::L, Core::HID::NpadButton::R>();
HandleWindowKeyButtonPressedOnce<HIDButton::DLeft, HIDButton::DUp, HIDButton::DRight, HandleWindowKeyButtonPressedOnce<
HIDButton::DDown, HIDButton::LStickLeft, Core::HID::NpadButton::Left, Core::HID::NpadButton::Up, Core::HID::NpadButton::Right,
HIDButton::LStickUp, HIDButton::LStickRight, Core::HID::NpadButton::Down, Core::HID::NpadButton::StickLLeft,
HIDButton::LStickDown>(); Core::HID::NpadButton::StickLUp, Core::HID::NpadButton::StickLRight,
Core::HID::NpadButton::StickLDown>();
HandleWindowKeyButtonHold<HIDButton::DLeft, HIDButton::DUp, HIDButton::DRight, HandleWindowKeyButtonHold<
HIDButton::DDown, HIDButton::LStickLeft, HIDButton::LStickUp, Core::HID::NpadButton::Left, Core::HID::NpadButton::Up, Core::HID::NpadButton::Right,
HIDButton::LStickRight, HIDButton::LStickDown>(); Core::HID::NpadButton::Down, Core::HID::NpadButton::StickLLeft,
Core::HID::NpadButton::StickLUp, Core::HID::NpadButton::StickLRight,
Core::HID::NpadButton::StickLDown>();
std::this_thread::sleep_for(std::chrono::milliseconds(50)); std::this_thread::sleep_for(std::chrono::milliseconds(50));
} }

View file

@ -16,8 +16,6 @@
#include "core/frontend/applets/web_browser.h" #include "core/frontend/applets/web_browser.h"
enum class HIDButton : u8;
class GMainWindow; class GMainWindow;
class InputInterpreter; class InputInterpreter;
class UrlRequestInterceptor; class UrlRequestInterceptor;
@ -26,6 +24,10 @@ namespace Core {
class System; class System;
} }
namespace Core::HID {
enum class NpadButton : u64;
}
namespace InputCommon { namespace InputCommon {
class InputSubsystem; class InputSubsystem;
} }
@ -114,7 +116,7 @@ private:
* *
* @tparam HIDButton The list of buttons contained in yuzu_key_callbacks * @tparam HIDButton The list of buttons contained in yuzu_key_callbacks
*/ */
template <HIDButton... T> template <Core::HID::NpadButton... T>
void HandleWindowFooterButtonPressedOnce(); void HandleWindowFooterButtonPressedOnce();
/** /**
@ -123,7 +125,7 @@ private:
* *
* @tparam HIDButton The list of buttons that can be converted into keyboard input. * @tparam HIDButton The list of buttons that can be converted into keyboard input.
*/ */
template <HIDButton... T> template <Core::HID::NpadButton... T>
void HandleWindowKeyButtonPressedOnce(); void HandleWindowKeyButtonPressedOnce();
/** /**
@ -132,7 +134,7 @@ private:
* *
* @tparam HIDButton The list of buttons that can be converted into keyboard input. * @tparam HIDButton The list of buttons that can be converted into keyboard input.
*/ */
template <HIDButton... T> template <Core::HID::NpadButton... T>
void HandleWindowKeyButtonHold(); void HandleWindowKeyButtonHold();
/** /**

View file

@ -32,10 +32,11 @@
#include "common/settings.h" #include "common/settings.h"
#include "core/core.h" #include "core/core.h"
#include "core/frontend/framebuffer_layout.h" #include "core/frontend/framebuffer_layout.h"
#include "input_common/keyboard.h" #include "input_common/drivers/keyboard.h"
#include "input_common/drivers/mouse.h"
#include "input_common/drivers/tas_input.h"
#include "input_common/drivers/touch_screen.h"
#include "input_common/main.h" #include "input_common/main.h"
#include "input_common/mouse/mouse_input.h"
#include "input_common/tas/tas_input.h"
#include "video_core/renderer_base.h" #include "video_core/renderer_base.h"
#include "video_core/video_core.h" #include "video_core/video_core.h"
#include "yuzu/bootmanager.h" #include "yuzu/bootmanager.h"
@ -296,7 +297,6 @@ GRenderWindow::GRenderWindow(GMainWindow* parent, EmuThread* emu_thread_,
layout->setContentsMargins(0, 0, 0, 0); layout->setContentsMargins(0, 0, 0, 0);
setLayout(layout); setLayout(layout);
input_subsystem->Initialize(); input_subsystem->Initialize();
this->setMouseTracking(true); this->setMouseTracking(true);
connect(this, &GRenderWindow::FirstFrameDisplayed, parent, &GMainWindow::OnLoadComplete); connect(this, &GRenderWindow::FirstFrameDisplayed, parent, &GMainWindow::OnLoadComplete);
@ -383,34 +383,310 @@ void GRenderWindow::closeEvent(QCloseEvent* event) {
QWidget::closeEvent(event); QWidget::closeEvent(event);
} }
int GRenderWindow::QtKeyToSwitchKey(Qt::Key qt_key) {
switch (qt_key) {
case Qt::Key_A:
return Settings::NativeKeyboard::A;
case Qt::Key_B:
return Settings::NativeKeyboard::B;
case Qt::Key_C:
return Settings::NativeKeyboard::C;
case Qt::Key_D:
return Settings::NativeKeyboard::D;
case Qt::Key_E:
return Settings::NativeKeyboard::E;
case Qt::Key_F:
return Settings::NativeKeyboard::F;
case Qt::Key_G:
return Settings::NativeKeyboard::G;
case Qt::Key_H:
return Settings::NativeKeyboard::H;
case Qt::Key_I:
return Settings::NativeKeyboard::I;
case Qt::Key_J:
return Settings::NativeKeyboard::J;
case Qt::Key_K:
return Settings::NativeKeyboard::K;
case Qt::Key_L:
return Settings::NativeKeyboard::L;
case Qt::Key_M:
return Settings::NativeKeyboard::M;
case Qt::Key_N:
return Settings::NativeKeyboard::N;
case Qt::Key_O:
return Settings::NativeKeyboard::O;
case Qt::Key_P:
return Settings::NativeKeyboard::P;
case Qt::Key_Q:
return Settings::NativeKeyboard::Q;
case Qt::Key_R:
return Settings::NativeKeyboard::R;
case Qt::Key_S:
return Settings::NativeKeyboard::S;
case Qt::Key_T:
return Settings::NativeKeyboard::T;
case Qt::Key_U:
return Settings::NativeKeyboard::U;
case Qt::Key_V:
return Settings::NativeKeyboard::V;
case Qt::Key_W:
return Settings::NativeKeyboard::W;
case Qt::Key_X:
return Settings::NativeKeyboard::X;
case Qt::Key_Y:
return Settings::NativeKeyboard::Y;
case Qt::Key_Z:
return Settings::NativeKeyboard::Z;
case Qt::Key_1:
return Settings::NativeKeyboard::N1;
case Qt::Key_2:
return Settings::NativeKeyboard::N2;
case Qt::Key_3:
return Settings::NativeKeyboard::N3;
case Qt::Key_4:
return Settings::NativeKeyboard::N4;
case Qt::Key_5:
return Settings::NativeKeyboard::N5;
case Qt::Key_6:
return Settings::NativeKeyboard::N6;
case Qt::Key_7:
return Settings::NativeKeyboard::N7;
case Qt::Key_8:
return Settings::NativeKeyboard::N8;
case Qt::Key_9:
return Settings::NativeKeyboard::N9;
case Qt::Key_0:
return Settings::NativeKeyboard::N0;
case Qt::Key_Return:
return Settings::NativeKeyboard::Return;
case Qt::Key_Escape:
return Settings::NativeKeyboard::Escape;
case Qt::Key_Backspace:
return Settings::NativeKeyboard::Backspace;
case Qt::Key_Tab:
return Settings::NativeKeyboard::Tab;
case Qt::Key_Space:
return Settings::NativeKeyboard::Space;
case Qt::Key_Minus:
return Settings::NativeKeyboard::Minus;
case Qt::Key_Plus:
case Qt::Key_questiondown:
return Settings::NativeKeyboard::Plus;
case Qt::Key_BracketLeft:
case Qt::Key_BraceLeft:
return Settings::NativeKeyboard::OpenBracket;
case Qt::Key_BracketRight:
case Qt::Key_BraceRight:
return Settings::NativeKeyboard::CloseBracket;
case Qt::Key_Bar:
return Settings::NativeKeyboard::Pipe;
case Qt::Key_Dead_Tilde:
return Settings::NativeKeyboard::Tilde;
case Qt::Key_Ntilde:
case Qt::Key_Semicolon:
return Settings::NativeKeyboard::Semicolon;
case Qt::Key_Apostrophe:
return Settings::NativeKeyboard::Quote;
case Qt::Key_Dead_Grave:
return Settings::NativeKeyboard::Backquote;
case Qt::Key_Comma:
return Settings::NativeKeyboard::Comma;
case Qt::Key_Period:
return Settings::NativeKeyboard::Period;
case Qt::Key_Slash:
return Settings::NativeKeyboard::Slash;
case Qt::Key_CapsLock:
return Settings::NativeKeyboard::CapsLock;
case Qt::Key_F1:
return Settings::NativeKeyboard::F1;
case Qt::Key_F2:
return Settings::NativeKeyboard::F2;
case Qt::Key_F3:
return Settings::NativeKeyboard::F3;
case Qt::Key_F4:
return Settings::NativeKeyboard::F4;
case Qt::Key_F5:
return Settings::NativeKeyboard::F5;
case Qt::Key_F6:
return Settings::NativeKeyboard::F6;
case Qt::Key_F7:
return Settings::NativeKeyboard::F7;
case Qt::Key_F8:
return Settings::NativeKeyboard::F8;
case Qt::Key_F9:
return Settings::NativeKeyboard::F9;
case Qt::Key_F10:
return Settings::NativeKeyboard::F10;
case Qt::Key_F11:
return Settings::NativeKeyboard::F11;
case Qt::Key_F12:
return Settings::NativeKeyboard::F12;
case Qt::Key_Print:
return Settings::NativeKeyboard::PrintScreen;
case Qt::Key_ScrollLock:
return Settings::NativeKeyboard::ScrollLock;
case Qt::Key_Pause:
return Settings::NativeKeyboard::Pause;
case Qt::Key_Insert:
return Settings::NativeKeyboard::Insert;
case Qt::Key_Home:
return Settings::NativeKeyboard::Home;
case Qt::Key_PageUp:
return Settings::NativeKeyboard::PageUp;
case Qt::Key_Delete:
return Settings::NativeKeyboard::Delete;
case Qt::Key_End:
return Settings::NativeKeyboard::End;
case Qt::Key_PageDown:
return Settings::NativeKeyboard::PageDown;
case Qt::Key_Right:
return Settings::NativeKeyboard::Right;
case Qt::Key_Left:
return Settings::NativeKeyboard::Left;
case Qt::Key_Down:
return Settings::NativeKeyboard::Down;
case Qt::Key_Up:
return Settings::NativeKeyboard::Up;
case Qt::Key_NumLock:
return Settings::NativeKeyboard::NumLock;
// Numpad keys are missing here
case Qt::Key_F13:
return Settings::NativeKeyboard::F13;
case Qt::Key_F14:
return Settings::NativeKeyboard::F14;
case Qt::Key_F15:
return Settings::NativeKeyboard::F15;
case Qt::Key_F16:
return Settings::NativeKeyboard::F16;
case Qt::Key_F17:
return Settings::NativeKeyboard::F17;
case Qt::Key_F18:
return Settings::NativeKeyboard::F18;
case Qt::Key_F19:
return Settings::NativeKeyboard::F19;
case Qt::Key_F20:
return Settings::NativeKeyboard::F20;
case Qt::Key_F21:
return Settings::NativeKeyboard::F21;
case Qt::Key_F22:
return Settings::NativeKeyboard::F22;
case Qt::Key_F23:
return Settings::NativeKeyboard::F23;
case Qt::Key_F24:
return Settings::NativeKeyboard::F24;
// case Qt:::
// return Settings::NativeKeyboard::KPComma;
// case Qt:::
// return Settings::NativeKeyboard::Ro;
case Qt::Key_Hiragana_Katakana:
return Settings::NativeKeyboard::KatakanaHiragana;
case Qt::Key_yen:
return Settings::NativeKeyboard::Yen;
case Qt::Key_Henkan:
return Settings::NativeKeyboard::Henkan;
case Qt::Key_Muhenkan:
return Settings::NativeKeyboard::Muhenkan;
// case Qt:::
// return Settings::NativeKeyboard::NumPadCommaPc98;
case Qt::Key_Hangul:
return Settings::NativeKeyboard::HangulEnglish;
case Qt::Key_Hangul_Hanja:
return Settings::NativeKeyboard::Hanja;
case Qt::Key_Katakana:
return Settings::NativeKeyboard::KatakanaKey;
case Qt::Key_Hiragana:
return Settings::NativeKeyboard::HiraganaKey;
case Qt::Key_Zenkaku_Hankaku:
return Settings::NativeKeyboard::ZenkakuHankaku;
// Modifier keys are handled by the modifier property
default:
return Settings::NativeKeyboard::None;
}
}
int GRenderWindow::QtModifierToSwitchModdifier(quint32 qt_moddifiers) {
int moddifier = 0;
// The values are obtained through testing, Qt doesn't seem to provide a proper enum
if ((qt_moddifiers & 0x1) != 0) {
moddifier |= 1 << Settings::NativeKeyboard::LeftShift;
}
if ((qt_moddifiers & 0x2) != 0) {
moddifier |= 1 << Settings::NativeKeyboard::LeftControl;
}
if ((qt_moddifiers & 0x4) != 0) {
moddifier |= 1 << Settings::NativeKeyboard::LeftAlt;
}
if ((qt_moddifiers & 0x08) != 0) {
moddifier |= 1 << Settings::NativeKeyboard::LeftMeta;
}
if ((qt_moddifiers & 0x10) != 0) {
moddifier |= 1 << Settings::NativeKeyboard::RightShift;
}
if ((qt_moddifiers & 0x20) != 0) {
moddifier |= 1 << Settings::NativeKeyboard::RightControl;
}
if ((qt_moddifiers & 0x40) != 0) {
moddifier |= 1 << Settings::NativeKeyboard::RightAlt;
}
if ((qt_moddifiers & 0x80) != 0) {
moddifier |= 1 << Settings::NativeKeyboard::RightMeta;
}
if ((qt_moddifiers & 0x100) != 0) {
moddifier |= 1 << Settings::NativeKeyboard::CapsLock;
}
if ((qt_moddifiers & 0x200) != 0) {
moddifier |= 1 << Settings::NativeKeyboard::NumLock;
}
// Verify the last two keys
if ((qt_moddifiers & 0x400) != 0) {
moddifier |= 1 << Settings::NativeKeyboard::Katakana;
}
if ((qt_moddifiers & 0x800) != 0) {
moddifier |= 1 << Settings::NativeKeyboard::Hiragana;
}
return moddifier;
}
void GRenderWindow::keyPressEvent(QKeyEvent* event) { void GRenderWindow::keyPressEvent(QKeyEvent* event) {
if (!event->isAutoRepeat()) { if (!event->isAutoRepeat()) {
const auto moddifier = QtModifierToSwitchModdifier(event->nativeModifiers());
// Replace event->key() with event->nativeVirtualKey() since the second one provides raw key
// buttons
const auto key = QtKeyToSwitchKey(Qt::Key(event->key()));
input_subsystem->GetKeyboard()->SetKeyboardModifiers(moddifier);
input_subsystem->GetKeyboard()->PressKeyboardKey(key);
// This is used for gamepads
input_subsystem->GetKeyboard()->PressKey(event->key()); input_subsystem->GetKeyboard()->PressKey(event->key());
} }
} }
void GRenderWindow::keyReleaseEvent(QKeyEvent* event) { void GRenderWindow::keyReleaseEvent(QKeyEvent* event) {
if (!event->isAutoRepeat()) { if (!event->isAutoRepeat()) {
const auto moddifier = QtModifierToSwitchModdifier(event->nativeModifiers());
const auto key = QtKeyToSwitchKey(Qt::Key(event->key()));
input_subsystem->GetKeyboard()->SetKeyboardModifiers(moddifier);
input_subsystem->GetKeyboard()->ReleaseKeyboardKey(key);
// This is used for gamepads
input_subsystem->GetKeyboard()->ReleaseKey(event->key()); input_subsystem->GetKeyboard()->ReleaseKey(event->key());
} }
} }
MouseInput::MouseButton GRenderWindow::QtButtonToMouseButton(Qt::MouseButton button) { InputCommon::MouseButton GRenderWindow::QtButtonToMouseButton(Qt::MouseButton button) {
switch (button) { switch (button) {
case Qt::LeftButton: case Qt::LeftButton:
return MouseInput::MouseButton::Left; return InputCommon::MouseButton::Left;
case Qt::RightButton: case Qt::RightButton:
return MouseInput::MouseButton::Right; return InputCommon::MouseButton::Right;
case Qt::MiddleButton: case Qt::MiddleButton:
return MouseInput::MouseButton::Wheel; return InputCommon::MouseButton::Wheel;
case Qt::BackButton: case Qt::BackButton:
return MouseInput::MouseButton::Backward; return InputCommon::MouseButton::Backward;
case Qt::ForwardButton: case Qt::ForwardButton:
return MouseInput::MouseButton::Forward; return InputCommon::MouseButton::Forward;
case Qt::TaskButton: case Qt::TaskButton:
return MouseInput::MouseButton::Task; return InputCommon::MouseButton::Task;
default: default:
return MouseInput::MouseButton::Extra; return InputCommon::MouseButton::Extra;
} }
} }
@ -423,12 +699,9 @@ void GRenderWindow::mousePressEvent(QMouseEvent* event) {
// coordinates and map them to the current render area // coordinates and map them to the current render area
const auto pos = mapFromGlobal(QCursor::pos()); const auto pos = mapFromGlobal(QCursor::pos());
const auto [x, y] = ScaleTouch(pos); const auto [x, y] = ScaleTouch(pos);
const auto [touch_x, touch_y] = MapToTouchScreen(x, y);
const auto button = QtButtonToMouseButton(event->button()); const auto button = QtButtonToMouseButton(event->button());
input_subsystem->GetMouse()->PressButton(x, y, button); input_subsystem->GetMouse()->PressButton(x, y, touch_x, touch_y, button);
if (event->button() == Qt::LeftButton) {
this->TouchPressed(x, y, 0);
}
emit MouseActivity(); emit MouseActivity();
} }
@ -442,10 +715,10 @@ void GRenderWindow::mouseMoveEvent(QMouseEvent* event) {
// coordinates and map them to the current render area // coordinates and map them to the current render area
const auto pos = mapFromGlobal(QCursor::pos()); const auto pos = mapFromGlobal(QCursor::pos());
const auto [x, y] = ScaleTouch(pos); const auto [x, y] = ScaleTouch(pos);
const auto [touch_x, touch_y] = MapToTouchScreen(x, y);
const int center_x = width() / 2; const int center_x = width() / 2;
const int center_y = height() / 2; const int center_y = height() / 2;
input_subsystem->GetMouse()->MouseMove(x, y, center_x, center_y); input_subsystem->GetMouse()->MouseMove(x, y, touch_x, touch_y, center_x, center_y);
this->TouchMoved(x, y, 0);
if (Settings::values.mouse_panning) { if (Settings::values.mouse_panning) {
QCursor::setPos(mapToGlobal({center_x, center_y})); QCursor::setPos(mapToGlobal({center_x, center_y}));
@ -462,10 +735,12 @@ void GRenderWindow::mouseReleaseEvent(QMouseEvent* event) {
const auto button = QtButtonToMouseButton(event->button()); const auto button = QtButtonToMouseButton(event->button());
input_subsystem->GetMouse()->ReleaseButton(button); input_subsystem->GetMouse()->ReleaseButton(button);
if (event->button() == Qt::LeftButton) {
this->TouchReleased(0);
} }
void GRenderWindow::wheelEvent(QWheelEvent* event) {
const int x = event->delta();
const int y = 0;
input_subsystem->GetMouse()->MouseWheelChange(x, y);
} }
void GRenderWindow::TouchBeginEvent(const QTouchEvent* event) { void GRenderWindow::TouchBeginEvent(const QTouchEvent* event) {
@ -488,7 +763,7 @@ void GRenderWindow::TouchUpdateEvent(const QTouchEvent* event) {
for (std::size_t id = 0; id < touch_ids.size(); ++id) { for (std::size_t id = 0; id < touch_ids.size(); ++id) {
if (!TouchExist(touch_ids[id], touch_points)) { if (!TouchExist(touch_ids[id], touch_points)) {
touch_ids[id] = 0; touch_ids[id] = 0;
this->TouchReleased(id + 1); input_subsystem->GetTouchScreen()->TouchReleased(id);
} }
} }
} }
@ -497,28 +772,28 @@ void GRenderWindow::TouchEndEvent() {
for (std::size_t id = 0; id < touch_ids.size(); ++id) { for (std::size_t id = 0; id < touch_ids.size(); ++id) {
if (touch_ids[id] != 0) { if (touch_ids[id] != 0) {
touch_ids[id] = 0; touch_ids[id] = 0;
this->TouchReleased(id + 1); input_subsystem->GetTouchScreen()->TouchReleased(id);
} }
} }
} }
bool GRenderWindow::TouchStart(const QTouchEvent::TouchPoint& touch_point) { void GRenderWindow::TouchStart(const QTouchEvent::TouchPoint& touch_point) {
for (std::size_t id = 0; id < touch_ids.size(); ++id) { for (std::size_t id = 0; id < touch_ids.size(); ++id) {
if (touch_ids[id] == 0) { if (touch_ids[id] == 0) {
touch_ids[id] = touch_point.id() + 1; touch_ids[id] = touch_point.id() + 1;
const auto [x, y] = ScaleTouch(touch_point.pos()); const auto [x, y] = ScaleTouch(touch_point.pos());
this->TouchPressed(x, y, id + 1); const auto [touch_x, touch_y] = MapToTouchScreen(x, y);
return true; input_subsystem->GetTouchScreen()->TouchPressed(touch_x, touch_y, id);
} }
} }
return false;
} }
bool GRenderWindow::TouchUpdate(const QTouchEvent::TouchPoint& touch_point) { bool GRenderWindow::TouchUpdate(const QTouchEvent::TouchPoint& touch_point) {
for (std::size_t id = 0; id < touch_ids.size(); ++id) { for (std::size_t id = 0; id < touch_ids.size(); ++id) {
if (touch_ids[id] == static_cast<std::size_t>(touch_point.id() + 1)) { if (touch_ids[id] == static_cast<std::size_t>(touch_point.id() + 1)) {
const auto [x, y] = ScaleTouch(touch_point.pos()); const auto [x, y] = ScaleTouch(touch_point.pos());
this->TouchMoved(x, y, id + 1); const auto [touch_x, touch_y] = MapToTouchScreen(x, y);
input_subsystem->GetTouchScreen()->TouchMoved(touch_x, touch_y, id);
return true; return true;
} }
} }
@ -551,7 +826,7 @@ void GRenderWindow::focusOutEvent(QFocusEvent* event) {
QWidget::focusOutEvent(event); QWidget::focusOutEvent(event);
input_subsystem->GetKeyboard()->ReleaseAllKeys(); input_subsystem->GetKeyboard()->ReleaseAllKeys();
input_subsystem->GetMouse()->ReleaseAllButtons(); input_subsystem->GetMouse()->ReleaseAllButtons();
this->TouchReleased(0); input_subsystem->GetTouchScreen()->ReleaseAllTouch();
} }
void GRenderWindow::resizeEvent(QResizeEvent* event) { void GRenderWindow::resizeEvent(QResizeEvent* event) {

View file

@ -30,11 +30,8 @@ class System;
namespace InputCommon { namespace InputCommon {
class InputSubsystem; class InputSubsystem;
}
namespace MouseInput {
enum class MouseButton; enum class MouseButton;
} } // namespace InputCommon
namespace VideoCore { namespace VideoCore {
enum class LoadCallbackStage; enum class LoadCallbackStage;
@ -157,15 +154,22 @@ public:
void resizeEvent(QResizeEvent* event) override; void resizeEvent(QResizeEvent* event) override;
/// Converts a Qt keybard key into NativeKeyboard key
static int QtKeyToSwitchKey(Qt::Key qt_keys);
/// Converts a Qt modifier keys into NativeKeyboard modifier keys
static int QtModifierToSwitchModdifier(quint32 qt_moddifiers);
void keyPressEvent(QKeyEvent* event) override; void keyPressEvent(QKeyEvent* event) override;
void keyReleaseEvent(QKeyEvent* event) override; void keyReleaseEvent(QKeyEvent* event) override;
/// Converts a Qt mouse button into MouseInput mouse button /// Converts a Qt mouse button into MouseInput mouse button
static MouseInput::MouseButton QtButtonToMouseButton(Qt::MouseButton button); static InputCommon::MouseButton QtButtonToMouseButton(Qt::MouseButton button);
void mousePressEvent(QMouseEvent* event) override; void mousePressEvent(QMouseEvent* event) override;
void mouseMoveEvent(QMouseEvent* event) override; void mouseMoveEvent(QMouseEvent* event) override;
void mouseReleaseEvent(QMouseEvent* event) override; void mouseReleaseEvent(QMouseEvent* event) override;
void wheelEvent(QWheelEvent* event) override;
bool event(QEvent* event) override; bool event(QEvent* event) override;
@ -209,7 +213,7 @@ private:
void TouchUpdateEvent(const QTouchEvent* event); void TouchUpdateEvent(const QTouchEvent* event);
void TouchEndEvent(); void TouchEndEvent();
bool TouchStart(const QTouchEvent::TouchPoint& touch_point); void TouchStart(const QTouchEvent::TouchPoint& touch_point);
bool TouchUpdate(const QTouchEvent::TouchPoint& touch_point); bool TouchUpdate(const QTouchEvent::TouchPoint& touch_point);
bool TouchExist(std::size_t id, const QList<QTouchEvent::TouchPoint>& touch_points) const; bool TouchExist(std::size_t id, const QList<QTouchEvent::TouchPoint>& touch_points) const;

View file

@ -11,7 +11,6 @@
#include "core/hle/service/acc/profile_manager.h" #include "core/hle/service/acc/profile_manager.h"
#include "core/hle/service/hid/controllers/npad.h" #include "core/hle/service/hid/controllers/npad.h"
#include "input_common/main.h" #include "input_common/main.h"
#include "input_common/udp/client.h"
#include "yuzu/configuration/config.h" #include "yuzu/configuration/config.h"
namespace FS = Common::FS; namespace FS = Common::FS;
@ -61,162 +60,6 @@ const std::array<int, 2> Config::default_stick_mod = {
0, 0,
}; };
const std::array<int, Settings::NativeMouseButton::NumMouseButtons> Config::default_mouse_buttons =
{
Qt::Key_BracketLeft, Qt::Key_BracketRight, Qt::Key_Apostrophe, Qt::Key_Minus, Qt::Key_Equal,
};
const std::array<int, Settings::NativeKeyboard::NumKeyboardKeys> Config::default_keyboard_keys = {
0,
0,
0,
0,
Qt::Key_A,
Qt::Key_B,
Qt::Key_C,
Qt::Key_D,
Qt::Key_E,
Qt::Key_F,
Qt::Key_G,
Qt::Key_H,
Qt::Key_I,
Qt::Key_J,
Qt::Key_K,
Qt::Key_L,
Qt::Key_M,
Qt::Key_N,
Qt::Key_O,
Qt::Key_P,
Qt::Key_Q,
Qt::Key_R,
Qt::Key_S,
Qt::Key_T,
Qt::Key_U,
Qt::Key_V,
Qt::Key_W,
Qt::Key_X,
Qt::Key_Y,
Qt::Key_Z,
Qt::Key_1,
Qt::Key_2,
Qt::Key_3,
Qt::Key_4,
Qt::Key_5,
Qt::Key_6,
Qt::Key_7,
Qt::Key_8,
Qt::Key_9,
Qt::Key_0,
Qt::Key_Enter,
Qt::Key_Escape,
Qt::Key_Backspace,
Qt::Key_Tab,
Qt::Key_Space,
Qt::Key_Minus,
Qt::Key_Equal,
Qt::Key_BracketLeft,
Qt::Key_BracketRight,
Qt::Key_Backslash,
Qt::Key_Dead_Tilde,
Qt::Key_Semicolon,
Qt::Key_Apostrophe,
Qt::Key_Dead_Grave,
Qt::Key_Comma,
Qt::Key_Period,
Qt::Key_Slash,
Qt::Key_CapsLock,
Qt::Key_F1,
Qt::Key_F2,
Qt::Key_F3,
Qt::Key_F4,
Qt::Key_F5,
Qt::Key_F6,
Qt::Key_F7,
Qt::Key_F8,
Qt::Key_F9,
Qt::Key_F10,
Qt::Key_F11,
Qt::Key_F12,
Qt::Key_SysReq,
Qt::Key_ScrollLock,
Qt::Key_Pause,
Qt::Key_Insert,
Qt::Key_Home,
Qt::Key_PageUp,
Qt::Key_Delete,
Qt::Key_End,
Qt::Key_PageDown,
Qt::Key_Right,
Qt::Key_Left,
Qt::Key_Down,
Qt::Key_Up,
Qt::Key_NumLock,
Qt::Key_Slash,
Qt::Key_Asterisk,
Qt::Key_Minus,
Qt::Key_Plus,
Qt::Key_Enter,
Qt::Key_1,
Qt::Key_2,
Qt::Key_3,
Qt::Key_4,
Qt::Key_5,
Qt::Key_6,
Qt::Key_7,
Qt::Key_8,
Qt::Key_9,
Qt::Key_0,
Qt::Key_Period,
0,
0,
Qt::Key_PowerOff,
Qt::Key_Equal,
Qt::Key_F13,
Qt::Key_F14,
Qt::Key_F15,
Qt::Key_F16,
Qt::Key_F17,
Qt::Key_F18,
Qt::Key_F19,
Qt::Key_F20,
Qt::Key_F21,
Qt::Key_F22,
Qt::Key_F23,
Qt::Key_F24,
Qt::Key_Open,
Qt::Key_Help,
Qt::Key_Menu,
0,
Qt::Key_Stop,
Qt::Key_AudioRepeat,
Qt::Key_Undo,
Qt::Key_Cut,
Qt::Key_Copy,
Qt::Key_Paste,
Qt::Key_Find,
Qt::Key_VolumeMute,
Qt::Key_VolumeUp,
Qt::Key_VolumeDown,
Qt::Key_CapsLock,
Qt::Key_NumLock,
Qt::Key_ScrollLock,
Qt::Key_Comma,
Qt::Key_ParenLeft,
Qt::Key_ParenRight,
};
const std::array<int, Settings::NativeKeyboard::NumKeyboardMods> Config::default_keyboard_mods = {
Qt::Key_Control, Qt::Key_Shift, Qt::Key_Alt, Qt::Key_ApplicationLeft,
Qt::Key_Control, Qt::Key_Shift, Qt::Key_AltGr, Qt::Key_ApplicationRight,
};
// This shouldn't have anything except static initializers (no functions). So // This shouldn't have anything except static initializers (no functions). So
// QKeySequence(...).toString() is NOT ALLOWED HERE. // QKeySequence(...).toString() is NOT ALLOWED HERE.
// This must be in alphabetical order according to action name as it must have the same order as // This must be in alphabetical order according to action name as it must have the same order as
@ -496,35 +339,10 @@ void Config::ReadDebugValues() {
void Config::ReadKeyboardValues() { void Config::ReadKeyboardValues() {
ReadBasicSetting(Settings::values.keyboard_enabled); ReadBasicSetting(Settings::values.keyboard_enabled);
std::transform(default_keyboard_keys.begin(), default_keyboard_keys.end(),
Settings::values.keyboard_keys.begin(), InputCommon::GenerateKeyboardParam);
std::transform(default_keyboard_mods.begin(), default_keyboard_mods.end(),
Settings::values.keyboard_keys.begin() +
Settings::NativeKeyboard::LeftControlKey,
InputCommon::GenerateKeyboardParam);
std::transform(default_keyboard_mods.begin(), default_keyboard_mods.end(),
Settings::values.keyboard_mods.begin(), InputCommon::GenerateKeyboardParam);
} }
void Config::ReadMouseValues() { void Config::ReadMouseValues() {
ReadBasicSetting(Settings::values.mouse_enabled); ReadBasicSetting(Settings::values.mouse_enabled);
for (int i = 0; i < Settings::NativeMouseButton::NumMouseButtons; ++i) {
const std::string default_param =
InputCommon::GenerateKeyboardParam(default_mouse_buttons[i]);
auto& mouse_buttons = Settings::values.mouse_buttons[i];
mouse_buttons = qt_config
->value(QStringLiteral("mouse_") +
QString::fromUtf8(Settings::NativeMouseButton::mapping[i]),
QString::fromStdString(default_param))
.toString()
.toStdString();
if (mouse_buttons.empty()) {
mouse_buttons = default_param;
}
}
} }
void Config::ReadTouchscreenValues() { void Config::ReadTouchscreenValues() {
@ -574,7 +392,6 @@ void Config::ReadControlValues() {
ReadBasicSetting(Settings::values.tas_enable); ReadBasicSetting(Settings::values.tas_enable);
ReadBasicSetting(Settings::values.tas_loop); ReadBasicSetting(Settings::values.tas_loop);
ReadBasicSetting(Settings::values.tas_swap_controllers);
ReadBasicSetting(Settings::values.pause_tas_on_load); ReadBasicSetting(Settings::values.pause_tas_on_load);
ReadGlobalSetting(Settings::values.use_docked_mode); ReadGlobalSetting(Settings::values.use_docked_mode);
@ -625,9 +442,7 @@ void Config::ReadMotionTouchValues() {
} }
qt_config->endArray(); qt_config->endArray();
ReadBasicSetting(Settings::values.motion_device);
ReadBasicSetting(Settings::values.touch_device); ReadBasicSetting(Settings::values.touch_device);
ReadBasicSetting(Settings::values.use_touch_from_button);
ReadBasicSetting(Settings::values.touch_from_button_map_index); ReadBasicSetting(Settings::values.touch_from_button_map_index);
Settings::values.touch_from_button_map_index = std::clamp( Settings::values.touch_from_button_map_index = std::clamp(
Settings::values.touch_from_button_map_index.GetValue(), 0, num_touch_from_button_maps - 1); Settings::values.touch_from_button_map_index.GetValue(), 0, num_touch_from_button_maps - 1);
@ -1111,15 +926,6 @@ void Config::SaveDebugValues() {
void Config::SaveMouseValues() { void Config::SaveMouseValues() {
WriteBasicSetting(Settings::values.mouse_enabled); WriteBasicSetting(Settings::values.mouse_enabled);
for (int i = 0; i < Settings::NativeMouseButton::NumMouseButtons; ++i) {
const std::string default_param =
InputCommon::GenerateKeyboardParam(default_mouse_buttons[i]);
WriteSetting(QStringLiteral("mouse_") +
QString::fromStdString(Settings::NativeMouseButton::mapping[i]),
QString::fromStdString(Settings::values.mouse_buttons[i]),
QString::fromStdString(default_param));
}
} }
void Config::SaveTouchscreenValues() { void Config::SaveTouchscreenValues() {
@ -1133,9 +939,7 @@ void Config::SaveTouchscreenValues() {
} }
void Config::SaveMotionTouchValues() { void Config::SaveMotionTouchValues() {
WriteBasicSetting(Settings::values.motion_device);
WriteBasicSetting(Settings::values.touch_device); WriteBasicSetting(Settings::values.touch_device);
WriteBasicSetting(Settings::values.use_touch_from_button);
WriteBasicSetting(Settings::values.touch_from_button_map_index); WriteBasicSetting(Settings::values.touch_from_button_map_index);
WriteBasicSetting(Settings::values.udp_input_servers); WriteBasicSetting(Settings::values.udp_input_servers);
@ -1210,7 +1014,6 @@ void Config::SaveControlValues() {
WriteBasicSetting(Settings::values.tas_enable); WriteBasicSetting(Settings::values.tas_enable);
WriteBasicSetting(Settings::values.tas_loop); WriteBasicSetting(Settings::values.tas_loop);
WriteBasicSetting(Settings::values.tas_swap_controllers);
WriteBasicSetting(Settings::values.pause_tas_on_load); WriteBasicSetting(Settings::values.pause_tas_on_load);
qt_config->endGroup(); qt_config->endGroup();

View file

@ -2,17 +2,18 @@
// Licensed under GPLv2 or any later version // Licensed under GPLv2 or any later version
// Refer to the license.txt file included. // Refer to the license.txt file included.
#include "core/core.h" #include "core/hid/hid_core.h"
#include "ui_configure_debug_controller.h" #include "ui_configure_debug_controller.h"
#include "yuzu/configuration/configure_debug_controller.h" #include "yuzu/configuration/configure_debug_controller.h"
#include "yuzu/configuration/configure_input_player.h" #include "yuzu/configuration/configure_input_player.h"
ConfigureDebugController::ConfigureDebugController(QWidget* parent, ConfigureDebugController::ConfigureDebugController(QWidget* parent,
InputCommon::InputSubsystem* input_subsystem, InputCommon::InputSubsystem* input_subsystem,
InputProfiles* profiles, Core::System& system) InputProfiles* profiles,
Core::HID::HIDCore& hid_core, bool is_powered_on)
: QDialog(parent), ui(std::make_unique<Ui::ConfigureDebugController>()), : QDialog(parent), ui(std::make_unique<Ui::ConfigureDebugController>()),
debug_controller( debug_controller(new ConfigureInputPlayer(this, 9, nullptr, input_subsystem, profiles,
new ConfigureInputPlayer(this, 9, nullptr, input_subsystem, profiles, system, true)) { hid_core, is_powered_on, true)) {
ui->setupUi(this); ui->setupUi(this);
ui->controllerLayout->addWidget(debug_controller); ui->controllerLayout->addWidget(debug_controller);

View file

@ -13,8 +13,8 @@ class ConfigureInputPlayer;
class InputProfiles; class InputProfiles;
namespace Core { namespace Core::HID {
class System; class HIDCore;
} }
namespace InputCommon { namespace InputCommon {
@ -30,7 +30,8 @@ class ConfigureDebugController : public QDialog {
public: public:
explicit ConfigureDebugController(QWidget* parent, InputCommon::InputSubsystem* input_subsystem, explicit ConfigureDebugController(QWidget* parent, InputCommon::InputSubsystem* input_subsystem,
InputProfiles* profiles, Core::System& system); InputProfiles* profiles, Core::HID::HIDCore& hid_core,
bool is_powered_on);
~ConfigureDebugController() override; ~ConfigureDebugController() override;
void ApplyConfiguration(); void ApplyConfiguration();

View file

@ -10,6 +10,8 @@
#include <QTimer> #include <QTimer>
#include "core/core.h" #include "core/core.h"
#include "core/hid/emulated_controller.h"
#include "core/hid/hid_core.h"
#include "core/hle/service/am/am.h" #include "core/hle/service/am/am.h"
#include "core/hle/service/am/applet_ae.h" #include "core/hle/service/am/applet_ae.h"
#include "core/hle/service/am/applet_oe.h" #include "core/hle/service/am/applet_oe.h"
@ -22,7 +24,6 @@
#include "yuzu/configuration/configure_input_advanced.h" #include "yuzu/configuration/configure_input_advanced.h"
#include "yuzu/configuration/configure_input_player.h" #include "yuzu/configuration/configure_input_player.h"
#include "yuzu/configuration/configure_motion_touch.h" #include "yuzu/configuration/configure_motion_touch.h"
#include "yuzu/configuration/configure_mouse_advanced.h"
#include "yuzu/configuration/configure_touchscreen_advanced.h" #include "yuzu/configuration/configure_touchscreen_advanced.h"
#include "yuzu/configuration/configure_vibration.h" #include "yuzu/configuration/configure_vibration.h"
#include "yuzu/configuration/input_profiles.h" #include "yuzu/configuration/input_profiles.h"
@ -75,23 +76,25 @@ ConfigureInput::~ConfigureInput() = default;
void ConfigureInput::Initialize(InputCommon::InputSubsystem* input_subsystem, void ConfigureInput::Initialize(InputCommon::InputSubsystem* input_subsystem,
std::size_t max_players) { std::size_t max_players) {
const bool is_powered_on = system.IsPoweredOn();
auto& hid_core = system.HIDCore();
player_controllers = { player_controllers = {
new ConfigureInputPlayer(this, 0, ui->consoleInputSettings, input_subsystem, profiles.get(), new ConfigureInputPlayer(this, 0, ui->consoleInputSettings, input_subsystem, profiles.get(),
system), hid_core, is_powered_on),
new ConfigureInputPlayer(this, 1, ui->consoleInputSettings, input_subsystem, profiles.get(), new ConfigureInputPlayer(this, 1, ui->consoleInputSettings, input_subsystem, profiles.get(),
system), hid_core, is_powered_on),
new ConfigureInputPlayer(this, 2, ui->consoleInputSettings, input_subsystem, profiles.get(), new ConfigureInputPlayer(this, 2, ui->consoleInputSettings, input_subsystem, profiles.get(),
system), hid_core, is_powered_on),
new ConfigureInputPlayer(this, 3, ui->consoleInputSettings, input_subsystem, profiles.get(), new ConfigureInputPlayer(this, 3, ui->consoleInputSettings, input_subsystem, profiles.get(),
system), hid_core, is_powered_on),
new ConfigureInputPlayer(this, 4, ui->consoleInputSettings, input_subsystem, profiles.get(), new ConfigureInputPlayer(this, 4, ui->consoleInputSettings, input_subsystem, profiles.get(),
system), hid_core, is_powered_on),
new ConfigureInputPlayer(this, 5, ui->consoleInputSettings, input_subsystem, profiles.get(), new ConfigureInputPlayer(this, 5, ui->consoleInputSettings, input_subsystem, profiles.get(),
system), hid_core, is_powered_on),
new ConfigureInputPlayer(this, 6, ui->consoleInputSettings, input_subsystem, profiles.get(), new ConfigureInputPlayer(this, 6, ui->consoleInputSettings, input_subsystem, profiles.get(),
system), hid_core, is_powered_on),
new ConfigureInputPlayer(this, 7, ui->consoleInputSettings, input_subsystem, profiles.get(), new ConfigureInputPlayer(this, 7, ui->consoleInputSettings, input_subsystem, profiles.get(),
system), hid_core, is_powered_on),
}; };
player_tabs = { player_tabs = {
@ -114,6 +117,7 @@ void ConfigureInput::Initialize(InputCommon::InputSubsystem* input_subsystem,
player_tabs[i]->setLayout(new QHBoxLayout(player_tabs[i])); player_tabs[i]->setLayout(new QHBoxLayout(player_tabs[i]));
player_tabs[i]->layout()->addWidget(player_controllers[i]); player_tabs[i]->layout()->addWidget(player_controllers[i]);
connect(player_controllers[i], &ConfigureInputPlayer::Connected, [&, i](bool is_connected) { connect(player_controllers[i], &ConfigureInputPlayer::Connected, [&, i](bool is_connected) {
// Ensures that the controllers are always connected in sequential order
if (is_connected) { if (is_connected) {
for (std::size_t index = 0; index <= i; ++index) { for (std::size_t index = 0; index <= i; ++index) {
player_connected[index]->setChecked(is_connected); player_connected[index]->setChecked(is_connected);
@ -146,12 +150,11 @@ void ConfigureInput::Initialize(InputCommon::InputSubsystem* input_subsystem,
advanced = new ConfigureInputAdvanced(this); advanced = new ConfigureInputAdvanced(this);
ui->tabAdvanced->setLayout(new QHBoxLayout(ui->tabAdvanced)); ui->tabAdvanced->setLayout(new QHBoxLayout(ui->tabAdvanced));
ui->tabAdvanced->layout()->addWidget(advanced); ui->tabAdvanced->layout()->addWidget(advanced);
connect(advanced, &ConfigureInputAdvanced::CallDebugControllerDialog, [this, input_subsystem] {
CallConfigureDialog<ConfigureDebugController>(*this, input_subsystem, profiles.get(), connect(advanced, &ConfigureInputAdvanced::CallDebugControllerDialog,
system); [this, input_subsystem, &hid_core, is_powered_on] {
}); CallConfigureDialog<ConfigureDebugController>(
connect(advanced, &ConfigureInputAdvanced::CallMouseConfigDialog, [this, input_subsystem] { *this, input_subsystem, profiles.get(), hid_core, is_powered_on);
CallConfigureDialog<ConfigureMouseAdvanced>(*this, input_subsystem);
}); });
connect(advanced, &ConfigureInputAdvanced::CallTouchscreenConfigDialog, connect(advanced, &ConfigureInputAdvanced::CallTouchscreenConfigDialog,
[this] { CallConfigureDialog<ConfigureTouchscreenAdvanced>(*this); }); [this] { CallConfigureDialog<ConfigureTouchscreenAdvanced>(*this); });
@ -184,22 +187,8 @@ QList<QWidget*> ConfigureInput::GetSubTabs() const {
void ConfigureInput::ApplyConfiguration() { void ConfigureInput::ApplyConfiguration() {
for (auto* controller : player_controllers) { for (auto* controller : player_controllers) {
controller->ApplyConfiguration(); controller->ApplyConfiguration();
controller->TryDisconnectSelectedController();
} }
// This emulates a delay between disconnecting and reconnecting controllers as some games
// do not respond to a change in controller type if it was instantaneous.
using namespace std::chrono_literals;
std::this_thread::sleep_for(150ms);
for (auto* controller : player_controllers) {
controller->TryConnectSelectedController();
}
// This emulates a delay between disconnecting and reconnecting controllers as some games
// do not respond to a change in controller type if it was instantaneous.
std::this_thread::sleep_for(150ms);
advanced->ApplyConfiguration(); advanced->ApplyConfiguration();
const bool pre_docked_mode = Settings::values.use_docked_mode.GetValue(); const bool pre_docked_mode = Settings::values.use_docked_mode.GetValue();
@ -223,8 +212,10 @@ void ConfigureInput::RetranslateUI() {
} }
void ConfigureInput::LoadConfiguration() { void ConfigureInput::LoadConfiguration() {
const auto* handheld = system.HIDCore().GetEmulatedController(Core::HID::NpadIdType::Handheld);
LoadPlayerControllerIndices(); LoadPlayerControllerIndices();
UpdateDockedState(Settings::values.players.GetValue()[8].connected); UpdateDockedState(handheld->IsConnected());
ui->vibrationGroup->setChecked(Settings::values.vibration_enabled.GetValue()); ui->vibrationGroup->setChecked(Settings::values.vibration_enabled.GetValue());
ui->motionGroup->setChecked(Settings::values.motion_enabled.GetValue()); ui->motionGroup->setChecked(Settings::values.motion_enabled.GetValue());
@ -232,9 +223,16 @@ void ConfigureInput::LoadConfiguration() {
void ConfigureInput::LoadPlayerControllerIndices() { void ConfigureInput::LoadPlayerControllerIndices() {
for (std::size_t i = 0; i < player_connected.size(); ++i) { for (std::size_t i = 0; i < player_connected.size(); ++i) {
const auto connected = Settings::values.players.GetValue()[i].connected || if (i == 0) {
(i == 0 && Settings::values.players.GetValue()[8].connected); auto* handheld =
player_connected[i]->setChecked(connected); system.HIDCore().GetEmulatedController(Core::HID::NpadIdType::Handheld);
if (handheld->IsConnected()) {
player_connected[i]->setChecked(true);
continue;
}
}
const auto* controller = system.HIDCore().GetEmulatedControllerByIndex(i);
player_connected[i]->setChecked(controller->IsConnected());
} }
} }

View file

@ -82,7 +82,6 @@ ConfigureInputAdvanced::ConfigureInputAdvanced(QWidget* parent)
connect(ui->debug_configure, &QPushButton::clicked, this, connect(ui->debug_configure, &QPushButton::clicked, this,
[this] { CallDebugControllerDialog(); }); [this] { CallDebugControllerDialog(); });
connect(ui->mouse_advanced, &QPushButton::clicked, this, [this] { CallMouseConfigDialog(); });
connect(ui->touchscreen_advanced, &QPushButton::clicked, this, connect(ui->touchscreen_advanced, &QPushButton::clicked, this,
[this] { CallTouchscreenConfigDialog(); }); [this] { CallTouchscreenConfigDialog(); });
connect(ui->buttonMotionTouch, &QPushButton::clicked, this, connect(ui->buttonMotionTouch, &QPushButton::clicked, this,
@ -178,7 +177,6 @@ void ConfigureInputAdvanced::RetranslateUI() {
} }
void ConfigureInputAdvanced::UpdateUIEnabled() { void ConfigureInputAdvanced::UpdateUIEnabled() {
ui->mouse_advanced->setEnabled(ui->mouse_enabled->isChecked());
ui->debug_configure->setEnabled(ui->debug_enabled->isChecked()); ui->debug_configure->setEnabled(ui->debug_enabled->isChecked());
ui->touchscreen_advanced->setEnabled(ui->touchscreen_enabled->isChecked()); ui->touchscreen_advanced->setEnabled(ui->touchscreen_enabled->isChecked());
} }

View file

@ -2528,11 +2528,11 @@
<number>0</number> <number>0</number>
</property> </property>
<item> <item>
<widget class="QGroupBox" name="gridGroupBox_3"> <widget class="QGroupBox" name="emulatedDevicesGroupBox">
<property name="title"> <property name="title">
<string>Other</string> <string>Emulated Devices</string>
</property> </property>
<layout class="QGridLayout" name="gridLayout_3"> <layout class="QGridLayout" name="emulatedDevicesGridLayout">
<item row="0" column="0"> <item row="0" column="0">
<widget class="QCheckBox" name="keyboard_enabled"> <widget class="QCheckBox" name="keyboard_enabled">
<property name="minimumSize"> <property name="minimumSize">
@ -2546,6 +2546,72 @@
</property> </property>
</widget> </widget>
</item> </item>
<item row="1" column="0">
<widget class="QCheckBox" name="mouse_enabled">
<property name="minimumSize">
<size>
<width>0</width>
<height>23</height>
</size>
</property>
<property name="text">
<string>Mouse</string>
</property>
</widget>
</item>
<item row="2" column="0">
<widget class="QCheckBox" name="touchscreen_enabled">
<property name="text">
<string>Touchscreen</string>
</property>
</widget>
</item>
<item row="2" column="1">
<spacer name="horizontalSpacer_8">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>76</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="2" column="2">
<widget class="QPushButton" name="touchscreen_advanced">
<property name="text">
<string>Advanced</string>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QCheckBox" name="debug_enabled">
<property name="text">
<string>Debug Controller</string>
</property>
</widget>
</item>
<item row="3" column="2">
<widget class="QPushButton" name="debug_configure">
<property name="text">
<string>Configure</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="otherGroupBox">
<property name="title">
<string>Other</string>
</property>
<layout class="QGridLayout" name="OtherGridLayout">
<item row="1" column="0"> <item row="1" column="0">
<widget class="QCheckBox" name="emulate_analog_keyboard"> <widget class="QCheckBox" name="emulate_analog_keyboard">
<property name="minimumSize"> <property name="minimumSize">
@ -2560,6 +2626,22 @@
</widget> </widget>
</item> </item>
<item row="2" column="0"> <item row="2" column="0">
<widget class="QCheckBox" name="enable_raw_input">
<property name="toolTip">
<string>Requires restarting yuzu</string>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>23</height>
</size>
</property>
<property name="text">
<string>Enable XInput 8 player support (disables web applet)</string>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QCheckBox" name="mouse_panning"> <widget class="QCheckBox" name="mouse_panning">
<property name="minimumSize"> <property name="minimumSize">
<size> <size>
@ -2572,7 +2654,7 @@
</property> </property>
</widget> </widget>
</item> </item>
<item row="2" column="2"> <item row="3" column="2">
<widget class="QSpinBox" name="mouse_panning_sensitivity"> <widget class="QSpinBox" name="mouse_panning_sensitivity">
<property name="toolTip"> <property name="toolTip">
<string>Mouse sensitivity</string> <string>Mouse sensitivity</string>
@ -2594,100 +2676,20 @@
</property> </property>
</widget> </widget>
</item> </item>
<item row="6" column="2"> <item row="4" column="0">
<widget class="QPushButton" name="touchscreen_advanced">
<property name="text">
<string>Advanced</string>
</property>
</widget>
</item>
<item row="3" column="1">
<spacer name="horizontalSpacer_8">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::Fixed</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>76</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item row="3" column="2">
<widget class="QPushButton" name="mouse_advanced">
<property name="text">
<string>Advanced</string>
</property>
</widget>
</item>
<item row="6" column="0">
<widget class="QCheckBox" name="touchscreen_enabled">
<property name="text">
<string>Touchscreen</string>
</property>
</widget>
</item>
<item row="3" column="0">
<widget class="QCheckBox" name="mouse_enabled">
<property name="minimumSize">
<size>
<width>0</width>
<height>23</height>
</size>
</property>
<property name="text">
<string>Mouse</string>
</property>
</widget>
</item>
<item row="8" column="0">
<widget class="QLabel" name="motion_touch"> <widget class="QLabel" name="motion_touch">
<property name="text"> <property name="text">
<string>Motion / Touch</string> <string>Motion / Touch</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="8" column="2"> <item row="4" column="2">
<widget class="QPushButton" name="buttonMotionTouch"> <widget class="QPushButton" name="buttonMotionTouch">
<property name="text"> <property name="text">
<string>Configure</string> <string>Configure</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="7" column="0">
<widget class="QCheckBox" name="debug_enabled">
<property name="text">
<string>Debug Controller</string>
</property>
</widget>
</item>
<item row="7" column="2">
<widget class="QPushButton" name="debug_configure">
<property name="text">
<string>Configure</string>
</property>
</widget>
</item>
<item row="9" column="0">
<widget class="QCheckBox" name="enable_raw_input">
<property name="toolTip">
<string>Requires restarting yuzu</string>
</property>
<property name="minimumSize">
<size>
<width>0</width>
<height>23</height>
</size>
</property>
<property name="text">
<string>Enable XInput 8 player support (disables web applet)</string>
</property>
</widget>
</item>
</layout> </layout>
</widget> </widget>
</item> </item>

File diff suppressed because it is too large Load diff

View file

@ -29,48 +29,37 @@ class QWidget;
class InputProfiles; class InputProfiles;
namespace Core {
class System;
}
namespace InputCommon { namespace InputCommon {
class InputSubsystem; class InputSubsystem;
} }
namespace InputCommon::Polling { namespace InputCommon::Polling {
class DevicePoller; enum class InputType;
enum class DeviceType;
} // namespace InputCommon::Polling } // namespace InputCommon::Polling
namespace Ui { namespace Ui {
class ConfigureInputPlayer; class ConfigureInputPlayer;
} }
namespace Core::HID {
class HIDCore;
class EmulatedController;
enum class NpadStyleIndex : u8;
} // namespace Core::HID
class ConfigureInputPlayer : public QWidget { class ConfigureInputPlayer : public QWidget {
Q_OBJECT Q_OBJECT
public: public:
explicit ConfigureInputPlayer(QWidget* parent, std::size_t player_index, QWidget* bottom_row, explicit ConfigureInputPlayer(QWidget* parent, std::size_t player_index, QWidget* bottom_row,
InputCommon::InputSubsystem* input_subsystem_, InputCommon::InputSubsystem* input_subsystem_,
InputProfiles* profiles_, Core::System& system_, InputProfiles* profiles_, Core::HID::HIDCore& hid_core_,
bool debug = false); bool is_powered_on_, bool debug = false);
~ConfigureInputPlayer() override; ~ConfigureInputPlayer() override;
/// Save all button configurations to settings file. /// Save all button configurations to settings file.
void ApplyConfiguration(); void ApplyConfiguration();
/**
* Attempts to connect the currently selected controller in the HID backend.
* This function will not do anything if it is not connected in the frontend.
*/
void TryConnectSelectedController();
/**
* Attempts to disconnect the currently selected controller in the HID backend.
* This function will not do anything if the configuration has not changed.
*/
void TryDisconnectSelectedController();
/// Set the connection state checkbox (used to sync state). /// Set the connection state checkbox (used to sync state).
void ConnectPlayer(bool connected); void ConnectPlayer(bool connected);
@ -104,6 +93,10 @@ protected:
void showEvent(QShowEvent* event) override; void showEvent(QShowEvent* event) override;
private: private:
QString ButtonToText(const Common::ParamPackage& param);
QString AnalogToText(const Common::ParamPackage& param, const std::string& dir);
void changeEvent(QEvent* event) override; void changeEvent(QEvent* event) override;
void RetranslateUI(); void RetranslateUI();
@ -113,7 +106,7 @@ private:
/// Called when the button was pressed. /// Called when the button was pressed.
void HandleClick(QPushButton* button, std::size_t button_id, void HandleClick(QPushButton* button, std::size_t button_id,
std::function<void(const Common::ParamPackage&)> new_input_setter, std::function<void(const Common::ParamPackage&)> new_input_setter,
InputCommon::Polling::DeviceType type); InputCommon::Polling::InputType type);
/// Finish polling and configure input using the input_setter. /// Finish polling and configure input using the input_setter.
void SetPollingResult(const Common::ParamPackage& params, bool abort); void SetPollingResult(const Common::ParamPackage& params, bool abort);
@ -134,17 +127,14 @@ private:
void SetConnectableControllers(); void SetConnectableControllers();
/// Gets the Controller Type for a given controller combobox index. /// Gets the Controller Type for a given controller combobox index.
Settings::ControllerType GetControllerTypeFromIndex(int index) const; Core::HID::NpadStyleIndex GetControllerTypeFromIndex(int index) const;
/// Gets the controller combobox index for a given Controller Type. /// Gets the controller combobox index for a given Controller Type.
int GetIndexFromControllerType(Settings::ControllerType type) const; int GetIndexFromControllerType(Core::HID::NpadStyleIndex type) const;
/// Update the available input devices. /// Update the available input devices.
void UpdateInputDevices(); void UpdateInputDevices();
/// Update the current controller icon.
void UpdateControllerIcon();
/// Hides and disables controller settings based on the current controller type. /// Hides and disables controller settings based on the current controller type.
void UpdateControllerAvailableButtons(); void UpdateControllerAvailableButtons();
@ -176,6 +166,7 @@ private:
std::size_t player_index; std::size_t player_index;
bool debug; bool debug;
bool is_powered_on;
InputCommon::InputSubsystem* input_subsystem; InputCommon::InputSubsystem* input_subsystem;
@ -185,7 +176,7 @@ private:
std::unique_ptr<QTimer> poll_timer; std::unique_ptr<QTimer> poll_timer;
/// Stores a pair of "Connected Controllers" combobox index and Controller Type enum. /// Stores a pair of "Connected Controllers" combobox index and Controller Type enum.
std::vector<std::pair<int, Settings::ControllerType>> index_controller_type_pairs; std::vector<std::pair<int, Core::HID::NpadStyleIndex>> index_controller_type_pairs;
static constexpr int PLAYER_COUNT = 8; static constexpr int PLAYER_COUNT = 8;
std::array<QCheckBox*, PLAYER_COUNT> player_connected_checkbox; std::array<QCheckBox*, PLAYER_COUNT> player_connected_checkbox;
@ -193,9 +184,7 @@ private:
/// This will be the the setting function when an input is awaiting configuration. /// This will be the the setting function when an input is awaiting configuration.
std::optional<std::function<void(const Common::ParamPackage&)>> input_setter; std::optional<std::function<void(const Common::ParamPackage&)>> input_setter;
std::array<Common::ParamPackage, Settings::NativeButton::NumButtons> buttons_param; Core::HID::EmulatedController* emulated_controller;
std::array<Common::ParamPackage, Settings::NativeAnalog::NumAnalogs> analogs_param;
std::array<Common::ParamPackage, Settings::NativeMotion::NumMotions> motions_param;
static constexpr int ANALOG_SUB_BUTTONS_NUM = 4; static constexpr int ANALOG_SUB_BUTTONS_NUM = 4;
@ -221,15 +210,9 @@ private:
static const std::array<std::string, ANALOG_SUB_BUTTONS_NUM> analog_sub_buttons; static const std::array<std::string, ANALOG_SUB_BUTTONS_NUM> analog_sub_buttons;
std::vector<std::unique_ptr<InputCommon::Polling::DevicePoller>> device_pollers;
/// A flag to indicate that the "Map Analog Stick" pop-up has been shown and accepted once. /// A flag to indicate that the "Map Analog Stick" pop-up has been shown and accepted once.
bool map_analog_stick_accepted{}; bool map_analog_stick_accepted{};
/// A flag to indicate if keyboard keys are okay when configuring an input. If this is false,
/// keyboard events are ignored.
bool want_keyboard_mouse{};
/// List of physical devices users can map with. If a SDL backed device is selected, then you /// List of physical devices users can map with. If a SDL backed device is selected, then you
/// can use this device to get a default mapping. /// can use this device to get a default mapping.
std::vector<Common::ParamPackage> input_devices; std::vector<Common::ParamPackage> input_devices;
@ -239,5 +222,5 @@ private:
/// parent of the widget to this widget (but thats fine). /// parent of the widget to this widget (but thats fine).
QWidget* bottom_row; QWidget* bottom_row;
Core::System& system; Core::HID::HIDCore& hid_core;
}; };

View file

@ -89,31 +89,6 @@
<height>21</height> <height>21</height>
</size> </size>
</property> </property>
<item>
<property name="text">
<string>Pro Controller</string>
</property>
</item>
<item>
<property name="text">
<string>Dual Joycons</string>
</property>
</item>
<item>
<property name="text">
<string>Left Joycon</string>
</property>
</item>
<item>
<property name="text">
<string>Right Joycon</string>
</property>
</item>
<item>
<property name="text">
<string>Handheld</string>
</property>
</item>
</widget> </widget>
</item> </item>
</layout> </layout>
@ -142,22 +117,9 @@
</property> </property>
<item> <item>
<widget class="QComboBox" name="comboDevices"> <widget class="QComboBox" name="comboDevices">
<property name="minimumSize"> <property name="minimumContentsLength">
<size> <number>60</number>
<width>0</width>
<height>21</height>
</size>
</property> </property>
<item>
<property name="text">
<string>Any</string>
</property>
</item>
<item>
<property name="text">
<string>Keyboard/Mouse</string>
</property>
</item>
</widget> </widget>
</item> </item>
<item> <item>
@ -342,7 +304,7 @@
<number>3</number> <number>3</number>
</property> </property>
<property name="topMargin"> <property name="topMargin">
<number>0</number> <number>6</number>
</property> </property>
<property name="rightMargin"> <property name="rightMargin">
<number>3</number> <number>3</number>
@ -918,7 +880,7 @@
<number>3</number> <number>3</number>
</property> </property>
<property name="topMargin"> <property name="topMargin">
<number>0</number> <number>6</number>
</property> </property>
<property name="rightMargin"> <property name="rightMargin">
<number>3</number> <number>3</number>
@ -2221,7 +2183,7 @@
<number>3</number> <number>3</number>
</property> </property>
<property name="topMargin"> <property name="topMargin">
<number>0</number> <number>6</number>
</property> </property>
<property name="rightMargin"> <property name="rightMargin">
<number>3</number> <number>3</number>
@ -2570,7 +2532,7 @@
<number>3</number> <number>3</number>
</property> </property>
<property name="topMargin"> <property name="topMargin">
<number>0</number> <number>6</number>
</property> </property>
<property name="rightMargin"> <property name="rightMargin">
<number>3</number> <number>3</number>

File diff suppressed because it is too large Load diff

View file

@ -7,9 +7,11 @@
#include <array> #include <array>
#include <QFrame> #include <QFrame>
#include <QPointer> #include <QPointer>
#include "common/settings.h"
#include "core/frontend/input.h" #include "common/input.h"
#include "yuzu/debugger/controller.h" #include "common/settings_input.h"
#include "core/hid/emulated_controller.h"
#include "core/hid/hid_types.h"
class QLabel; class QLabel;
@ -24,17 +26,26 @@ public:
explicit PlayerControlPreview(QWidget* parent); explicit PlayerControlPreview(QWidget* parent);
~PlayerControlPreview() override; ~PlayerControlPreview() override;
void SetPlayerInput(std::size_t index, const ButtonParam& buttons_param, // Sets the emulated controller to be displayed
const AnalogParam& analogs_param); void SetController(Core::HID::EmulatedController* controller);
void SetPlayerInputRaw(std::size_t index, const Settings::ButtonsRaw& buttons_,
Settings::AnalogsRaw analogs_); // Disables events from the emulated controller
void SetConnectedStatus(bool checked); void UnloadController();
void SetControllerType(Settings::ControllerType type);
// Starts blinking animation at the button specified
void BeginMappingButton(std::size_t button_id); void BeginMappingButton(std::size_t button_id);
void BeginMappingAnalog(std::size_t button_id);
// Starts moving animation at the stick specified
void BeginMappingAnalog(std::size_t stick_id);
// Stops any ongoing animation
void EndMapping(); void EndMapping();
// Handles emulated controller events
void ControllerUpdate(Core::HID::ControllerTriggerType type);
// Updates input on sheduled interval
void UpdateInput(); void UpdateInput();
void SetCallBack(ControllerCallback callback_);
protected: protected:
void paintEvent(QPaintEvent* event) override; void paintEvent(QPaintEvent* event) override;
@ -63,22 +74,6 @@ private:
SR, SR,
}; };
struct AxisValue {
QPointF value{};
QPointF raw_value{};
Input::AnalogProperties properties{};
int size{};
QPoint offset{};
bool active{};
};
struct LedPattern {
bool position1;
bool position2;
bool position3;
bool position4;
};
struct ColorMapping { struct ColorMapping {
QColor outline{}; QColor outline{};
QColor primary{}; QColor primary{};
@ -101,7 +96,6 @@ private:
QColor deadzone{}; QColor deadzone{};
}; };
static LedPattern GetColorPattern(std::size_t index, bool player_on);
void UpdateColors(); void UpdateColors();
void ResetInputs(); void ResetInputs();
@ -122,47 +116,75 @@ private:
void DrawGCBody(QPainter& p, QPointF center); void DrawGCBody(QPainter& p, QPointF center);
// Draw triggers functions // Draw triggers functions
void DrawProTriggers(QPainter& p, QPointF center, bool left_pressed, bool right_pressed); void DrawProTriggers(QPainter& p, QPointF center,
void DrawGCTriggers(QPainter& p, QPointF center, bool left_pressed, bool right_pressed); const Common::Input::ButtonStatus& left_pressed,
void DrawHandheldTriggers(QPainter& p, QPointF center, bool left_pressed, bool right_pressed); const Common::Input::ButtonStatus& right_pressed);
void DrawDualTriggers(QPainter& p, QPointF center, bool left_pressed, bool right_pressed); void DrawGCTriggers(QPainter& p, QPointF center, Common::Input::TriggerStatus left_trigger,
void DrawDualTriggersTopView(QPainter& p, QPointF center, bool left_pressed, Common::Input::TriggerStatus right_trigger);
bool right_pressed); void DrawHandheldTriggers(QPainter& p, QPointF center,
void DrawDualZTriggersTopView(QPainter& p, QPointF center, bool left_pressed, const Common::Input::ButtonStatus& left_pressed,
bool right_pressed); const Common::Input::ButtonStatus& right_pressed);
void DrawLeftTriggers(QPainter& p, QPointF center, bool left_pressed); void DrawDualTriggers(QPainter& p, QPointF center,
void DrawLeftZTriggers(QPainter& p, QPointF center, bool left_pressed); const Common::Input::ButtonStatus& left_pressed,
void DrawLeftTriggersTopView(QPainter& p, QPointF center, bool left_pressed); const Common::Input::ButtonStatus& right_pressed);
void DrawLeftZTriggersTopView(QPainter& p, QPointF center, bool left_pressed); void DrawDualTriggersTopView(QPainter& p, QPointF center,
void DrawRightTriggers(QPainter& p, QPointF center, bool right_pressed); const Common::Input::ButtonStatus& left_pressed,
void DrawRightZTriggers(QPainter& p, QPointF center, bool right_pressed); const Common::Input::ButtonStatus& right_pressed);
void DrawRightTriggersTopView(QPainter& p, QPointF center, bool right_pressed); void DrawDualZTriggersTopView(QPainter& p, QPointF center,
void DrawRightZTriggersTopView(QPainter& p, QPointF center, bool right_pressed); const Common::Input::ButtonStatus& left_pressed,
const Common::Input::ButtonStatus& right_pressed);
void DrawLeftTriggers(QPainter& p, QPointF center,
const Common::Input::ButtonStatus& left_pressed);
void DrawLeftZTriggers(QPainter& p, QPointF center,
const Common::Input::ButtonStatus& left_pressed);
void DrawLeftTriggersTopView(QPainter& p, QPointF center,
const Common::Input::ButtonStatus& left_pressed);
void DrawLeftZTriggersTopView(QPainter& p, QPointF center,
const Common::Input::ButtonStatus& left_pressed);
void DrawRightTriggers(QPainter& p, QPointF center,
const Common::Input::ButtonStatus& right_pressed);
void DrawRightZTriggers(QPainter& p, QPointF center,
const Common::Input::ButtonStatus& right_pressed);
void DrawRightTriggersTopView(QPainter& p, QPointF center,
const Common::Input::ButtonStatus& right_pressed);
void DrawRightZTriggersTopView(QPainter& p, QPointF center,
const Common::Input::ButtonStatus& right_pressed);
// Draw joystick functions // Draw joystick functions
void DrawJoystick(QPainter& p, QPointF center, float size, bool pressed); void DrawJoystick(QPainter& p, QPointF center, float size,
void DrawJoystickSideview(QPainter& p, QPointF center, float angle, float size, bool pressed); const Common::Input::ButtonStatus& pressed);
void DrawJoystickSideview(QPainter& p, QPointF center, float angle, float size,
const Common::Input::ButtonStatus& pressed);
void DrawRawJoystick(QPainter& p, QPointF center_left, QPointF center_right); void DrawRawJoystick(QPainter& p, QPointF center_left, QPointF center_right);
void DrawJoystickProperties(QPainter& p, QPointF center, void DrawJoystickProperties(QPainter& p, QPointF center,
const Input::AnalogProperties& properties); const Common::Input::AnalogProperties& properties);
void DrawJoystickDot(QPainter& p, QPointF center, QPointF value, void DrawJoystickDot(QPainter& p, QPointF center, const Common::Input::StickStatus& stick,
const Input::AnalogProperties& properties); bool raw);
void DrawProJoystick(QPainter& p, QPointF center, QPointF offset, float scalar, bool pressed); void DrawProJoystick(QPainter& p, QPointF center, QPointF offset, float scalar,
void DrawGCJoystick(QPainter& p, QPointF center, bool pressed); const Common::Input::ButtonStatus& pressed);
void DrawGCJoystick(QPainter& p, QPointF center, const Common::Input::ButtonStatus& pressed);
// Draw button functions // Draw button functions
void DrawCircleButton(QPainter& p, QPointF center, bool pressed, float button_size); void DrawCircleButton(QPainter& p, QPointF center, const Common::Input::ButtonStatus& pressed,
void DrawRoundButton(QPainter& p, QPointF center, bool pressed, float width, float height, float button_size);
Direction direction = Direction::None, float radius = 2); void DrawRoundButton(QPainter& p, QPointF center, const Common::Input::ButtonStatus& pressed,
void DrawMinusButton(QPainter& p, QPointF center, bool pressed, int button_size); float width, float height, Direction direction = Direction::None,
void DrawPlusButton(QPainter& p, QPointF center, bool pressed, int button_size); float radius = 2);
void DrawGCButtonX(QPainter& p, QPointF center, bool pressed); void DrawMinusButton(QPainter& p, QPointF center, const Common::Input::ButtonStatus& pressed,
void DrawGCButtonY(QPainter& p, QPointF center, bool pressed); int button_size);
void DrawGCButtonZ(QPainter& p, QPointF center, bool pressed); void DrawPlusButton(QPainter& p, QPointF center, const Common::Input::ButtonStatus& pressed,
int button_size);
void DrawGCButtonX(QPainter& p, QPointF center, const Common::Input::ButtonStatus& pressed);
void DrawGCButtonY(QPainter& p, QPointF center, const Common::Input::ButtonStatus& pressed);
void DrawGCButtonZ(QPainter& p, QPointF center, const Common::Input::ButtonStatus& pressed);
void DrawArrowButtonOutline(QPainter& p, const QPointF center, float size = 1.0f); void DrawArrowButtonOutline(QPainter& p, const QPointF center, float size = 1.0f);
void DrawArrowButton(QPainter& p, QPointF center, Direction direction, bool pressed, void DrawArrowButton(QPainter& p, QPointF center, Direction direction,
float size = 1.0f); const Common::Input::ButtonStatus& pressed, float size = 1.0f);
void DrawTriggerButton(QPainter& p, QPointF center, Direction direction, bool pressed); void DrawTriggerButton(QPainter& p, QPointF center, Direction direction,
const Common::Input::ButtonStatus& pressed);
// Draw battery functions
void DrawBattery(QPainter& p, QPointF center, Common::Input::BatteryLevel battery);
// Draw icon functions // Draw icon functions
void DrawSymbol(QPainter& p, QPointF center, Symbol symbol, float icon_size); void DrawSymbol(QPainter& p, QPointF center, Symbol symbol, float icon_size);
@ -178,24 +200,23 @@ private:
void SetTextFont(QPainter& p, float text_size, void SetTextFont(QPainter& p, float text_size,
const QString& font_family = QStringLiteral("sans-serif")); const QString& font_family = QStringLiteral("sans-serif"));
using ButtonArray = bool is_controller_set{};
std::array<std::unique_ptr<Input::ButtonDevice>, Settings::NativeButton::BUTTON_NS_END>; bool is_connected{};
using StickArray = bool needs_redraw{};
std::array<std::unique_ptr<Input::AnalogDevice>, Settings::NativeAnalog::NUM_STICKS_HID>; Core::HID::NpadStyleIndex controller_type;
ControllerCallback controller_callback;
bool is_enabled{};
bool mapping_active{}; bool mapping_active{};
int blink_counter{}; int blink_counter{};
int callback_key;
QColor button_color{}; QColor button_color{};
ColorMapping colors{}; ColorMapping colors{};
std::array<QColor, 4> led_color{}; Core::HID::LedPattern led_pattern{0, 0, 0, 0};
ButtonArray buttons{};
StickArray sticks{};
std::size_t player_index{}; std::size_t player_index{};
std::size_t button_mapping_index{Settings::NativeButton::BUTTON_NS_END}; Core::HID::EmulatedController* controller;
std::size_t analog_mapping_index{Settings::NativeAnalog::NUM_STICKS_HID}; std::size_t button_mapping_index{Settings::NativeButton::NumButtons};
std::array<AxisValue, Settings::NativeAnalog::NUM_STICKS_HID> axis_values{}; std::size_t analog_mapping_index{Settings::NativeAnalog::NumAnalogs};
std::array<bool, Settings::NativeButton::NumButtons> button_values{}; Core::HID::ButtonValues button_values{};
Settings::ControllerType controller_type{Settings::ControllerType::ProController}; Core::HID::SticksValues stick_values{};
Core::HID::TriggerValues trigger_values{};
Core::HID::BatteryValues battery_values{};
}; };

View file

@ -11,8 +11,8 @@ ConfigureInputProfileDialog::ConfigureInputProfileDialog(
QWidget* parent, InputCommon::InputSubsystem* input_subsystem, InputProfiles* profiles, QWidget* parent, InputCommon::InputSubsystem* input_subsystem, InputProfiles* profiles,
Core::System& system) Core::System& system)
: QDialog(parent), ui(std::make_unique<Ui::ConfigureInputProfileDialog>()), : QDialog(parent), ui(std::make_unique<Ui::ConfigureInputProfileDialog>()),
profile_widget( profile_widget(new ConfigureInputPlayer(this, 9, nullptr, input_subsystem, profiles,
new ConfigureInputPlayer(this, 9, nullptr, input_subsystem, profiles, system, false)) { system.HIDCore(), system.IsPoweredOn(), false)) {
ui->setupUi(this); ui->setupUi(this);
ui->controllerLayout->addWidget(profile_widget); ui->controllerLayout->addWidget(profile_widget);

View file

@ -15,9 +15,9 @@
#include "common/logging/log.h" #include "common/logging/log.h"
#include "common/settings.h" #include "common/settings.h"
#include "input_common/drivers/udp_client.h"
#include "input_common/helpers/udp_protocol.h"
#include "input_common/main.h" #include "input_common/main.h"
#include "input_common/udp/client.h"
#include "input_common/udp/udp.h"
#include "ui_configure_motion_touch.h" #include "ui_configure_motion_touch.h"
#include "yuzu/configuration/configure_motion_touch.h" #include "yuzu/configuration/configure_motion_touch.h"
#include "yuzu/configuration/configure_touch_from_button.h" #include "yuzu/configuration/configure_touch_from_button.h"
@ -93,6 +93,7 @@ ConfigureMotionTouch::ConfigureMotionTouch(QWidget* parent,
"using-a-controller-or-android-phone-for-motion-or-touch-input'><span " "using-a-controller-or-android-phone-for-motion-or-touch-input'><span "
"style=\"text-decoration: underline; color:#039be5;\">Learn More</span></a>")); "style=\"text-decoration: underline; color:#039be5;\">Learn More</span></a>"));
setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
SetConfiguration(); SetConfiguration();
UpdateUiDisplay(); UpdateUiDisplay();
ConnectEvents(); ConnectEvents();
@ -101,17 +102,14 @@ ConfigureMotionTouch::ConfigureMotionTouch(QWidget* parent,
ConfigureMotionTouch::~ConfigureMotionTouch() = default; ConfigureMotionTouch::~ConfigureMotionTouch() = default;
void ConfigureMotionTouch::SetConfiguration() { void ConfigureMotionTouch::SetConfiguration() {
const Common::ParamPackage motion_param(Settings::values.motion_device.GetValue());
const Common::ParamPackage touch_param(Settings::values.touch_device.GetValue()); const Common::ParamPackage touch_param(Settings::values.touch_device.GetValue());
ui->touch_from_button_checkbox->setChecked(Settings::values.use_touch_from_button.GetValue());
touch_from_button_maps = Settings::values.touch_from_button_maps; touch_from_button_maps = Settings::values.touch_from_button_maps;
for (const auto& touch_map : touch_from_button_maps) { for (const auto& touch_map : touch_from_button_maps) {
ui->touch_from_button_map->addItem(QString::fromStdString(touch_map.name)); ui->touch_from_button_map->addItem(QString::fromStdString(touch_map.name));
} }
ui->touch_from_button_map->setCurrentIndex( ui->touch_from_button_map->setCurrentIndex(
Settings::values.touch_from_button_map_index.GetValue()); Settings::values.touch_from_button_map_index.GetValue());
ui->motion_sensitivity->setValue(motion_param.Get("sensitivity", 0.01f));
min_x = touch_param.Get("min_x", 100); min_x = touch_param.Get("min_x", 100);
min_y = touch_param.Get("min_y", 50); min_y = touch_param.Get("min_y", 50);
@ -139,9 +137,6 @@ void ConfigureMotionTouch::SetConfiguration() {
void ConfigureMotionTouch::UpdateUiDisplay() { void ConfigureMotionTouch::UpdateUiDisplay() {
const QString cemuhook_udp = QStringLiteral("cemuhookudp"); const QString cemuhook_udp = QStringLiteral("cemuhookudp");
ui->motion_sensitivity_label->setVisible(true);
ui->motion_sensitivity->setVisible(true);
ui->touch_calibration->setVisible(true); ui->touch_calibration->setVisible(true);
ui->touch_calibration_config->setVisible(true); ui->touch_calibration_config->setVisible(true);
ui->touch_calibration_label->setVisible(true); ui->touch_calibration_label->setVisible(true);
@ -312,7 +307,6 @@ void ConfigureMotionTouch::ApplyConfiguration() {
touch_param.Set("max_y", max_y); touch_param.Set("max_y", max_y);
Settings::values.touch_device = touch_param.Serialize(); Settings::values.touch_device = touch_param.Serialize();
Settings::values.use_touch_from_button = ui->touch_from_button_checkbox->isChecked();
Settings::values.touch_from_button_map_index = ui->touch_from_button_map->currentIndex(); Settings::values.touch_from_button_map_index = ui->touch_from_button_map->currentIndex();
Settings::values.touch_from_button_maps = touch_from_button_maps; Settings::values.touch_from_button_maps = touch_from_button_maps;
Settings::values.udp_input_servers = GetUDPServerString(); Settings::values.udp_input_servers = GetUDPServerString();

View file

@ -2,14 +2,6 @@
<ui version="4.0"> <ui version="4.0">
<class>ConfigureMotionTouch</class> <class>ConfigureMotionTouch</class>
<widget class="QDialog" name="ConfigureMotionTouch"> <widget class="QDialog" name="ConfigureMotionTouch">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>500</width>
<height>482</height>
</rect>
</property>
<property name="windowTitle"> <property name="windowTitle">
<string>Configure Motion / Touch</string> <string>Configure Motion / Touch</string>
</property> </property>
@ -17,48 +9,6 @@
<string notr="true"/> <string notr="true"/>
</property> </property>
<layout class="QVBoxLayout"> <layout class="QVBoxLayout">
<item>
<widget class="QGroupBox" name="motion_group_box">
<property name="title">
<string>Mouse Motion</string>
</property>
<layout class="QVBoxLayout">
<item>
<layout class="QHBoxLayout">
<item>
<widget class="QLabel" name="motion_sensitivity_label">
<property name="text">
<string>Sensitivity:</string>
</property>
</widget>
</item>
<item>
<widget class="QDoubleSpinBox" name="motion_sensitivity">
<property name="alignment">
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
</property>
<property name="decimals">
<number>4</number>
</property>
<property name="minimum">
<double>0.010000000000000</double>
</property>
<property name="maximum">
<double>10.000000000000000</double>
</property>
<property name="singleStep">
<double>0.001000000000000</double>
</property>
<property name="value">
<double>0.010000000000000</double>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
</item>
<item> <item>
<widget class="QGroupBox" name="touch_group_box"> <widget class="QGroupBox" name="touch_group_box">
<property name="title"> <property name="title">
@ -102,15 +52,9 @@
<item> <item>
<layout class="QHBoxLayout"> <layout class="QHBoxLayout">
<item> <item>
<widget class="QCheckBox" name="touch_from_button_checkbox"> <widget class="QLabel" name="touch_from_button_label">
<property name="sizePolicy">
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="text"> <property name="text">
<string>Use button mapping:</string> <string>Touch from button profile:</string>
</property> </property>
</widget> </widget>
</item> </item>

View file

@ -32,7 +32,6 @@ void ConfigureTasDialog::LoadConfiguration() {
ui->tas_path_edit->setText( ui->tas_path_edit->setText(
QString::fromStdString(Common::FS::GetYuzuPathString(Common::FS::YuzuPath::TASDir))); QString::fromStdString(Common::FS::GetYuzuPathString(Common::FS::YuzuPath::TASDir)));
ui->tas_enable->setChecked(Settings::values.tas_enable.GetValue()); ui->tas_enable->setChecked(Settings::values.tas_enable.GetValue());
ui->tas_control_swap->setChecked(Settings::values.tas_swap_controllers.GetValue());
ui->tas_loop_script->setChecked(Settings::values.tas_loop.GetValue()); ui->tas_loop_script->setChecked(Settings::values.tas_loop.GetValue());
ui->tas_pause_on_load->setChecked(Settings::values.pause_tas_on_load.GetValue()); ui->tas_pause_on_load->setChecked(Settings::values.pause_tas_on_load.GetValue());
} }
@ -40,7 +39,6 @@ void ConfigureTasDialog::LoadConfiguration() {
void ConfigureTasDialog::ApplyConfiguration() { void ConfigureTasDialog::ApplyConfiguration() {
Common::FS::SetYuzuPath(Common::FS::YuzuPath::TASDir, ui->tas_path_edit->text().toStdString()); Common::FS::SetYuzuPath(Common::FS::YuzuPath::TASDir, ui->tas_path_edit->text().toStdString());
Settings::values.tas_enable.SetValue(ui->tas_enable->isChecked()); Settings::values.tas_enable.SetValue(ui->tas_enable->isChecked());
Settings::values.tas_swap_controllers.SetValue(ui->tas_control_swap->isChecked());
Settings::values.tas_loop.SetValue(ui->tas_loop_script->isChecked()); Settings::values.tas_loop.SetValue(ui->tas_loop_script->isChecked());
Settings::values.pause_tas_on_load.SetValue(ui->tas_pause_on_load->isChecked()); Settings::values.pause_tas_on_load.SetValue(ui->tas_pause_on_load->isChecked());
} }

View file

@ -59,20 +59,13 @@
</widget> </widget>
</item> </item>
<item row="1" column="0" colspan="4"> <item row="1" column="0" colspan="4">
<widget class="QCheckBox" name="tas_control_swap">
<property name="text">
<string>Automatic controller profile swapping</string>
</property>
</widget>
</item>
<item row="2" column="0" colspan="4">
<widget class="QCheckBox" name="tas_loop_script"> <widget class="QCheckBox" name="tas_loop_script">
<property name="text"> <property name="text">
<string>Loop script</string> <string>Loop script</string>
</property> </property>
</widget> </widget>
</item> </item>
<item row="3" column="0" colspan="4"> <item row="2" column="0" colspan="4">
<widget class="QCheckBox" name="tas_pause_on_load"> <widget class="QCheckBox" name="tas_pause_on_load">
<property name="enabled"> <property name="enabled">
<bool>false</bool> <bool>false</bool>

View file

@ -163,14 +163,11 @@ void ConfigureTouchFromButton::ConnectEvents() {
connect(timeout_timer.get(), &QTimer::timeout, [this]() { SetPollingResult({}, true); }); connect(timeout_timer.get(), &QTimer::timeout, [this]() { SetPollingResult({}, true); });
connect(poll_timer.get(), &QTimer::timeout, [this]() { connect(poll_timer.get(), &QTimer::timeout, [this]() {
Common::ParamPackage params; const auto& params = input_subsystem->GetNextInput();
for (auto& poller : device_pollers) {
params = poller->GetNextInput();
if (params.Has("engine")) { if (params.Has("engine")) {
SetPollingResult(params, false); SetPollingResult(params, false);
return; return;
} }
}
}); });
} }
@ -248,11 +245,7 @@ void ConfigureTouchFromButton::GetButtonInput(const int row_index, const bool is
} }
}; };
device_pollers = input_subsystem->GetPollers(InputCommon::Polling::DeviceType::Button); input_subsystem->BeginMapping(InputCommon::Polling::InputType::Button);
for (auto& poller : device_pollers) {
poller->Start();
}
grabKeyboard(); grabKeyboard();
grabMouse(); grabMouse();
@ -365,14 +358,14 @@ void ConfigureTouchFromButton::SetCoordinates(const int dot_id, const QPoint& po
void ConfigureTouchFromButton::SetPollingResult(const Common::ParamPackage& params, void ConfigureTouchFromButton::SetPollingResult(const Common::ParamPackage& params,
const bool cancel) { const bool cancel) {
timeout_timer->stop();
poll_timer->stop();
input_subsystem->StopMapping();
releaseKeyboard(); releaseKeyboard();
releaseMouse(); releaseMouse();
qApp->restoreOverrideCursor(); qApp->restoreOverrideCursor();
timeout_timer->stop();
poll_timer->stop();
for (auto& poller : device_pollers) {
poller->Stop();
}
if (input_setter) { if (input_setter) {
(*input_setter)(params, cancel); (*input_setter)(params, cancel);
input_setter.reset(); input_setter.reset();

View file

@ -24,10 +24,6 @@ namespace InputCommon {
class InputSubsystem; class InputSubsystem;
} }
namespace InputCommon::Polling {
class DevicePoller;
}
namespace Settings { namespace Settings {
struct TouchFromButtonMap; struct TouchFromButtonMap;
} }
@ -85,7 +81,6 @@ private:
std::unique_ptr<QTimer> timeout_timer; std::unique_ptr<QTimer> timeout_timer;
std::unique_ptr<QTimer> poll_timer; std::unique_ptr<QTimer> poll_timer;
std::vector<std::unique_ptr<InputCommon::Polling::DevicePoller>> device_pollers;
std::optional<std::function<void(const Common::ParamPackage&, bool)>> input_setter; std::optional<std::function<void(const Common::ParamPackage&, bool)>> input_setter;
static constexpr int DataRoleDot = Qt::ItemDataRole::UserRole + 2; static constexpr int DataRoleDot = Qt::ItemDataRole::UserRole + 2;

View file

@ -97,7 +97,7 @@ void ConfigureVibration::SetVibrationDevices(std::size_t player_index) {
const auto engine = param.Get("engine", ""); const auto engine = param.Get("engine", "");
const auto guid = param.Get("guid", ""); const auto guid = param.Get("guid", "");
const auto port = param.Get("port", ""); const auto port = param.Get("port", 0);
if (engine.empty() || engine == "keyboard" || engine == "mouse" || engine == "tas") { if (engine.empty() || engine == "keyboard" || engine == "mouse" || engine == "tas") {
continue; continue;
@ -105,7 +105,7 @@ void ConfigureVibration::SetVibrationDevices(std::size_t player_index) {
vibration_param_str += fmt::format("engine:{}", engine); vibration_param_str += fmt::format("engine:{}", engine);
if (!port.empty()) { if (port != 0) {
vibration_param_str += fmt::format(",port:{}", port); vibration_param_str += fmt::format(",port:{}", port);
} }
if (!guid.empty()) { if (!guid.empty()) {

View file

@ -6,13 +6,17 @@
#include <QLayout> #include <QLayout>
#include <QString> #include <QString>
#include "common/settings.h" #include "common/settings.h"
#include "core/hid/emulated_controller.h"
#include "core/hid/hid_core.h"
#include "input_common/drivers/tas_input.h"
#include "input_common/main.h" #include "input_common/main.h"
#include "input_common/tas/tas_input.h"
#include "yuzu/configuration/configure_input_player_widget.h" #include "yuzu/configuration/configure_input_player_widget.h"
#include "yuzu/debugger/controller.h" #include "yuzu/debugger/controller.h"
ControllerDialog::ControllerDialog(QWidget* parent, InputCommon::InputSubsystem* input_subsystem_) ControllerDialog::ControllerDialog(Core::HID::HIDCore& hid_core_,
: QWidget(parent, Qt::Dialog), input_subsystem{input_subsystem_} { std::shared_ptr<InputCommon::InputSubsystem> input_subsystem_,
QWidget* parent)
: QWidget(parent, Qt::Dialog), hid_core{hid_core_}, input_subsystem{input_subsystem_} {
setObjectName(QStringLiteral("Controller")); setObjectName(QStringLiteral("Controller"));
setWindowTitle(tr("Controller P1")); setWindowTitle(tr("Controller P1"));
resize(500, 350); resize(500, 350);
@ -31,20 +35,24 @@ ControllerDialog::ControllerDialog(QWidget* parent, InputCommon::InputSubsystem*
// Configure focus so that widget is focusable and the dialog automatically forwards focus to // Configure focus so that widget is focusable and the dialog automatically forwards focus to
// it. // it.
setFocusProxy(widget); setFocusProxy(widget);
widget->SetConnectedStatus(false);
widget->setFocusPolicy(Qt::StrongFocus); widget->setFocusPolicy(Qt::StrongFocus);
widget->setFocus(); widget->setFocus();
} }
void ControllerDialog::refreshConfiguration() { void ControllerDialog::refreshConfiguration() {
const auto& players = Settings::values.players.GetValue(); UnloadController();
constexpr std::size_t player = 0; auto* player_1 = hid_core.GetEmulatedController(Core::HID::NpadIdType::Player1);
widget->SetPlayerInputRaw(player, players[player].buttons, players[player].analogs); auto* handheld = hid_core.GetEmulatedController(Core::HID::NpadIdType::Handheld);
widget->SetControllerType(players[player].controller_type); // Display the correct controller
ControllerCallback callback{[this](ControllerInput input) { InputController(input); }}; controller = handheld->IsConnected() ? handheld : player_1;
widget->SetCallBack(callback);
widget->repaint(); Core::HID::ControllerUpdateCallback engine_callback{
widget->SetConnectedStatus(players[player].connected); .on_change = [this](Core::HID::ControllerTriggerType type) { ControllerUpdate(type); },
.is_npad_service = true,
};
callback_key = controller->SetCallback(engine_callback);
widget->SetController(controller);
is_controller_set = true;
} }
QAction* ControllerDialog::toggleViewAction() { QAction* ControllerDialog::toggleViewAction() {
@ -58,11 +66,18 @@ QAction* ControllerDialog::toggleViewAction() {
return toggle_view_action; return toggle_view_action;
} }
void ControllerDialog::UnloadController() {
widget->UnloadController();
if (is_controller_set) {
controller->DeleteCallback(callback_key);
is_controller_set = false;
}
}
void ControllerDialog::showEvent(QShowEvent* ev) { void ControllerDialog::showEvent(QShowEvent* ev) {
if (toggle_view_action) { if (toggle_view_action) {
toggle_view_action->setChecked(isVisible()); toggle_view_action->setChecked(isVisible());
} }
refreshConfiguration();
QWidget::showEvent(ev); QWidget::showEvent(ev);
} }
@ -70,16 +85,34 @@ void ControllerDialog::hideEvent(QHideEvent* ev) {
if (toggle_view_action) { if (toggle_view_action) {
toggle_view_action->setChecked(isVisible()); toggle_view_action->setChecked(isVisible());
} }
widget->SetConnectedStatus(false);
QWidget::hideEvent(ev); QWidget::hideEvent(ev);
} }
void ControllerDialog::InputController(ControllerInput input) { void ControllerDialog::ControllerUpdate(Core::HID::ControllerTriggerType type) {
u32 buttons = 0; // TODO(german77): Remove TAS from here
int index = 0; switch (type) {
for (bool btn : input.button_values) { case Core::HID::ControllerTriggerType::Button:
buttons |= (btn ? 1U : 0U) << index; case Core::HID::ControllerTriggerType::Stick: {
const auto buttons_values = controller->GetButtonsValues();
const auto stick_values = controller->GetSticksValues();
u64 buttons = 0;
std::size_t index = 0;
for (const auto& button : buttons_values) {
buttons |= button.value ? 1LLU << index : 0;
index++; index++;
} }
input_subsystem->GetTas()->RecordInput(buttons, input.axis_values); const InputCommon::TasInput::TasAnalog left_axis = {
.x = stick_values[Settings::NativeAnalog::LStick].x.value,
.y = stick_values[Settings::NativeAnalog::LStick].y.value,
};
const InputCommon::TasInput::TasAnalog right_axis = {
.x = stick_values[Settings::NativeAnalog::RStick].x.value,
.y = stick_values[Settings::NativeAnalog::RStick].y.value,
};
input_subsystem->GetTas()->RecordInput(buttons, left_axis, right_axis);
break;
}
default:
break;
}
} }

View file

@ -4,9 +4,7 @@
#pragma once #pragma once
#include <QFileSystemWatcher>
#include <QWidget> #include <QWidget>
#include "common/settings.h"
class QAction; class QAction;
class QHideEvent; class QHideEvent;
@ -17,35 +15,43 @@ namespace InputCommon {
class InputSubsystem; class InputSubsystem;
} }
struct ControllerInput { namespace Core::HID {
std::array<std::pair<float, float>, Settings::NativeAnalog::NUM_STICKS_HID> axis_values{}; class HIDCore;
std::array<bool, Settings::NativeButton::NumButtons> button_values{}; class EmulatedController;
bool changed{}; enum class ControllerTriggerType;
}; } // namespace Core::HID
struct ControllerCallback {
std::function<void(ControllerInput)> input;
};
class ControllerDialog : public QWidget { class ControllerDialog : public QWidget {
Q_OBJECT Q_OBJECT
public: public:
explicit ControllerDialog(QWidget* parent = nullptr, explicit ControllerDialog(Core::HID::HIDCore& hid_core_,
InputCommon::InputSubsystem* input_subsystem_ = nullptr); std::shared_ptr<InputCommon::InputSubsystem> input_subsystem_,
QWidget* parent = nullptr);
/// Returns a QAction that can be used to toggle visibility of this dialog. /// Returns a QAction that can be used to toggle visibility of this dialog.
QAction* toggleViewAction(); QAction* toggleViewAction();
/// Reloads the widget to apply any changes in the configuration
void refreshConfiguration(); void refreshConfiguration();
/// Disables events from the emulated controller
void UnloadController();
protected: protected:
void showEvent(QShowEvent* ev) override; void showEvent(QShowEvent* ev) override;
void hideEvent(QHideEvent* ev) override; void hideEvent(QHideEvent* ev) override;
private: private:
void InputController(ControllerInput input); /// Redirects input from the widget to the TAS driver
void ControllerUpdate(Core::HID::ControllerTriggerType type);
int callback_key;
bool is_controller_set{};
Core::HID::EmulatedController* controller;
QAction* toggle_view_action = nullptr; QAction* toggle_view_action = nullptr;
QFileSystemWatcher* watcher = nullptr;
PlayerControlPreview* widget; PlayerControlPreview* widget;
InputCommon::InputSubsystem* input_subsystem; Core::HID::HIDCore& hid_core;
std::shared_ptr<InputCommon::InputSubsystem> input_subsystem;
}; };

View file

@ -26,6 +26,8 @@
#include "core/frontend/applets/controller.h" #include "core/frontend/applets/controller.h"
#include "core/frontend/applets/general_frontend.h" #include "core/frontend/applets/general_frontend.h"
#include "core/frontend/applets/software_keyboard.h" #include "core/frontend/applets/software_keyboard.h"
#include "core/hid/emulated_controller.h"
#include "core/hid/hid_core.h"
#include "core/hle/service/acc/profile_manager.h" #include "core/hle/service/acc/profile_manager.h"
#include "core/hle/service/am/applet_ae.h" #include "core/hle/service/am/applet_ae.h"
#include "core/hle/service/am/applet_oe.h" #include "core/hle/service/am/applet_oe.h"
@ -106,8 +108,8 @@ static FileSys::VirtualFile VfsDirectoryCreateFileWrapper(const FileSys::Virtual
#include "core/loader/loader.h" #include "core/loader/loader.h"
#include "core/perf_stats.h" #include "core/perf_stats.h"
#include "core/telemetry_session.h" #include "core/telemetry_session.h"
#include "input_common/drivers/tas_input.h"
#include "input_common/main.h" #include "input_common/main.h"
#include "input_common/tas/tas_input.h"
#include "ui_main.h" #include "ui_main.h"
#include "util/overlay_dialog.h" #include "util/overlay_dialog.h"
#include "video_core/gpu.h" #include "video_core/gpu.h"
@ -227,6 +229,9 @@ GMainWindow::GMainWindow()
ConnectMenuEvents(); ConnectMenuEvents();
ConnectWidgetEvents(); ConnectWidgetEvents();
system->HIDCore().ReloadInputDevices();
controller_dialog->refreshConfiguration();
const auto branch_name = std::string(Common::g_scm_branch); const auto branch_name = std::string(Common::g_scm_branch);
const auto description = std::string(Common::g_scm_desc); const auto description = std::string(Common::g_scm_desc);
const auto build_id = std::string(Common::g_build_id); const auto build_id = std::string(Common::g_build_id);
@ -829,15 +834,16 @@ void GMainWindow::InitializeWidgets() {
dock_status_button->setFocusPolicy(Qt::NoFocus); dock_status_button->setFocusPolicy(Qt::NoFocus);
connect(dock_status_button, &QPushButton::clicked, [&] { connect(dock_status_button, &QPushButton::clicked, [&] {
const bool is_docked = Settings::values.use_docked_mode.GetValue(); const bool is_docked = Settings::values.use_docked_mode.GetValue();
auto& controller_type = Settings::values.players.GetValue()[0].controller_type; auto* player_1 = system->HIDCore().GetEmulatedController(Core::HID::NpadIdType::Player1);
auto* handheld = system->HIDCore().GetEmulatedController(Core::HID::NpadIdType::Handheld);
if (!is_docked && controller_type == Settings::ControllerType::Handheld) { if (!is_docked && handheld->IsConnected()) {
QMessageBox::warning(this, tr("Invalid config detected"), QMessageBox::warning(this, tr("Invalid config detected"),
tr("Handheld controller can't be used on docked mode. Pro " tr("Handheld controller can't be used on docked mode. Pro "
"controller will be selected.")); "controller will be selected."));
controller_type = Settings::ControllerType::ProController; handheld->Disconnect();
ConfigureDialog configure_dialog(this, hotkey_registry, input_subsystem.get(), *system); player_1->SetNpadStyleIndex(Core::HID::NpadStyleIndex::ProController);
configure_dialog.ApplyConfiguration(); player_1->Connect();
controller_dialog->refreshConfiguration(); controller_dialog->refreshConfiguration();
} }
@ -922,7 +928,7 @@ void GMainWindow::InitializeDebugWidgets() {
waitTreeWidget->hide(); waitTreeWidget->hide();
debug_menu->addAction(waitTreeWidget->toggleViewAction()); debug_menu->addAction(waitTreeWidget->toggleViewAction());
controller_dialog = new ControllerDialog(this, input_subsystem.get()); controller_dialog = new ControllerDialog(system->HIDCore(), input_subsystem, this);
controller_dialog->hide(); controller_dialog->hide();
debug_menu->addAction(controller_dialog->toggleViewAction()); debug_menu->addAction(controller_dialog->toggleViewAction());
@ -2774,7 +2780,6 @@ void GMainWindow::OnConfigure() {
ShowTelemetryCallout(); ShowTelemetryCallout();
} }
controller_dialog->refreshConfiguration();
InitializeHotkeys(); InitializeHotkeys();
if (UISettings::values.theme != old_theme) { if (UISettings::values.theme != old_theme) {
@ -2807,6 +2812,7 @@ void GMainWindow::OnConfigure() {
} }
UpdateStatusButtons(); UpdateStatusButtons();
controller_dialog->refreshConfiguration();
} }
void GMainWindow::OnConfigureTas() { void GMainWindow::OnConfigureTas() {
@ -3003,11 +3009,11 @@ void GMainWindow::UpdateWindowTitle(std::string_view title_name, std::string_vie
QString GMainWindow::GetTasStateDescription() const { QString GMainWindow::GetTasStateDescription() const {
auto [tas_status, current_tas_frame, total_tas_frames] = input_subsystem->GetTas()->GetStatus(); auto [tas_status, current_tas_frame, total_tas_frames] = input_subsystem->GetTas()->GetStatus();
switch (tas_status) { switch (tas_status) {
case TasInput::TasState::Running: case InputCommon::TasInput::TasState::Running:
return tr("TAS state: Running %1/%2").arg(current_tas_frame).arg(total_tas_frames); return tr("TAS state: Running %1/%2").arg(current_tas_frame).arg(total_tas_frames);
case TasInput::TasState::Recording: case InputCommon::TasInput::TasState::Recording:
return tr("TAS state: Recording %1").arg(total_tas_frames); return tr("TAS state: Recording %1").arg(total_tas_frames);
case TasInput::TasState::Stopped: case InputCommon::TasInput::TasState::Stopped:
return tr("TAS state: Idle %1/%2").arg(current_tas_frame).arg(total_tas_frames); return tr("TAS state: Idle %1/%2").arg(current_tas_frame).arg(total_tas_frames);
default: default:
return tr("TAS State: Invalid"); return tr("TAS State: Invalid");
@ -3386,6 +3392,8 @@ void GMainWindow::closeEvent(QCloseEvent* event) {
UpdateUISettings(); UpdateUISettings();
game_list->SaveInterfaceLayout(); game_list->SaveInterfaceLayout();
hotkey_registry.SaveHotkeys(); hotkey_registry.SaveHotkeys();
controller_dialog->UnloadController();
system->HIDCore().UnloadInputDevices();
// Shutdown session if the emu thread is active... // Shutdown session if the emu thread is active...
if (emu_thread != nullptr) { if (emu_thread != nullptr) {

View file

@ -6,7 +6,8 @@
#include <QScreen> #include <QScreen>
#include "core/core.h" #include "core/core.h"
#include "core/frontend/input_interpreter.h" #include "core/hid/hid_types.h"
#include "core/hid/input_interpreter.h"
#include "ui_overlay_dialog.h" #include "ui_overlay_dialog.h"
#include "yuzu/util/overlay_dialog.h" #include "yuzu/util/overlay_dialog.h"
@ -179,9 +180,9 @@ void OverlayDialog::MoveAndResizeWindow() {
QDialog::resize(width, height); QDialog::resize(width, height);
} }
template <HIDButton... T> template <Core::HID::NpadButton... T>
void OverlayDialog::HandleButtonPressedOnce() { void OverlayDialog::HandleButtonPressedOnce() {
const auto f = [this](HIDButton button) { const auto f = [this](Core::HID::NpadButton button) {
if (input_interpreter->IsButtonPressedOnce(button)) { if (input_interpreter->IsButtonPressedOnce(button)) {
TranslateButtonPress(button); TranslateButtonPress(button);
} }
@ -190,7 +191,7 @@ void OverlayDialog::HandleButtonPressedOnce() {
(f(T), ...); (f(T), ...);
} }
void OverlayDialog::TranslateButtonPress(HIDButton button) { void OverlayDialog::TranslateButtonPress(Core::HID::NpadButton button) {
QPushButton* left_button = use_rich_text ? ui->button_cancel_rich : ui->button_cancel; QPushButton* left_button = use_rich_text ? ui->button_cancel_rich : ui->button_cancel;
QPushButton* right_button = use_rich_text ? ui->button_ok_rich : ui->button_ok_label; QPushButton* right_button = use_rich_text ? ui->button_ok_rich : ui->button_ok_label;
@ -198,20 +199,20 @@ void OverlayDialog::TranslateButtonPress(HIDButton button) {
// TODO (Morph): focusPrevious/NextChild() doesn't work well with the rich text dialog, fix it // TODO (Morph): focusPrevious/NextChild() doesn't work well with the rich text dialog, fix it
switch (button) { switch (button) {
case HIDButton::A: case Core::HID::NpadButton::A:
case HIDButton::B: case Core::HID::NpadButton::B:
if (left_button->hasFocus()) { if (left_button->hasFocus()) {
left_button->click(); left_button->click();
} else if (right_button->hasFocus()) { } else if (right_button->hasFocus()) {
right_button->click(); right_button->click();
} }
break; break;
case HIDButton::DLeft: case Core::HID::NpadButton::Left:
case HIDButton::LStickLeft: case Core::HID::NpadButton::StickLLeft:
focusPreviousChild(); focusPreviousChild();
break; break;
case HIDButton::DRight: case Core::HID::NpadButton::Right:
case HIDButton::LStickRight: case Core::HID::NpadButton::StickLRight:
focusNextChild(); focusNextChild();
break; break;
default: default:
@ -241,8 +242,10 @@ void OverlayDialog::InputThread() {
while (input_thread_running) { while (input_thread_running) {
input_interpreter->PollInput(); input_interpreter->PollInput();
HandleButtonPressedOnce<HIDButton::A, HIDButton::B, HIDButton::DLeft, HIDButton::DRight, HandleButtonPressedOnce<Core::HID::NpadButton::A, Core::HID::NpadButton::B,
HIDButton::LStickLeft, HIDButton::LStickRight>(); Core::HID::NpadButton::Left, Core::HID::NpadButton::Right,
Core::HID::NpadButton::StickLLeft,
Core::HID::NpadButton::StickLRight>();
std::this_thread::sleep_for(std::chrono::milliseconds(50)); std::this_thread::sleep_for(std::chrono::milliseconds(50));
} }

View file

@ -13,14 +13,16 @@
#include "common/common_types.h" #include "common/common_types.h"
enum class HIDButton : u8;
class InputInterpreter; class InputInterpreter;
namespace Core { namespace Core {
class System; class System;
} }
namespace Core::HID {
enum class NpadButton : u64;
}
namespace Ui { namespace Ui {
class OverlayDialog; class OverlayDialog;
} }
@ -79,7 +81,7 @@ private:
* *
* @tparam HIDButton The list of buttons that can be converted into keyboard input. * @tparam HIDButton The list of buttons that can be converted into keyboard input.
*/ */
template <HIDButton... T> template <Core::HID::NpadButton... T>
void HandleButtonPressedOnce(); void HandleButtonPressedOnce();
/** /**
@ -87,7 +89,7 @@ private:
* *
* @param button The button press to process. * @param button The button press to process.
*/ */
void TranslateButtonPress(HIDButton button); void TranslateButtonPress(Core::HID::NpadButton button);
void StartInputThread(); void StartInputThread();
void StopInputThread(); void StopInputThread();

View file

@ -24,7 +24,6 @@
#include "common/settings.h" #include "common/settings.h"
#include "core/hle/service/acc/profile_manager.h" #include "core/hle/service/acc/profile_manager.h"
#include "input_common/main.h" #include "input_common/main.h"
#include "input_common/udp/client.h"
#include "yuzu_cmd/config.h" #include "yuzu_cmd/config.h"
#include "yuzu_cmd/default_ini.h" #include "yuzu_cmd/default_ini.h"
@ -84,163 +83,6 @@ static const std::array<std::array<int, 5>, Settings::NativeAnalog::NumAnalogs>
}, },
}}; }};
static const std::array<int, Settings::NativeMouseButton::NumMouseButtons> default_mouse_buttons = {
SDL_SCANCODE_LEFTBRACKET, SDL_SCANCODE_RIGHTBRACKET, SDL_SCANCODE_APOSTROPHE,
SDL_SCANCODE_MINUS, SDL_SCANCODE_EQUALS,
};
static const std::array<int, 0x8A> keyboard_keys = {
0,
0,
0,
0,
SDL_SCANCODE_A,
SDL_SCANCODE_B,
SDL_SCANCODE_C,
SDL_SCANCODE_D,
SDL_SCANCODE_E,
SDL_SCANCODE_F,
SDL_SCANCODE_G,
SDL_SCANCODE_H,
SDL_SCANCODE_I,
SDL_SCANCODE_J,
SDL_SCANCODE_K,
SDL_SCANCODE_L,
SDL_SCANCODE_M,
SDL_SCANCODE_N,
SDL_SCANCODE_O,
SDL_SCANCODE_P,
SDL_SCANCODE_Q,
SDL_SCANCODE_R,
SDL_SCANCODE_S,
SDL_SCANCODE_T,
SDL_SCANCODE_U,
SDL_SCANCODE_V,
SDL_SCANCODE_W,
SDL_SCANCODE_X,
SDL_SCANCODE_Y,
SDL_SCANCODE_Z,
SDL_SCANCODE_1,
SDL_SCANCODE_2,
SDL_SCANCODE_3,
SDL_SCANCODE_4,
SDL_SCANCODE_5,
SDL_SCANCODE_6,
SDL_SCANCODE_7,
SDL_SCANCODE_8,
SDL_SCANCODE_9,
SDL_SCANCODE_0,
SDL_SCANCODE_RETURN,
SDL_SCANCODE_ESCAPE,
SDL_SCANCODE_BACKSPACE,
SDL_SCANCODE_TAB,
SDL_SCANCODE_SPACE,
SDL_SCANCODE_MINUS,
SDL_SCANCODE_EQUALS,
SDL_SCANCODE_LEFTBRACKET,
SDL_SCANCODE_RIGHTBRACKET,
SDL_SCANCODE_BACKSLASH,
0,
SDL_SCANCODE_SEMICOLON,
SDL_SCANCODE_APOSTROPHE,
SDL_SCANCODE_GRAVE,
SDL_SCANCODE_COMMA,
SDL_SCANCODE_PERIOD,
SDL_SCANCODE_SLASH,
SDL_SCANCODE_CAPSLOCK,
SDL_SCANCODE_F1,
SDL_SCANCODE_F2,
SDL_SCANCODE_F3,
SDL_SCANCODE_F4,
SDL_SCANCODE_F5,
SDL_SCANCODE_F6,
SDL_SCANCODE_F7,
SDL_SCANCODE_F8,
SDL_SCANCODE_F9,
SDL_SCANCODE_F10,
SDL_SCANCODE_F11,
SDL_SCANCODE_F12,
0,
SDL_SCANCODE_SCROLLLOCK,
SDL_SCANCODE_PAUSE,
SDL_SCANCODE_INSERT,
SDL_SCANCODE_HOME,
SDL_SCANCODE_PAGEUP,
SDL_SCANCODE_DELETE,
SDL_SCANCODE_END,
SDL_SCANCODE_PAGEDOWN,
SDL_SCANCODE_RIGHT,
SDL_SCANCODE_LEFT,
SDL_SCANCODE_DOWN,
SDL_SCANCODE_UP,
SDL_SCANCODE_NUMLOCKCLEAR,
SDL_SCANCODE_KP_DIVIDE,
SDL_SCANCODE_KP_MULTIPLY,
SDL_SCANCODE_KP_MINUS,
SDL_SCANCODE_KP_PLUS,
SDL_SCANCODE_KP_ENTER,
SDL_SCANCODE_KP_1,
SDL_SCANCODE_KP_2,
SDL_SCANCODE_KP_3,
SDL_SCANCODE_KP_4,
SDL_SCANCODE_KP_5,
SDL_SCANCODE_KP_6,
SDL_SCANCODE_KP_7,
SDL_SCANCODE_KP_8,
SDL_SCANCODE_KP_9,
SDL_SCANCODE_KP_0,
SDL_SCANCODE_KP_PERIOD,
0,
0,
SDL_SCANCODE_POWER,
SDL_SCANCODE_KP_EQUALS,
SDL_SCANCODE_F13,
SDL_SCANCODE_F14,
SDL_SCANCODE_F15,
SDL_SCANCODE_F16,
SDL_SCANCODE_F17,
SDL_SCANCODE_F18,
SDL_SCANCODE_F19,
SDL_SCANCODE_F20,
SDL_SCANCODE_F21,
SDL_SCANCODE_F22,
SDL_SCANCODE_F23,
SDL_SCANCODE_F24,
0,
SDL_SCANCODE_HELP,
SDL_SCANCODE_MENU,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
0,
SDL_SCANCODE_KP_COMMA,
SDL_SCANCODE_KP_LEFTPAREN,
SDL_SCANCODE_KP_RIGHTPAREN,
0,
0,
0,
0,
};
static const std::array<int, 8> keyboard_mods{
SDL_SCANCODE_LCTRL, SDL_SCANCODE_LSHIFT, SDL_SCANCODE_LALT, SDL_SCANCODE_LGUI,
SDL_SCANCODE_RCTRL, SDL_SCANCODE_RSHIFT, SDL_SCANCODE_RALT, SDL_SCANCODE_RGUI,
};
template <> template <>
void Config::ReadSetting(const std::string& group, Settings::BasicSetting<std::string>& setting) { void Config::ReadSetting(const std::string& group, Settings::BasicSetting<std::string>& setting) {
setting = sdl2_config->Get(group, setting.GetLabel(), setting.GetDefault()); setting = sdl2_config->Get(group, setting.GetLabel(), setting.GetDefault());
@ -284,16 +126,6 @@ void Config::ReadValues() {
} }
ReadSetting("ControlsGeneral", Settings::values.mouse_enabled); ReadSetting("ControlsGeneral", Settings::values.mouse_enabled);
for (int i = 0; i < Settings::NativeMouseButton::NumMouseButtons; ++i) {
std::string default_param = InputCommon::GenerateKeyboardParam(default_mouse_buttons[i]);
Settings::values.mouse_buttons[i] = sdl2_config->Get(
"ControlsGeneral", std::string("mouse_") + Settings::NativeMouseButton::mapping[i],
default_param);
if (Settings::values.mouse_buttons[i].empty())
Settings::values.mouse_buttons[i] = default_param;
}
ReadSetting("ControlsGeneral", Settings::values.motion_device);
ReadSetting("ControlsGeneral", Settings::values.touch_device); ReadSetting("ControlsGeneral", Settings::values.touch_device);
@ -363,21 +195,11 @@ void Config::ReadValues() {
Settings::TouchFromButtonMap{"default", {}}); Settings::TouchFromButtonMap{"default", {}});
num_touch_from_button_maps = 1; num_touch_from_button_maps = 1;
} }
ReadSetting("ControlsGeneral", Settings::values.use_touch_from_button);
Settings::values.touch_from_button_map_index = std::clamp( Settings::values.touch_from_button_map_index = std::clamp(
Settings::values.touch_from_button_map_index.GetValue(), 0, num_touch_from_button_maps - 1); Settings::values.touch_from_button_map_index.GetValue(), 0, num_touch_from_button_maps - 1);
ReadSetting("ControlsGeneral", Settings::values.udp_input_servers); ReadSetting("ControlsGeneral", Settings::values.udp_input_servers);
std::transform(keyboard_keys.begin(), keyboard_keys.end(),
Settings::values.keyboard_keys.begin(), InputCommon::GenerateKeyboardParam);
std::transform(keyboard_mods.begin(), keyboard_mods.end(),
Settings::values.keyboard_keys.begin() +
Settings::NativeKeyboard::LeftControlKey,
InputCommon::GenerateKeyboardParam);
std::transform(keyboard_mods.begin(), keyboard_mods.end(),
Settings::values.keyboard_mods.begin(), InputCommon::GenerateKeyboardParam);
// Data Storage // Data Storage
ReadSetting("Data Storage", Settings::values.use_virtual_sd); ReadSetting("Data Storage", Settings::values.use_virtual_sd);
FS::SetYuzuPath(FS::YuzuPath::NANDDir, FS::SetYuzuPath(FS::YuzuPath::NANDDir,

View file

@ -84,23 +84,10 @@ enable_accurate_vibrations=
# 0: Disabled, 1 (default): Enabled # 0: Disabled, 1 (default): Enabled
motion_enabled = motion_enabled =
# for motion input, the following devices are available: # Defines the udp device's touch screen coordinate system for cemuhookudp devices
# - "motion_emu" (default) for emulating motion input from mouse input. Required parameters: # - "min_x", "min_y", "max_x", "max_y"
# - "update_period": update period in milliseconds (default to 100)
# - "sensitivity": the coefficient converting mouse movement to tilting angle (default to 0.01)
# - "cemuhookudp" reads motion input from a udp server that uses cemuhook's udp protocol
motion_device=
# for touch input, the following devices are available:
# - "emu_window" (default) for emulating touch input from mouse input to the emulation window. No parameters required
# - "cemuhookudp" reads touch input from a udp server that uses cemuhook's udp protocol
# - "min_x", "min_y", "max_x", "max_y": defines the udp device's touch screen coordinate system
touch_device= touch_device=
# Whether to enable or disable touch input from button
# 0 (default): Disabled, 1: Enabled
use_touch_from_button=
# for mapping buttons to touch inputs. # for mapping buttons to touch inputs.
#touch_from_button_map=1 #touch_from_button_map=1
#touch_from_button_maps_0_name=default #touch_from_button_maps_0_name=default

View file

@ -9,10 +9,10 @@
#include "common/settings.h" #include "common/settings.h"
#include "core/core.h" #include "core/core.h"
#include "core/perf_stats.h" #include "core/perf_stats.h"
#include "input_common/keyboard.h" #include "input_common/drivers/keyboard.h"
#include "input_common/drivers/mouse.h"
#include "input_common/drivers/touch_screen.h"
#include "input_common/main.h" #include "input_common/main.h"
#include "input_common/mouse/mouse_input.h"
#include "input_common/sdl/sdl.h"
#include "yuzu_cmd/emu_window/emu_window_sdl2.h" #include "yuzu_cmd/emu_window/emu_window_sdl2.h"
#include "yuzu_cmd/yuzu_icon.h" #include "yuzu_cmd/yuzu_icon.h"
@ -32,44 +32,34 @@ EmuWindow_SDL2::~EmuWindow_SDL2() {
} }
void EmuWindow_SDL2::OnMouseMotion(s32 x, s32 y) { void EmuWindow_SDL2::OnMouseMotion(s32 x, s32 y) {
TouchMoved((unsigned)std::max(x, 0), (unsigned)std::max(y, 0), 0); input_subsystem->GetMouse()->MouseMove(x, y, 0, 0, 0, 0);
input_subsystem->GetMouse()->MouseMove(x, y, 0, 0);
} }
MouseInput::MouseButton EmuWindow_SDL2::SDLButtonToMouseButton(u32 button) const { InputCommon::MouseButton EmuWindow_SDL2::SDLButtonToMouseButton(u32 button) const {
switch (button) { switch (button) {
case SDL_BUTTON_LEFT: case SDL_BUTTON_LEFT:
return MouseInput::MouseButton::Left; return InputCommon::MouseButton::Left;
case SDL_BUTTON_RIGHT: case SDL_BUTTON_RIGHT:
return MouseInput::MouseButton::Right; return InputCommon::MouseButton::Right;
case SDL_BUTTON_MIDDLE: case SDL_BUTTON_MIDDLE:
return MouseInput::MouseButton::Wheel; return InputCommon::MouseButton::Wheel;
case SDL_BUTTON_X1: case SDL_BUTTON_X1:
return MouseInput::MouseButton::Backward; return InputCommon::MouseButton::Backward;
case SDL_BUTTON_X2: case SDL_BUTTON_X2:
return MouseInput::MouseButton::Forward; return InputCommon::MouseButton::Forward;
default: default:
return MouseInput::MouseButton::Undefined; return InputCommon::MouseButton::Undefined;
} }
} }
void EmuWindow_SDL2::OnMouseButton(u32 button, u8 state, s32 x, s32 y) { void EmuWindow_SDL2::OnMouseButton(u32 button, u8 state, s32 x, s32 y) {
const auto mouse_button = SDLButtonToMouseButton(button); const auto mouse_button = SDLButtonToMouseButton(button);
if (button == SDL_BUTTON_LEFT) {
if (state == SDL_PRESSED) { if (state == SDL_PRESSED) {
TouchPressed((unsigned)std::max(x, 0), (unsigned)std::max(y, 0), 0); input_subsystem->GetMouse()->PressButton(x, y, 0, 0, mouse_button);
} else {
TouchReleased(0);
}
} else {
if (state == SDL_PRESSED) {
input_subsystem->GetMouse()->PressButton(x, y, mouse_button);
} else { } else {
input_subsystem->GetMouse()->ReleaseButton(mouse_button); input_subsystem->GetMouse()->ReleaseButton(mouse_button);
} }
} }
}
std::pair<unsigned, unsigned> EmuWindow_SDL2::TouchToPixelPos(float touch_x, float touch_y) const { std::pair<unsigned, unsigned> EmuWindow_SDL2::TouchToPixelPos(float touch_x, float touch_y) const {
int w, h; int w, h;
@ -82,29 +72,35 @@ std::pair<unsigned, unsigned> EmuWindow_SDL2::TouchToPixelPos(float touch_x, flo
static_cast<unsigned>(std::max(std::round(touch_y), 0.0f))}; static_cast<unsigned>(std::max(std::round(touch_y), 0.0f))};
} }
void EmuWindow_SDL2::OnFingerDown(float x, float y) { void EmuWindow_SDL2::OnFingerDown(float x, float y, std::size_t id) {
// TODO(NeatNit): keep track of multitouch using the fingerID and a dictionary of some kind int width, height;
// This isn't critical because the best we can do when we have that is to average them, like the SDL_GetWindowSize(render_window, &width, &height);
// 3DS does
const auto [px, py] = TouchToPixelPos(x, y); const auto [px, py] = TouchToPixelPos(x, y);
TouchPressed(px, py, 0); const float fx = px * 1.0f / width;
const float fy = py * 1.0f / height;
input_subsystem->GetTouchScreen()->TouchPressed(fx, fy, id);
} }
void EmuWindow_SDL2::OnFingerMotion(float x, float y) { void EmuWindow_SDL2::OnFingerMotion(float x, float y, std::size_t id) {
int width, height;
SDL_GetWindowSize(render_window, &width, &height);
const auto [px, py] = TouchToPixelPos(x, y); const auto [px, py] = TouchToPixelPos(x, y);
TouchMoved(px, py, 0); const float fx = px * 1.0f / width;
const float fy = py * 1.0f / height;
input_subsystem->GetTouchScreen()->TouchMoved(fx, fy, id);
} }
void EmuWindow_SDL2::OnFingerUp() { void EmuWindow_SDL2::OnFingerUp() {
TouchReleased(0); input_subsystem->GetTouchScreen()->TouchReleased(0);
} }
void EmuWindow_SDL2::OnKeyEvent(int key, u8 state) { void EmuWindow_SDL2::OnKeyEvent(int key, u8 state) {
if (state == SDL_PRESSED) { if (state == SDL_PRESSED) {
input_subsystem->GetKeyboard()->PressKey(key); input_subsystem->GetKeyboard()->PressKey(static_cast<std::size_t>(key));
} else if (state == SDL_RELEASED) { } else if (state == SDL_RELEASED) {
input_subsystem->GetKeyboard()->ReleaseKey(key); input_subsystem->GetKeyboard()->ReleaseKey(static_cast<std::size_t>(key));
} }
} }
@ -205,10 +201,12 @@ void EmuWindow_SDL2::WaitEvent() {
} }
break; break;
case SDL_FINGERDOWN: case SDL_FINGERDOWN:
OnFingerDown(event.tfinger.x, event.tfinger.y); OnFingerDown(event.tfinger.x, event.tfinger.y,
static_cast<std::size_t>(event.tfinger.touchId));
break; break;
case SDL_FINGERMOTION: case SDL_FINGERMOTION:
OnFingerMotion(event.tfinger.x, event.tfinger.y); OnFingerMotion(event.tfinger.x, event.tfinger.y,
static_cast<std::size_t>(event.tfinger.touchId));
break; break;
case SDL_FINGERUP: case SDL_FINGERUP:
OnFingerUp(); OnFingerUp();

View file

@ -16,11 +16,8 @@ class System;
namespace InputCommon { namespace InputCommon {
class InputSubsystem; class InputSubsystem;
}
namespace MouseInput {
enum class MouseButton; enum class MouseButton;
} } // namespace InputCommon
class EmuWindow_SDL2 : public Core::Frontend::EmuWindow { class EmuWindow_SDL2 : public Core::Frontend::EmuWindow {
public: public:
@ -47,7 +44,7 @@ protected:
void OnMouseMotion(s32 x, s32 y); void OnMouseMotion(s32 x, s32 y);
/// Converts a SDL mouse button into MouseInput mouse button /// Converts a SDL mouse button into MouseInput mouse button
MouseInput::MouseButton SDLButtonToMouseButton(u32 button) const; InputCommon::MouseButton SDLButtonToMouseButton(u32 button) const;
/// Called by WaitEvent when a mouse button is pressed or released /// Called by WaitEvent when a mouse button is pressed or released
void OnMouseButton(u32 button, u8 state, s32 x, s32 y); void OnMouseButton(u32 button, u8 state, s32 x, s32 y);
@ -56,10 +53,10 @@ protected:
std::pair<unsigned, unsigned> TouchToPixelPos(float touch_x, float touch_y) const; std::pair<unsigned, unsigned> TouchToPixelPos(float touch_x, float touch_y) const;
/// Called by WaitEvent when a finger starts touching the touchscreen /// Called by WaitEvent when a finger starts touching the touchscreen
void OnFingerDown(float x, float y); void OnFingerDown(float x, float y, std::size_t id);
/// Called by WaitEvent when a finger moves while touching the touchscreen /// Called by WaitEvent when a finger moves while touching the touchscreen
void OnFingerMotion(float x, float y); void OnFingerMotion(float x, float y, std::size_t id);
/// Called by WaitEvent when a finger stops touching the touchscreen /// Called by WaitEvent when a finger stops touching the touchscreen
void OnFingerUp(); void OnFingerUp();

View file

@ -17,7 +17,6 @@
#include "common/settings.h" #include "common/settings.h"
#include "common/string_util.h" #include "common/string_util.h"
#include "core/core.h" #include "core/core.h"
#include "input_common/keyboard.h"
#include "input_common/main.h" #include "input_common/main.h"
#include "video_core/renderer_base.h" #include "video_core/renderer_base.h"
#include "yuzu_cmd/emu_window/emu_window_sdl2_gl.h" #include "yuzu_cmd/emu_window/emu_window_sdl2_gl.h"