mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-02-10 22:49:00 +01:00
Wiimote: Separate the Input system state update from the emulated state update.
This commit is contained in:
parent
bb5943ae77
commit
a2dadbb2f0
@ -7,6 +7,11 @@
|
|||||||
#include "Core/HW/WiimoteCommon/WiimoteConstants.h"
|
#include "Core/HW/WiimoteCommon/WiimoteConstants.h"
|
||||||
#include "Core/HW/WiimoteCommon/WiimoteReport.h"
|
#include "Core/HW/WiimoteCommon/WiimoteReport.h"
|
||||||
|
|
||||||
|
namespace WiimoteEmu
|
||||||
|
{
|
||||||
|
struct DesiredWiimoteState;
|
||||||
|
}
|
||||||
|
|
||||||
namespace WiimoteCommon
|
namespace WiimoteCommon
|
||||||
{
|
{
|
||||||
// Source: HID_010_SPC_PFL/1.0 (official HID specification)
|
// Source: HID_010_SPC_PFL/1.0 (official HID specification)
|
||||||
@ -34,7 +39,8 @@ public:
|
|||||||
virtual void SetWiimoteDeviceIndex(u8 index) = 0;
|
virtual void SetWiimoteDeviceIndex(u8 index) = 0;
|
||||||
|
|
||||||
// Called every ~200hz after HID channels are established.
|
// Called every ~200hz after HID channels are established.
|
||||||
virtual void Update() = 0;
|
virtual void PrepareInput(WiimoteEmu::DesiredWiimoteState* target_state) = 0;
|
||||||
|
virtual void Update(const WiimoteEmu::DesiredWiimoteState& target_state) = 0;
|
||||||
|
|
||||||
void SetInterruptCallback(InterruptCallbackType callback) { m_callback = std::move(callback); }
|
void SetInterruptCallback(InterruptCallbackType callback) { m_callback = std::move(callback); }
|
||||||
|
|
||||||
@ -42,8 +48,10 @@ public:
|
|||||||
// Does not include HID-type header.
|
// Does not include HID-type header.
|
||||||
virtual void InterruptDataOutput(const u8* data, u32 size) = 0;
|
virtual void InterruptDataOutput(const u8* data, u32 size) = 0;
|
||||||
|
|
||||||
// Used to connect a disconnected wii remote on button press.
|
// Get a snapshot of the current state of the Wiimote's buttons.
|
||||||
virtual bool IsButtonPressed() = 0;
|
// Note that only the button bits of the return value are meaningful, the rest should be ignored.
|
||||||
|
// This is used to query a disconnected Wiimote whether it wants to reconnect.
|
||||||
|
virtual ButtonData GetCurrentlyPressedButtons() = 0;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
void InterruptDataInputCallback(const u8* data, u32 size)
|
void InterruptDataInputCallback(const u8* data, u32 size)
|
||||||
|
@ -448,7 +448,7 @@ void Wiimote::UpdateButtonsStatus(const DesiredWiimoteState& target_state)
|
|||||||
m_status.buttons.hex = target_state.buttons.hex & ButtonData::BUTTON_MASK;
|
m_status.buttons.hex = target_state.buttons.hex & ButtonData::BUTTON_MASK;
|
||||||
}
|
}
|
||||||
|
|
||||||
DesiredWiimoteState Wiimote::BuildDesiredWiimoteState()
|
void Wiimote::BuildDesiredWiimoteState(DesiredWiimoteState* target_state)
|
||||||
{
|
{
|
||||||
// Hotkey / settings modifier
|
// Hotkey / settings modifier
|
||||||
// Data is later accessed in IsSideways and IsUpright
|
// Data is later accessed in IsSideways and IsUpright
|
||||||
@ -457,36 +457,35 @@ DesiredWiimoteState Wiimote::BuildDesiredWiimoteState()
|
|||||||
// Update our motion simulations.
|
// Update our motion simulations.
|
||||||
StepDynamics();
|
StepDynamics();
|
||||||
|
|
||||||
DesiredWiimoteState wiimote_state;
|
|
||||||
|
|
||||||
// Fetch pressed buttons from user input.
|
// Fetch pressed buttons from user input.
|
||||||
m_buttons->GetState(&wiimote_state.buttons.hex, button_bitmasks);
|
target_state->buttons.hex = 0;
|
||||||
m_dpad->GetState(&wiimote_state.buttons.hex,
|
m_buttons->GetState(&target_state->buttons.hex, button_bitmasks);
|
||||||
|
m_dpad->GetState(&target_state->buttons.hex,
|
||||||
IsSideways() ? dpad_sideways_bitmasks : dpad_bitmasks);
|
IsSideways() ? dpad_sideways_bitmasks : dpad_bitmasks);
|
||||||
|
|
||||||
// Calculate accelerometer state.
|
// Calculate accelerometer state.
|
||||||
// Calibration values are 8-bit but we want 10-bit precision, so << 2.
|
// Calibration values are 8-bit but we want 10-bit precision, so << 2.
|
||||||
wiimote_state.acceleration =
|
target_state->acceleration =
|
||||||
ConvertAccelData(GetTotalAcceleration(), ACCEL_ZERO_G << 2, ACCEL_ONE_G << 2);
|
ConvertAccelData(GetTotalAcceleration(), ACCEL_ZERO_G << 2, ACCEL_ONE_G << 2);
|
||||||
|
|
||||||
// Calculate IR camera state.
|
// Calculate IR camera state.
|
||||||
wiimote_state.camera_points = CameraLogic::GetCameraPoints(
|
target_state->camera_points = CameraLogic::GetCameraPoints(
|
||||||
GetTotalTransformation(),
|
GetTotalTransformation(),
|
||||||
Common::Vec2(m_fov_x_setting.GetValue(), m_fov_y_setting.GetValue()) / 360 *
|
Common::Vec2(m_fov_x_setting.GetValue(), m_fov_y_setting.GetValue()) / 360 *
|
||||||
float(MathUtil::TAU));
|
float(MathUtil::TAU));
|
||||||
|
|
||||||
// Calculate MotionPlus state.
|
// Calculate MotionPlus state.
|
||||||
if (m_motion_plus_setting.GetValue())
|
if (m_motion_plus_setting.GetValue())
|
||||||
wiimote_state.motion_plus = MotionPlus::GetGyroscopeData(GetTotalAngularVelocity());
|
target_state->motion_plus = MotionPlus::GetGyroscopeData(GetTotalAngularVelocity());
|
||||||
|
else
|
||||||
|
target_state->motion_plus = std::nullopt;
|
||||||
|
|
||||||
// Build Extension state.
|
// Build Extension state.
|
||||||
// This also allows the extension to perform any regular duties it may need.
|
// This also allows the extension to perform any regular duties it may need.
|
||||||
// (e.g. Nunchuk motion simulation step)
|
// (e.g. Nunchuk motion simulation step)
|
||||||
static_cast<Extension*>(
|
static_cast<Extension*>(
|
||||||
m_attachments->GetAttachmentList()[m_attachments->GetSelectedAttachment()].get())
|
m_attachments->GetAttachmentList()[m_attachments->GetSelectedAttachment()].get())
|
||||||
->BuildDesiredExtensionState(&wiimote_state.extension);
|
->BuildDesiredExtensionState(&target_state->extension);
|
||||||
|
|
||||||
return wiimote_state;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
u8 Wiimote::GetWiimoteDeviceIndex() const
|
u8 Wiimote::GetWiimoteDeviceIndex() const
|
||||||
@ -500,13 +499,14 @@ void Wiimote::SetWiimoteDeviceIndex(u8 index)
|
|||||||
}
|
}
|
||||||
|
|
||||||
// This is called every ::Wiimote::UPDATE_FREQ (200hz)
|
// This is called every ::Wiimote::UPDATE_FREQ (200hz)
|
||||||
void Wiimote::Update()
|
void Wiimote::PrepareInput(WiimoteEmu::DesiredWiimoteState* target_state)
|
||||||
{
|
{
|
||||||
const auto lock = GetStateLock();
|
const auto lock = GetStateLock();
|
||||||
|
BuildDesiredWiimoteState(target_state);
|
||||||
|
}
|
||||||
|
|
||||||
// Build target state.
|
void Wiimote::Update(const WiimoteEmu::DesiredWiimoteState& target_state)
|
||||||
auto target_state = BuildDesiredWiimoteState();
|
{
|
||||||
|
|
||||||
// Update buttons in the status struct which is sent in 99% of input reports.
|
// Update buttons in the status struct which is sent in 99% of input reports.
|
||||||
UpdateButtonsStatus(target_state);
|
UpdateButtonsStatus(target_state);
|
||||||
|
|
||||||
@ -656,14 +656,15 @@ void Wiimote::SendDataReport(const DesiredWiimoteState& target_state)
|
|||||||
m_reporting_mode = InputReportID::ReportInterleave1;
|
m_reporting_mode = InputReportID::ReportInterleave1;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Wiimote::IsButtonPressed()
|
ButtonData Wiimote::GetCurrentlyPressedButtons()
|
||||||
{
|
{
|
||||||
u16 buttons = 0;
|
|
||||||
const auto lock = GetStateLock();
|
const auto lock = GetStateLock();
|
||||||
m_buttons->GetState(&buttons, button_bitmasks);
|
|
||||||
m_dpad->GetState(&buttons, dpad_bitmasks);
|
|
||||||
|
|
||||||
return buttons != 0;
|
ButtonData buttons{};
|
||||||
|
m_buttons->GetState(&buttons.hex, button_bitmasks);
|
||||||
|
m_dpad->GetState(&buttons.hex, IsSideways() ? dpad_sideways_bitmasks : dpad_bitmasks);
|
||||||
|
|
||||||
|
return buttons;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Wiimote::LoadDefaults(const ControllerInterface& ciface)
|
void Wiimote::LoadDefaults(const ControllerInterface& ciface)
|
||||||
|
@ -132,11 +132,12 @@ public:
|
|||||||
u8 GetWiimoteDeviceIndex() const override;
|
u8 GetWiimoteDeviceIndex() const override;
|
||||||
void SetWiimoteDeviceIndex(u8 index) override;
|
void SetWiimoteDeviceIndex(u8 index) override;
|
||||||
|
|
||||||
void Update() override;
|
void PrepareInput(WiimoteEmu::DesiredWiimoteState* target_state) override;
|
||||||
|
void Update(const WiimoteEmu::DesiredWiimoteState& target_state) override;
|
||||||
void EventLinked() override;
|
void EventLinked() override;
|
||||||
void EventUnlinked() override;
|
void EventUnlinked() override;
|
||||||
void InterruptDataOutput(const u8* data, u32 size) override;
|
void InterruptDataOutput(const u8* data, u32 size) override;
|
||||||
bool IsButtonPressed() override;
|
WiimoteCommon::ButtonData GetCurrentlyPressedButtons() override;
|
||||||
|
|
||||||
void Reset();
|
void Reset();
|
||||||
|
|
||||||
@ -157,7 +158,7 @@ private:
|
|||||||
|
|
||||||
void StepDynamics();
|
void StepDynamics();
|
||||||
void UpdateButtonsStatus(const DesiredWiimoteState& target_state);
|
void UpdateButtonsStatus(const DesiredWiimoteState& target_state);
|
||||||
DesiredWiimoteState BuildDesiredWiimoteState();
|
void BuildDesiredWiimoteState(DesiredWiimoteState* target_state);
|
||||||
|
|
||||||
// Returns simulated accelerometer data in m/s^2.
|
// Returns simulated accelerometer data in m/s^2.
|
||||||
Common::Vec3 GetAcceleration(
|
Common::Vec3 GetAcceleration(
|
||||||
|
@ -460,7 +460,12 @@ void Wiimote::SetWiimoteDeviceIndex(u8 index)
|
|||||||
m_bt_device_index = index;
|
m_bt_device_index = index;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Wiimote::Update()
|
void Wiimote::PrepareInput(WiimoteEmu::DesiredWiimoteState* target_state)
|
||||||
|
{
|
||||||
|
// Nothing to do here on real Wiimotes.
|
||||||
|
}
|
||||||
|
|
||||||
|
void Wiimote::Update(const WiimoteEmu::DesiredWiimoteState& target_state)
|
||||||
{
|
{
|
||||||
// Wii remotes send input at 200hz once a Wii enables "sniff mode" on the connection.
|
// Wii remotes send input at 200hz once a Wii enables "sniff mode" on the connection.
|
||||||
// PC bluetooth stacks do not enable sniff mode causing remotes to send input at only 100hz.
|
// PC bluetooth stacks do not enable sniff mode causing remotes to send input at only 100hz.
|
||||||
@ -485,7 +490,7 @@ void Wiimote::Update()
|
|||||||
u32(rpt.size() - REPORT_HID_HEADER_SIZE));
|
u32(rpt.size() - REPORT_HID_HEADER_SIZE));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Wiimote::IsButtonPressed()
|
ButtonData Wiimote::GetCurrentlyPressedButtons()
|
||||||
{
|
{
|
||||||
Report& rpt = m_last_input_report;
|
Report& rpt = m_last_input_report;
|
||||||
if (rpt.size() >= 4)
|
if (rpt.size() >= 4)
|
||||||
@ -499,10 +504,10 @@ bool Wiimote::IsButtonPressed()
|
|||||||
ButtonData buttons = {};
|
ButtonData buttons = {};
|
||||||
builder->GetCoreData(&buttons);
|
builder->GetCoreData(&buttons);
|
||||||
|
|
||||||
return buttons.hex != 0;
|
return buttons;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return ButtonData{};
|
||||||
}
|
}
|
||||||
|
|
||||||
void Wiimote::Prepare()
|
void Wiimote::Prepare()
|
||||||
|
@ -66,10 +66,11 @@ public:
|
|||||||
u8 GetWiimoteDeviceIndex() const override;
|
u8 GetWiimoteDeviceIndex() const override;
|
||||||
void SetWiimoteDeviceIndex(u8 index) override;
|
void SetWiimoteDeviceIndex(u8 index) override;
|
||||||
|
|
||||||
void Update() override;
|
void PrepareInput(WiimoteEmu::DesiredWiimoteState* target_state) override;
|
||||||
|
void Update(const WiimoteEmu::DesiredWiimoteState& target_state) override;
|
||||||
void EventLinked() override;
|
void EventLinked() override;
|
||||||
void EventUnlinked() override;
|
void EventUnlinked() override;
|
||||||
bool IsButtonPressed() override;
|
WiimoteCommon::ButtonData GetCurrentlyPressedButtons() override;
|
||||||
|
|
||||||
void EmuStop();
|
void EmuStop();
|
||||||
|
|
||||||
|
@ -19,6 +19,7 @@
|
|||||||
#include "Core/HW/Memmap.h"
|
#include "Core/HW/Memmap.h"
|
||||||
#include "Core/HW/SystemTimers.h"
|
#include "Core/HW/SystemTimers.h"
|
||||||
#include "Core/HW/Wiimote.h"
|
#include "Core/HW/Wiimote.h"
|
||||||
|
#include "Core/HW/WiimoteEmu/DesiredWiimoteState.h"
|
||||||
#include "Core/IOS/Device.h"
|
#include "Core/IOS/Device.h"
|
||||||
#include "Core/IOS/IOS.h"
|
#include "Core/IOS/IOS.h"
|
||||||
#include "Core/SysConf.h"
|
#include "Core/SysConf.h"
|
||||||
@ -58,7 +59,7 @@ BluetoothEmuDevice::BluetoothEmuDevice(Kernel& ios, const std::string& device_na
|
|||||||
DEBUG_LOG_FMT(IOS_WIIMOTE, "Wii Remote {} BT ID {:x},{:x},{:x},{:x},{:x},{:x}", i, tmp_bd[0],
|
DEBUG_LOG_FMT(IOS_WIIMOTE, "Wii Remote {} BT ID {:x},{:x},{:x},{:x},{:x},{:x}", i, tmp_bd[0],
|
||||||
tmp_bd[1], tmp_bd[2], tmp_bd[3], tmp_bd[4], tmp_bd[5]);
|
tmp_bd[1], tmp_bd[2], tmp_bd[3], tmp_bd[4], tmp_bd[5]);
|
||||||
|
|
||||||
m_wiimotes.emplace_back(std::make_unique<WiimoteDevice>(this, tmp_bd, i));
|
m_wiimotes[i] = std::make_unique<WiimoteDevice>(this, tmp_bd, i);
|
||||||
}
|
}
|
||||||
|
|
||||||
bt_dinf.num_registered = MAX_BBMOTES;
|
bt_dinf.num_registered = MAX_BBMOTES;
|
||||||
@ -340,8 +341,16 @@ void BluetoothEmuDevice::Update()
|
|||||||
{
|
{
|
||||||
g_controller_interface.SetCurrentInputChannel(ciface::InputChannel::Bluetooth);
|
g_controller_interface.SetCurrentInputChannel(ciface::InputChannel::Bluetooth);
|
||||||
g_controller_interface.UpdateInput();
|
g_controller_interface.UpdateInput();
|
||||||
for (auto& wiimote : m_wiimotes)
|
|
||||||
wiimote->UpdateInput();
|
std::array<WiimoteEmu::DesiredWiimoteState, MAX_BBMOTES> wiimote_states;
|
||||||
|
std::array<WiimoteDevice::NextUpdateInputCall, MAX_BBMOTES> next_call;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < m_wiimotes.size(); ++i)
|
||||||
|
next_call[i] = m_wiimotes[i]->PrepareInput(&wiimote_states[i]);
|
||||||
|
|
||||||
|
for (size_t i = 0; i < m_wiimotes.size(); ++i)
|
||||||
|
m_wiimotes[i]->UpdateInput(next_call[i], wiimote_states[i]);
|
||||||
|
|
||||||
m_last_ticks = now;
|
m_last_ticks = now;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -60,7 +60,7 @@ public:
|
|||||||
void DoState(PointerWrap& p) override;
|
void DoState(PointerWrap& p) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::vector<std::unique_ptr<WiimoteDevice>> m_wiimotes;
|
std::array<std::unique_ptr<WiimoteDevice>, MAX_BBMOTES> m_wiimotes;
|
||||||
|
|
||||||
bdaddr_t m_controller_bd{{0x11, 0x02, 0x19, 0x79, 0x00, 0xff}};
|
bdaddr_t m_controller_bd{{0x11, 0x02, 0x19, 0x79, 0x00, 0xff}};
|
||||||
|
|
||||||
|
@ -21,6 +21,7 @@
|
|||||||
#include "Core/HW/Wiimote.h"
|
#include "Core/HW/Wiimote.h"
|
||||||
#include "Core/HW/WiimoteCommon/WiimoteConstants.h"
|
#include "Core/HW/WiimoteCommon/WiimoteConstants.h"
|
||||||
#include "Core/HW/WiimoteCommon/WiimoteHid.h"
|
#include "Core/HW/WiimoteCommon/WiimoteHid.h"
|
||||||
|
#include "Core/HW/WiimoteEmu/DesiredWiimoteState.h"
|
||||||
#include "Core/Host.h"
|
#include "Core/Host.h"
|
||||||
#include "Core/IOS/USB/Bluetooth/BTEmu.h"
|
#include "Core/IOS/USB/Bluetooth/BTEmu.h"
|
||||||
#include "Core/IOS/USB/Bluetooth/WiimoteHIDAttr.h"
|
#include "Core/IOS/USB/Bluetooth/WiimoteHIDAttr.h"
|
||||||
@ -341,25 +342,51 @@ void WiimoteDevice::Update()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void WiimoteDevice::UpdateInput()
|
WiimoteDevice::NextUpdateInputCall
|
||||||
|
WiimoteDevice::PrepareInput(WiimoteEmu::DesiredWiimoteState* wiimote_state)
|
||||||
{
|
{
|
||||||
if (m_connection_request_counter)
|
if (m_connection_request_counter)
|
||||||
--m_connection_request_counter;
|
--m_connection_request_counter;
|
||||||
|
|
||||||
if (!IsSourceValid())
|
if (!IsSourceValid())
|
||||||
return;
|
return NextUpdateInputCall::None;
|
||||||
|
|
||||||
// Allow button press to trigger activation after a second of no connection activity.
|
if (m_baseband_state == BasebandState::Inactive)
|
||||||
if (!m_connection_request_counter && m_baseband_state == BasebandState::Inactive)
|
|
||||||
{
|
{
|
||||||
if (Wiimote::NetPlay_GetButtonPress(GetNumber(), m_hid_source->IsButtonPressed()))
|
// Allow button press to trigger activation after a second of no connection activity.
|
||||||
Activate(true);
|
if (!m_connection_request_counter)
|
||||||
|
{
|
||||||
|
wiimote_state->buttons = m_hid_source->GetCurrentlyPressedButtons();
|
||||||
|
return NextUpdateInputCall::Activate;
|
||||||
|
}
|
||||||
|
return NextUpdateInputCall::None;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Verify interrupt channel is connected and configured.
|
// Verify interrupt channel is connected and configured.
|
||||||
const auto* channel = FindChannelWithPSM(L2CAP_PSM_HID_INTR);
|
const auto* channel = FindChannelWithPSM(L2CAP_PSM_HID_INTR);
|
||||||
if (channel && channel->IsComplete())
|
if (channel && channel->IsComplete())
|
||||||
m_hid_source->Update();
|
{
|
||||||
|
m_hid_source->PrepareInput(wiimote_state);
|
||||||
|
return NextUpdateInputCall::Update;
|
||||||
|
}
|
||||||
|
return NextUpdateInputCall::None;
|
||||||
|
}
|
||||||
|
|
||||||
|
void WiimoteDevice::UpdateInput(NextUpdateInputCall next_call,
|
||||||
|
const WiimoteEmu::DesiredWiimoteState& wiimote_state)
|
||||||
|
{
|
||||||
|
switch (next_call)
|
||||||
|
{
|
||||||
|
case NextUpdateInputCall::Activate:
|
||||||
|
if (wiimote_state.buttons.hex & WiimoteCommon::ButtonData::BUTTON_MASK)
|
||||||
|
Activate(true);
|
||||||
|
break;
|
||||||
|
case NextUpdateInputCall::Update:
|
||||||
|
m_hid_source->Update(wiimote_state);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// This function receives L2CAP commands from the CPU
|
// This function receives L2CAP commands from the CPU
|
||||||
|
@ -13,6 +13,11 @@
|
|||||||
|
|
||||||
class PointerWrap;
|
class PointerWrap;
|
||||||
|
|
||||||
|
namespace WiimoteEmu
|
||||||
|
{
|
||||||
|
struct DesiredWiimoteState;
|
||||||
|
}
|
||||||
|
|
||||||
namespace IOS::HLE
|
namespace IOS::HLE
|
||||||
{
|
{
|
||||||
class BluetoothEmuDevice;
|
class BluetoothEmuDevice;
|
||||||
@ -38,7 +43,15 @@ public:
|
|||||||
void Update();
|
void Update();
|
||||||
|
|
||||||
// Called every ~200hz.
|
// Called every ~200hz.
|
||||||
void UpdateInput();
|
enum class NextUpdateInputCall
|
||||||
|
{
|
||||||
|
None,
|
||||||
|
Activate,
|
||||||
|
Update
|
||||||
|
};
|
||||||
|
NextUpdateInputCall PrepareInput(WiimoteEmu::DesiredWiimoteState* wiimote_state);
|
||||||
|
void UpdateInput(NextUpdateInputCall next_call,
|
||||||
|
const WiimoteEmu::DesiredWiimoteState& wiimote_state);
|
||||||
|
|
||||||
void DoState(PointerWrap& p);
|
void DoState(PointerWrap& p);
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user