Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Win32: Add Rumble Support #1315

Merged
merged 13 commits into from
Nov 6, 2023
Merged
4 changes: 2 additions & 2 deletions Source/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -454,8 +454,8 @@ set(COMMON_SRC_FILES
OpticalMedia.h
PadHandler.cpp
PadHandler.h
PadListener.cpp
PadListener.h
PadInterface.cpp
PadInterface.h
Pch.cpp
Pch.h
PH_Generic.cpp
Expand Down
6 changes: 3 additions & 3 deletions Source/PH_Generic.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,19 +19,19 @@ CPadHandler::FactoryFunction CPH_Generic::GetFactoryFunction()

void CPH_Generic::Update(uint8* ram)
{
for(auto& listener : m_listeners)
for(auto& interface : m_interfaces)
{
for(unsigned int i = 0; i < PS2::CControllerInfo::MAX_BUTTONS; i++)
{
auto button = static_cast<PS2::CControllerInfo::BUTTON>(i);
if(PS2::CControllerInfo::IsAxis(button))
{
float buttonValue = ((m_axisStates[i] + 1.0f) / 2.0f) * 255.f;
listener->SetAxisState(0, button, static_cast<uint8>(buttonValue), ram);
interface->SetAxisState(0, button, static_cast<uint8>(buttonValue), ram);
}
else
{
listener->SetButtonState(0, button, m_buttonStates[i], ram);
interface->SetButtonState(0, button, m_buttonStates[i], ram);
}
}
}
Expand Down
6 changes: 3 additions & 3 deletions Source/PadHandler.cpp
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
#include "PadHandler.h"

void CPadHandler::InsertListener(CPadListener* pListener)
void CPadHandler::InsertListener(CPadInterface* pListener)
{
m_listeners.push_back(pListener);
m_interfaces.push_back(pListener);
}

void CPadHandler::RemoveAllListeners()
{
m_listeners.clear();
m_interfaces.clear();
}
8 changes: 4 additions & 4 deletions Source/PadHandler.h
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#ifndef _PADHANDLER_H_
#define _PADHANDLER_H_

#include "PadListener.h"
#include "PadInterface.h"
#include <list>
#include <functional>

Expand All @@ -13,12 +13,12 @@ class CPadHandler
CPadHandler() = default;
virtual ~CPadHandler() = default;
virtual void Update(uint8*) = 0;
void InsertListener(CPadListener*);
void InsertListener(CPadInterface*);
void RemoveAllListeners();

protected:
typedef std::list<CPadListener*> ListenerList;
ListenerList m_listeners;
typedef std::list<CPadInterface*> ListenerList;
ListenerList m_interfaces;
};

#endif
70 changes: 35 additions & 35 deletions Source/PadListener.cpp → Source/PadInterface.cpp
Original file line number Diff line number Diff line change
@@ -1,35 +1,35 @@
#include <assert.h>
#include "PadListener.h"
using namespace PS2;
uint32 CPadListener::GetButtonMask(CControllerInfo::BUTTON button)
{
static uint32 buttonMask[CControllerInfo::MAX_BUTTONS] =
{
static_cast<uint32>(-1),
static_cast<uint32>(-1),
static_cast<uint32>(-1),
static_cast<uint32>(-1),
0x1000,
0x4000,
0x8000,
0x2000,
0x0100,
0x0800,
0x0080,
0x0010,
0x0020,
0x0040,
0x0004, //L1
0x0001, //L2
0x0200, //L3
0x0008, //R1
0x0002, //R2
0x0400, //R3
};
uint32 result = buttonMask[button];
assert(result != -1);
return result;
}
#include <assert.h>
#include "PadInterface.h"

using namespace PS2;

uint32 CPadInterface::GetButtonMask(CControllerInfo::BUTTON button)
{
static uint32 buttonMask[CControllerInfo::MAX_BUTTONS] =
{
static_cast<uint32>(-1),
static_cast<uint32>(-1),
static_cast<uint32>(-1),
static_cast<uint32>(-1),
0x1000,
0x4000,
0x8000,
0x2000,
0x0100,
0x0800,
0x0080,
0x0010,
0x0020,
0x0040,
0x0004, //L1
0x0001, //L2
0x0200, //L3
0x0008, //R1
0x0002, //R2
0x0400, //R3
};

uint32 result = buttonMask[button];
assert(result != -1);
return result;
}
27 changes: 14 additions & 13 deletions Source/PadListener.h → Source/PadInterface.h
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
#pragma once

#include "Types.h"
#include "ControllerInfo.h"

class CPadListener
{
public:
virtual ~CPadListener() = default;
virtual void SetButtonState(unsigned int, PS2::CControllerInfo::BUTTON, bool, uint8*) = 0;
virtual void SetAxisState(unsigned int, PS2::CControllerInfo::BUTTON, uint8, uint8*) = 0;
static uint32 GetButtonMask(PS2::CControllerInfo::BUTTON);
};
#pragma once

#include "Types.h"
#include "ControllerInfo.h"

class CPadInterface
{
public:
virtual ~CPadInterface() = default;
virtual void SetButtonState(unsigned int, PS2::CControllerInfo::BUTTON, bool, uint8*) = 0;
virtual void SetAxisState(unsigned int, PS2::CControllerInfo::BUTTON, uint8, uint8*) = 0;
virtual void GetVibration(unsigned int, uint8& largeMotor, uint8& smallMotor) = 0;
static uint32 GetButtonMask(PS2::CControllerInfo::BUTTON);
};
144 changes: 144 additions & 0 deletions Source/input/InputBindingManager.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#include <cassert>
#include "InputBindingManager.h"
#include "ThreadUtils.h"
#include "AppConfig.h"
#include "string_format.h"

Expand Down Expand Up @@ -151,6 +152,17 @@ std::string CInputBindingManager::GetTargetDescription(const BINDINGTARGET& targ
return provider->GetTargetDescription(target);
}

std::vector<DEVICEINFO> CInputBindingManager::GetDevices() const
{
std::vector<DEVICEINFO> devices;
for(auto& [_, provider] : m_providers)
{
auto providerDevices = provider->GetDevices();
devices.insert(devices.end(), providerDevices.begin(), providerDevices.end());
}
return devices;
}

void CInputBindingManager::OnInputEventReceived(const BINDINGTARGET& target, uint32 value)
{
for(unsigned int pad = 0; pad < MAX_PADS; pad++)
Expand Down Expand Up @@ -192,6 +204,10 @@ void CInputBindingManager::Reload()
}
CPovHatBinding::RegisterPreferences(*m_config, prefBase.c_str());
}
{
auto prefBase = Framework::CConfig::MakePreferenceName(CONFIG_PREFIX, m_padPreferenceName[pad], "motor");
RegisterBindingTargetPreference(*m_config, Framework::CConfig::MakePreferenceName(prefBase, CONFIG_BINDINGTARGET1).c_str());
}
}

for(unsigned int pad = 0; pad < MAX_PADS; pad++)
Expand Down Expand Up @@ -226,6 +242,12 @@ void CInputBindingManager::Reload()
}
m_bindings[pad][button] = binding;
}
{
auto binding = std::make_shared<CMotorBinding>(m_providers);
auto prefBase = Framework::CConfig::MakePreferenceName(CONFIG_PREFIX, m_padPreferenceName[pad], "motor");
binding->Load(*m_config, prefBase.c_str());
m_motorBindings[pad] = binding;
}
}
ResetBindingValues();
}
Expand Down Expand Up @@ -256,6 +278,21 @@ void CInputBindingManager::Save()
m_config->SetPreferenceInteger(prefBindingType.c_str(), BINDING_UNBOUND);
}
}

{
auto prefBase = Framework::CConfig::MakePreferenceName(CONFIG_PREFIX, m_padPreferenceName[pad], "motor");
auto prefBindingType = Framework::CConfig::MakePreferenceName(prefBase, CONFIG_BINDING_TYPE);
const auto& binding = m_motorBindings[pad];
if(binding)
{
m_config->SetPreferenceInteger(prefBindingType.c_str(), binding->GetBindingType());
binding->Save(*m_config, prefBase.c_str());
}
else
{
m_config->SetPreferenceInteger(prefBindingType.c_str(), BINDING_UNBOUND);
}
}
}
m_config->Save();
}
Expand All @@ -269,6 +306,20 @@ const CInputBindingManager::CBinding* CInputBindingManager::GetBinding(uint32 pa
return m_bindings[pad][button].get();
}

CInputBindingManager::CMotorBinding* CInputBindingManager::GetMotorBinding(uint32 pad) const
{
if(pad >= MAX_PADS)
{
throw std::exception();
}
return m_motorBindings[pad].get();
}

void CInputBindingManager::SetMotorBinding(uint32 pad, const BINDINGTARGET& binding)
{
m_motorBindings[pad] = std::make_shared<CMotorBinding>(binding, m_providers);
}

float CInputBindingManager::GetAnalogSensitivity(uint32 pad) const
{
return m_analogSensitivity[pad];
Expand Down Expand Up @@ -571,3 +622,96 @@ void CInputBindingManager::CSimulatedAxisBinding::Load(Framework::CConfig& confi
m_key1Binding = LoadBindingTargetPreference(config, key1PrefBase.c_str());
m_key2Binding = LoadBindingTargetPreference(config, key2PrefBase.c_str());
}

////////////////////////////////////////////////
// CMotorBinding, Specialised binding that can communicate back to a provider
////////////////////////////////////////////////
CInputBindingManager::CMotorBinding::CMotorBinding(const BINDINGTARGET& binding, const CInputBindingManager::ProviderMap& providers)
: m_binding(binding)
, m_providers(providers)
, m_running(true)
, m_nextTimeout(std::chrono::steady_clock::now())
{
m_thread = std::thread(&CInputBindingManager::CMotorBinding::ThreadProc, this);
Framework::ThreadUtils::SetThreadName(m_thread, "MotorBinding Thread");
}

CInputBindingManager::CMotorBinding::CMotorBinding(ProviderMap& providers)
: CMotorBinding(BINDINGTARGET(), providers)
{
}

CInputBindingManager::CMotorBinding::CMotorBinding()
: CMotorBinding(BINDINGTARGET(), {})
{
}

CInputBindingManager::CMotorBinding::~CMotorBinding()
{
m_running = false;
m_cv.notify_all();
if(m_thread.joinable())
{
m_thread.join();
}
}

void CInputBindingManager::CMotorBinding::ProcessEvent(uint8 largeMotor, uint8 smallMotor)
{
for(auto& [id, provider] : m_providers)
{
if(id == m_binding.providerId)
{
provider->SetVibration(m_binding.deviceId, largeMotor, smallMotor);
if(largeMotor + smallMotor)
{
m_nextTimeout = std::chrono::steady_clock::now() + std::chrono::seconds(1);
m_cv.notify_all();
}
}
}
}

CInputBindingManager::BINDINGTYPE CInputBindingManager::CMotorBinding::GetBindingType() const
{
return BINDING_MOTOR;
}

BINDINGTARGET CInputBindingManager::CMotorBinding::GetBindingTarget() const
{
return m_binding;
}

void CInputBindingManager::CMotorBinding::Save(Framework::CConfig& config, const char* buttonBase) const
{
auto prefBase = Framework::CConfig::MakePreferenceName(buttonBase, CONFIG_BINDINGTARGET1);
SaveBindingTargetPreference(config, prefBase.c_str(), m_binding);
}

void CInputBindingManager::CMotorBinding::Load(Framework::CConfig& config, const char* buttonBase)
{
auto prefBase = Framework::CConfig::MakePreferenceName(buttonBase, CONFIG_BINDINGTARGET1);
m_binding = LoadBindingTargetPreference(config, prefBase.c_str());
}

void CInputBindingManager::CMotorBinding::ThreadProc()
{
while(m_running)
{
std::unique_lock<std::mutex> lock(m_mutex);
m_cv.wait(lock);

while(m_running && m_nextTimeout.load() > std::chrono::steady_clock::now())
{
std::this_thread::sleep_for(std::chrono::milliseconds(16));
}

for(auto& [id, provider] : m_providers)
{
if(id == m_binding.providerId)
{
provider->SetVibration(m_binding.deviceId, 0, 0);
}
}
}
}
Loading
Loading