Skip to content

Commit

Permalink
Merge pull request #1315 from Zer0xFF/rumble
Browse files Browse the repository at this point in the history
Win32: Add Rumble Support
  • Loading branch information
jpd002 authored Nov 6, 2023
2 parents 985ff95 + f513e7c commit f1c5006
Show file tree
Hide file tree
Showing 23 changed files with 480 additions and 121 deletions.
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

0 comments on commit f1c5006

Please sign in to comment.