mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-07-21 21:30:19 -06:00
InputCommon: Add real Wii Remote support to ControllerInterface. Add option to connect additional Wii Remotes.
This commit is contained in:
@ -7,6 +7,7 @@
|
||||
#include <algorithm>
|
||||
|
||||
#include "Common/Logging/Log.h"
|
||||
#include "Core/HW/WiimoteReal/WiimoteReal.h"
|
||||
|
||||
#ifdef CIFACE_USE_WIN32
|
||||
#include "InputCommon/ControllerInterface/Win32/Win32.h"
|
||||
@ -131,7 +132,8 @@ void ControllerInterface::RefreshDevices()
|
||||
#ifdef CIFACE_USE_DUALSHOCKUDPCLIENT
|
||||
ciface::DualShockUDPClient::PopulateDevices();
|
||||
#endif
|
||||
ciface::Wiimote::PopulateDevices();
|
||||
|
||||
WiimoteReal::ProcessWiimotePool();
|
||||
|
||||
m_is_populating_devices = false;
|
||||
InvokeDevicesChangedCallbacks();
|
||||
|
1631
Source/Core/InputCommon/ControllerInterface/Wiimote/Wiimote.cpp
Normal file
1631
Source/Core/InputCommon/ControllerInterface/Wiimote/Wiimote.cpp
Normal file
File diff suppressed because it is too large
Load Diff
276
Source/Core/InputCommon/ControllerInterface/Wiimote/Wiimote.h
Normal file
276
Source/Core/InputCommon/ControllerInterface/Wiimote/Wiimote.h
Normal file
@ -0,0 +1,276 @@
|
||||
// Copyright 2020 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <chrono>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include "Core/HW/WiimoteCommon/DataReport.h"
|
||||
#include "Core/HW/WiimoteCommon/WiimoteReport.h"
|
||||
#include "Core/HW/WiimoteEmu/Camera.h"
|
||||
#include "Core/HW/WiimoteEmu/Extension/Classic.h"
|
||||
#include "Core/HW/WiimoteEmu/Extension/Nunchuk.h"
|
||||
#include "Core/HW/WiimoteEmu/MotionPlus.h"
|
||||
#include "Core/HW/WiimoteReal/WiimoteReal.h"
|
||||
#include "InputCommon/ControllerInterface/Device.h"
|
||||
|
||||
namespace ciface::Wiimote
|
||||
{
|
||||
using namespace WiimoteCommon;
|
||||
|
||||
void AddDevice(std::unique_ptr<WiimoteReal::Wiimote>);
|
||||
void ReleaseDevices(std::optional<u32> count = std::nullopt);
|
||||
|
||||
class Device final : public Core::Device
|
||||
{
|
||||
public:
|
||||
Device(std::unique_ptr<WiimoteReal::Wiimote> wiimote);
|
||||
~Device();
|
||||
|
||||
std::string GetName() const override;
|
||||
std::string GetSource() const override;
|
||||
|
||||
void UpdateInput() override;
|
||||
|
||||
private:
|
||||
using Clock = std::chrono::steady_clock;
|
||||
|
||||
enum class ExtensionID
|
||||
{
|
||||
Nunchuk,
|
||||
Classic,
|
||||
Unsupported,
|
||||
};
|
||||
|
||||
class MotionPlusState
|
||||
{
|
||||
public:
|
||||
void SetCalibrationData(const WiimoteEmu::MotionPlus::CalibrationData&);
|
||||
void ProcessData(const WiimoteEmu::MotionPlus::DataFormat&);
|
||||
|
||||
using PassthroughMode = WiimoteEmu::MotionPlus::PassthroughMode;
|
||||
|
||||
// State is unknown by default.
|
||||
std::optional<PassthroughMode> current_mode;
|
||||
|
||||
// The last known state of the passthrough port flag.
|
||||
// Used to detect passthrough extension port events.
|
||||
std::optional<bool> passthrough_port;
|
||||
|
||||
Common::Vec3 gyro_data = {};
|
||||
|
||||
std::optional<WiimoteEmu::MotionPlus::CalibrationBlocks> calibration;
|
||||
|
||||
private:
|
||||
// Used to perform realtime calibration.
|
||||
std::optional<Common::Vec3> m_dynamic_calibration = {};
|
||||
Common::Vec3 m_new_dynamic_calibration = {};
|
||||
u32 m_new_calibration_frames = 0;
|
||||
};
|
||||
|
||||
struct NunchukState
|
||||
{
|
||||
using CalibrationData = WiimoteEmu::Nunchuk::CalibrationData;
|
||||
|
||||
void SetCalibrationData(const CalibrationData&);
|
||||
void ProcessData(const WiimoteEmu::Nunchuk::DataFormat&);
|
||||
|
||||
Common::Vec2 stick = {};
|
||||
Common::Vec3 accel = {};
|
||||
|
||||
u8 buttons = 0;
|
||||
|
||||
struct Calibration
|
||||
{
|
||||
CalibrationData::AccelCalibration accel;
|
||||
CalibrationData::StickCalibration stick;
|
||||
};
|
||||
|
||||
std::optional<Calibration> calibration;
|
||||
};
|
||||
|
||||
struct ClassicState
|
||||
{
|
||||
using CalibrationData = WiimoteEmu::Classic::CalibrationData;
|
||||
|
||||
void SetCalibrationData(const CalibrationData&);
|
||||
void ProcessData(const WiimoteEmu::Classic::DataFormat&);
|
||||
|
||||
std::array<Common::Vec2, 2> sticks = {};
|
||||
std::array<float, 2> triggers = {};
|
||||
|
||||
u16 buttons = 0;
|
||||
|
||||
struct Calibration
|
||||
{
|
||||
CalibrationData::StickCalibration left_stick;
|
||||
CalibrationData::StickCalibration right_stick;
|
||||
|
||||
CalibrationData::TriggerCalibration left_trigger;
|
||||
CalibrationData::TriggerCalibration right_trigger;
|
||||
};
|
||||
|
||||
std::optional<Calibration> calibration;
|
||||
};
|
||||
|
||||
struct IRState
|
||||
{
|
||||
static u32 GetDesiredIRSensitivity();
|
||||
|
||||
void ProcessData(const std::array<WiimoteEmu::IRBasic, 2>&);
|
||||
bool IsFullyConfigured() const;
|
||||
|
||||
u32 current_sensitivity = u32(-1);
|
||||
bool enabled = false;
|
||||
bool mode_set = false;
|
||||
|
||||
// Average of visible IR "objects".
|
||||
Common::Vec2 center_position = {};
|
||||
|
||||
bool is_hidden = true;
|
||||
};
|
||||
|
||||
class ReportHandler
|
||||
{
|
||||
public:
|
||||
enum class HandlerResult
|
||||
{
|
||||
Handled,
|
||||
NotHandled,
|
||||
};
|
||||
|
||||
ReportHandler(Clock::time_point expired_time);
|
||||
|
||||
template <typename R, typename T>
|
||||
void AddHandler(std::function<R(const T&)>);
|
||||
|
||||
HandlerResult TryToHandleReport(const WiimoteReal::Report& report);
|
||||
|
||||
bool IsExpired() const;
|
||||
|
||||
private:
|
||||
const Clock::time_point m_expired_time;
|
||||
std::vector<std::function<HandlerResult(const WiimoteReal::Report& report)>> m_callbacks;
|
||||
};
|
||||
|
||||
using AckReportHandler = std::function<ReportHandler::HandlerResult(const InputReportAck& reply)>;
|
||||
|
||||
static AckReportHandler MakeAckHandler(OutputReportID report_id,
|
||||
std::function<void(WiimoteCommon::ErrorCode)> callback);
|
||||
|
||||
// TODO: Make parameter const. (need to modify DataReportManipulator)
|
||||
void ProcessInputReport(WiimoteReal::Report& report);
|
||||
void ProcessMotionPlusExtensionData(const u8* data, u32 size);
|
||||
void ProcessNormalExtensionData(const u8* data, u32 size);
|
||||
void ProcessExtensionEvent(bool connected);
|
||||
void ProcessExtensionID(u8 id_0, u8 id_4, u8 id_5);
|
||||
void ProcessStatusReport(const InputReportStatus&);
|
||||
|
||||
void RunTasks();
|
||||
|
||||
bool IsPerformingTask() const;
|
||||
|
||||
template <typename T>
|
||||
void QueueReport(T&& report, std::function<void(ErrorCode)> ack_callback = {});
|
||||
|
||||
template <typename... T>
|
||||
void AddReportHandler(T&&... callbacks);
|
||||
|
||||
using ReadResponse = std::optional<std::vector<u8>>;
|
||||
|
||||
void ReadData(AddressSpace space, u8 slave, u16 address, u16 size,
|
||||
std::function<void(ReadResponse)> callback);
|
||||
|
||||
void AddReadDataReplyHandler(AddressSpace space, u8 slave, u16 address, u16 size,
|
||||
std::vector<u8> starting_data,
|
||||
std::function<void(ReadResponse)> callback);
|
||||
|
||||
template <typename T = std::initializer_list<u8>, typename C>
|
||||
void WriteData(AddressSpace space, u8 slave, u16 address, T&& data, C&& callback);
|
||||
|
||||
void ReadActiveExtensionID();
|
||||
void SetIRSensitivity(u32 level);
|
||||
void ConfigureSpeaker();
|
||||
void ConfigureIRCamera();
|
||||
|
||||
u8 GetDesiredLEDValue() const;
|
||||
|
||||
void TriggerMotionPlusModeChange();
|
||||
void TriggerMotionPlusCalibration();
|
||||
|
||||
bool IsMotionPlusStateKnown() const;
|
||||
bool IsMotionPlusActive() const;
|
||||
bool IsMotionPlusInDesiredMode() const;
|
||||
|
||||
bool IsWaitingForMotionPlus() const;
|
||||
void WaitForMotionPlus();
|
||||
void HandleMotionPlusNonResponse();
|
||||
|
||||
void UpdateRumble();
|
||||
void UpdateOrientation();
|
||||
void UpdateExtensionNumberInput();
|
||||
|
||||
std::unique_ptr<WiimoteReal::Wiimote> m_wiimote;
|
||||
|
||||
// Buttons.
|
||||
DataReportManipulator::CoreData m_core_data = {};
|
||||
|
||||
// Accelerometer.
|
||||
Common::Vec3 m_accel_data = {};
|
||||
std::optional<AccelCalibrationData::Calibration> m_accel_calibration;
|
||||
|
||||
// Pitch, Roll, Yaw inputs.
|
||||
Common::Vec3 m_rotation_inputs = {};
|
||||
|
||||
MotionPlusState m_mplus_state = {};
|
||||
NunchukState m_nunchuk_state = {};
|
||||
ClassicState m_classic_state = {};
|
||||
IRState m_ir_state = {};
|
||||
|
||||
// Used to poll for M+ periodically and wait for it to reset.
|
||||
Clock::time_point m_mplus_wait_time = Clock::now();
|
||||
|
||||
// The desired mode is set based on the attached normal extension.
|
||||
std::optional<MotionPlusState::PassthroughMode> m_mplus_desired_mode;
|
||||
|
||||
// Status report is requested every so often to update the battery level.
|
||||
Clock::time_point m_status_outdated_time = Clock::now();
|
||||
u8 m_battery = 0;
|
||||
u8 m_leds = 0;
|
||||
|
||||
bool m_speaker_configured = false;
|
||||
|
||||
// The last known state of the extension port status flag.
|
||||
// Used to detect extension port events.
|
||||
std::optional<bool> m_extension_port;
|
||||
|
||||
// Note this refers to the passthrough extension when M+ is active.
|
||||
std::optional<ExtensionID> m_extension_id;
|
||||
|
||||
// Rumble state must be saved to set the proper flag in every output report.
|
||||
bool m_rumble = false;
|
||||
|
||||
// For pulse of rumble motor to simulate multiple levels.
|
||||
ControlState m_rumble_level = 0;
|
||||
Clock::time_point m_last_rumble_change = Clock::now();
|
||||
|
||||
// Assume mode is disabled so one gets set.
|
||||
InputReportID m_reporting_mode = InputReportID::ReportDisabled;
|
||||
|
||||
// Used only to provide a value for a specialty "input". (for attached extension passthrough)
|
||||
WiimoteEmu::ExtensionNumber m_extension_number_input = WiimoteEmu::ExtensionNumber::NONE;
|
||||
bool m_mplus_attached_input = false;
|
||||
|
||||
// Holds callbacks for output report replies.
|
||||
std::list<ReportHandler> m_report_handlers;
|
||||
|
||||
// World rotation. (used to rotate IR data and provide pitch, roll, yaw inputs)
|
||||
Common::Matrix33 m_orientation = Common::Matrix33::Identity();
|
||||
Clock::time_point m_last_report_time = Clock::now();
|
||||
};
|
||||
|
||||
} // namespace ciface::Wiimote
|
Reference in New Issue
Block a user