mirror of https://github.com/SourMesen/Mesen2
SNES: Added new controller type that supports rumble
This commit is contained in:
parent
13ee75aa05
commit
5350959230
|
|
@ -586,6 +586,7 @@
|
|||
<ClInclude Include="Netplay\ClientConnectionData.h" />
|
||||
<ClInclude Include="SNES\DSP\DspTypes.h" />
|
||||
<ClInclude Include="SNES\DSP\DspVoice.h" />
|
||||
<ClInclude Include="SNES\Input\SnesRumbleController.h" />
|
||||
<ClInclude Include="SNES\SnesCpu.Shared.h" />
|
||||
<ClInclude Include="SNES\Coprocessors\SA1\CpuBwRamHandler.h" />
|
||||
<ClInclude Include="SNES\Debugger\SnesDebugger.h" />
|
||||
|
|
@ -978,6 +979,7 @@
|
|||
<ClCompile Include="SNES\Debugger\TraceLogger\St018TraceLogger.cpp" />
|
||||
<ClCompile Include="SNES\DSP\Dsp.cpp" />
|
||||
<ClCompile Include="SNES\DSP\DspVoice.cpp" />
|
||||
<ClCompile Include="SNES\Input\SnesRumbleController.cpp" />
|
||||
<ClCompile Include="SNES\SnesConsole.cpp" />
|
||||
<ClCompile Include="Shared\EmulatorLock.cpp" />
|
||||
<ClCompile Include="SNES\SnesControlManager.cpp" />
|
||||
|
|
|
|||
|
|
@ -2982,6 +2982,9 @@
|
|||
<ClInclude Include="GBA\GbaWaitStates.h">
|
||||
<Filter>GBA</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="SNES\Input\SnesRumbleController.h">
|
||||
<Filter>SNES\Input</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="Shared\Video\RotateFilter.cpp">
|
||||
|
|
@ -3344,6 +3347,9 @@
|
|||
<ClCompile Include="SNES\Debugger\St018DisUtils.cpp">
|
||||
<Filter>SNES\Debugger</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="SNES\Input\SnesRumbleController.cpp">
|
||||
<Filter>SNES\Input</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Filter Include="PCE">
|
||||
|
|
|
|||
|
|
@ -0,0 +1,52 @@
|
|||
#include "pch.h"
|
||||
#include "SNES/Input/SnesRumbleController.h"
|
||||
#include "SNES/SnesConsole.h"
|
||||
#include "SNES/InternalRegisters.h"
|
||||
#include "Shared/Emulator.h"
|
||||
#include "Shared/EmuSettings.h"
|
||||
#include "Shared/KeyManager.h"
|
||||
|
||||
SnesRumbleController::SnesRumbleController(Emulator* emu, SnesConsole* console, uint8_t port, KeyMappingSet keyMappings) : SnesController(emu, port, keyMappings)
|
||||
{
|
||||
_console = console;
|
||||
_type = ControllerType::SnesRumbleController;
|
||||
}
|
||||
|
||||
SnesRumbleController::~SnesRumbleController()
|
||||
{
|
||||
KeyManager::SetForceFeedback(0, 0);
|
||||
}
|
||||
|
||||
void SnesRumbleController::Serialize(Serializer& s)
|
||||
{
|
||||
SnesController::Serialize(s);
|
||||
SV(_rumbleData);
|
||||
}
|
||||
|
||||
uint8_t SnesRumbleController::ReadRam(uint16_t addr)
|
||||
{
|
||||
if(IsCurrentPort(addr)) {
|
||||
uint8_t ioPort = _console->GetInternalRegisters()->GetIoPortOutput();
|
||||
|
||||
//Technically, when plugged into port 2, this uses bit 7, but activating the rumble
|
||||
//in both ports at the same time could potentially draw too much current, so the
|
||||
//UI current prevents picking a rumble controller for P2
|
||||
uint8_t ioBit = (GetPort() == 0 ? (ioPort >> 6) : (ioPort >> 7)) & 0x01;
|
||||
|
||||
_rumbleData = (_rumbleData << 1) | ioBit;
|
||||
|
||||
if((_rumbleData & 0xFF00) == 0x7200) {
|
||||
uint8_t rumble = _rumbleData & 0xFF;
|
||||
|
||||
//Multiply by 4369 to use all values from 0 to 65535
|
||||
uint16_t rightRumble = (rumble >> 4) * 4369;
|
||||
uint16_t leftRumble = (rumble & 0x0F) * 4369;
|
||||
|
||||
KeyManager::SetForceFeedback(rightRumble, leftRumble);
|
||||
|
||||
_rumbleData = 0;
|
||||
}
|
||||
}
|
||||
|
||||
return SnesController::ReadRam(addr);
|
||||
}
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
#pragma once
|
||||
#include "pch.h"
|
||||
#include "Shared/BaseControlDevice.h"
|
||||
#include "SNES/Input/SnesController.h"
|
||||
#include "Utilities/Serializer.h"
|
||||
|
||||
class Emulator;
|
||||
class SnesConsole;
|
||||
|
||||
class SnesRumbleController : public SnesController
|
||||
{
|
||||
private:
|
||||
SnesConsole* _console = nullptr;
|
||||
uint16_t _rumbleData = 0;
|
||||
|
||||
protected:
|
||||
void Serialize(Serializer& s) override;
|
||||
|
||||
public:
|
||||
SnesRumbleController(Emulator* emu, SnesConsole* console, uint8_t port, KeyMappingSet keyMappings);
|
||||
virtual ~SnesRumbleController();
|
||||
|
||||
uint8_t ReadRam(uint16_t addr) override;
|
||||
};
|
||||
|
|
@ -10,6 +10,7 @@
|
|||
#include "Shared/Interfaces/IInputProvider.h"
|
||||
#include "Shared/Interfaces/IInputRecorder.h"
|
||||
#include "SNES/Input/SnesController.h"
|
||||
#include "SNES/Input/SnesRumbleController.h"
|
||||
#include "SNES/Input/SnesMouse.h"
|
||||
#include "SNES/Input/Multitap.h"
|
||||
#include "SNES/Input/SuperScope.h"
|
||||
|
|
@ -62,6 +63,10 @@ shared_ptr<BaseControlDevice> SnesControlManager::CreateControllerDevice(Control
|
|||
device.reset(new Multitap(_console, port, controllers));
|
||||
break;
|
||||
}
|
||||
|
||||
case ControllerType::SnesRumbleController:
|
||||
device.reset(new SnesRumbleController(_emu, _console, port, port == 0 ? cfg.Port1.Keys : cfg.Port2.Keys));
|
||||
break;
|
||||
}
|
||||
|
||||
return device;
|
||||
|
|
|
|||
|
|
@ -45,5 +45,5 @@ public:
|
|||
virtual void ResetKeyState() = 0;
|
||||
virtual void SetDisabled(bool disabled) = 0;
|
||||
|
||||
virtual void SetForceFeedback(uint16_t magnitude) {}
|
||||
virtual void SetForceFeedback(uint16_t magnitudeRight, uint16_t magnitudeLeft) {}
|
||||
};
|
||||
|
|
@ -135,9 +135,15 @@ MousePosition KeyManager::GetMousePosition()
|
|||
return _mousePosition;
|
||||
}
|
||||
|
||||
void KeyManager::SetForceFeedback(uint16_t magnitude)
|
||||
void KeyManager::SetForceFeedback(uint16_t magnitudeRight, uint16_t magnitudeLeft)
|
||||
{
|
||||
if(_keyManager != nullptr) {
|
||||
_keyManager->SetForceFeedback(magnitude * _settings->GetInputConfig().ForceFeedbackIntensity);
|
||||
double intensity = _settings->GetInputConfig().ForceFeedbackIntensity;
|
||||
_keyManager->SetForceFeedback(magnitudeRight * intensity, magnitudeLeft * intensity);
|
||||
}
|
||||
}
|
||||
|
||||
void KeyManager::SetForceFeedback(uint16_t magnitude)
|
||||
{
|
||||
SetForceFeedback(magnitude, magnitude);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -37,4 +37,5 @@ public:
|
|||
static MousePosition GetMousePosition();
|
||||
|
||||
static void SetForceFeedback(uint16_t magnitude);
|
||||
static void SetForceFeedback(uint16_t magnitudeRight, uint16_t magnitudeLeft);
|
||||
};
|
||||
|
|
@ -181,6 +181,7 @@ enum class ControllerType
|
|||
SnesMouse,
|
||||
SuperScope,
|
||||
Multitap,
|
||||
SnesRumbleController,
|
||||
|
||||
//NES controllers
|
||||
NesController,
|
||||
|
|
|
|||
|
|
@ -248,14 +248,14 @@ optional<int16_t> LinuxGameController::GetAxisPosition(int axis)
|
|||
return axis & 0x01 ? axisValue : -axisValue;
|
||||
}
|
||||
|
||||
void LinuxGameController::SetForceFeedback(uint16_t magnitude)
|
||||
void LinuxGameController::SetForceFeedback(uint16_t magnitudeRight, uint16_t magnitudeLeft)
|
||||
{
|
||||
if(!_rumbleEffect || !_enableForceFeedback) {
|
||||
return;
|
||||
}
|
||||
|
||||
_rumbleEffect->u.rumble.strong_magnitude = magnitude;
|
||||
_rumbleEffect->u.rumble.weak_magnitude = magnitude;
|
||||
_rumbleEffect->u.rumble.strong_magnitude = magnitudeLeft;
|
||||
_rumbleEffect->u.rumble.weak_magnitude = magnitudeRight;
|
||||
int rc = ioctl(_fd, EVIOCSFF, _rumbleEffect.get());
|
||||
if(rc < 0) {
|
||||
//MessageManager::Log("Could not update force feedback effect.");
|
||||
|
|
|
|||
|
|
@ -35,5 +35,5 @@ public:
|
|||
bool IsButtonPressed(int buttonNumber);
|
||||
optional<int16_t> GetAxisPosition(int axis);
|
||||
|
||||
void SetForceFeedback(uint16_t magnitude);
|
||||
void SetForceFeedback(uint16_t rightMagnitude, uint16_t leftMagnitude);
|
||||
};
|
||||
|
|
@ -214,9 +214,9 @@ void LinuxKeyManager::SetDisabled(bool disabled)
|
|||
_disableAllKeys = disabled;
|
||||
}
|
||||
|
||||
void LinuxKeyManager::SetForceFeedback(uint16_t magnitude)
|
||||
void LinuxKeyManager::SetForceFeedback(uint16_t magnitudeRight, uint16_t magnitudeLeft)
|
||||
{
|
||||
for(auto& controller : _controllers) {
|
||||
controller->SetForceFeedback(magnitude);
|
||||
controller->SetForceFeedback(magnitudeRight, magnitudeLeft);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -46,5 +46,5 @@ public:
|
|||
|
||||
void SetDisabled(bool disabled) override;
|
||||
|
||||
void SetForceFeedback(uint16_t magnitude) override;
|
||||
void SetForceFeedback(uint16_t magnitudeRight, uint16_t magnitudeLeft) override;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -34,5 +34,5 @@ public:
|
|||
bool IsButtonPressed(int buttonNumber);
|
||||
std::optional<int16_t> GetAxisPosition(int axis);
|
||||
|
||||
void SetForceFeedback(uint16_t magnitude);
|
||||
void SetForceFeedback(uint16_t magnitudeRight, uint16_t magnitudeLeft);
|
||||
};
|
||||
|
|
|
|||
|
|
@ -115,7 +115,7 @@ std::optional<int16_t> MacOSGameController::GetAxisPosition(int axis)
|
|||
return _axisState[axis];
|
||||
}
|
||||
|
||||
void MacOSGameController::SetForceFeedback(uint16_t magnitude)
|
||||
void MacOSGameController::SetForceFeedback(uint16_t magnitudeRight, uint16_t magnitudeLeft)
|
||||
{
|
||||
NSError* error = nil;
|
||||
|
||||
|
|
@ -134,11 +134,11 @@ void MacOSGameController::SetForceFeedback(uint16_t magnitude)
|
|||
}
|
||||
|
||||
//If magnitude is zero, only stop current effect
|
||||
if(magnitude == 0) {
|
||||
if(magnitudeRight == 0 && magnitudeLeft == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
double strength = magnitude / (double) UINT16_MAX;
|
||||
double strength = (magnitudeRight < magnitudeLeft ? magnitudeLeft : magnitudeRight) / (double)UINT16_MAX;
|
||||
CHHapticEventParameter* intensityPar = [[CHHapticEventParameter alloc] initWithParameterID:CHHapticEventParameterIDHapticIntensity value:strength];
|
||||
CHHapticEventParameter* sharpnessPar = [[CHHapticEventParameter alloc] initWithParameterID:CHHapticEventParameterIDHapticSharpness value:0.6];
|
||||
CHHapticEvent* event = [[CHHapticEvent alloc] initWithEventType:CHHapticEventTypeHapticContinuous parameters:@[intensityPar, sharpnessPar] relativeTime:0.0 duration:GCHapticDurationInfinite];
|
||||
|
|
|
|||
|
|
@ -61,5 +61,5 @@ public:
|
|||
|
||||
void SetDisabled(bool disabled) override;
|
||||
|
||||
void SetForceFeedback(uint16_t magnitude) override;
|
||||
void SetForceFeedback(uint16_t magnitudeRight, uint16_t magnitudeLeft) override;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -215,9 +215,9 @@ void MacOSKeyManager::SetDisabled(bool disabled)
|
|||
_disableAllKeys = disabled;
|
||||
}
|
||||
|
||||
void MacOSKeyManager::SetForceFeedback(uint16_t magnitude)
|
||||
void MacOSKeyManager::SetForceFeedback(uint16_t magnitudeRight, uint16_t magnitudeLeft)
|
||||
{
|
||||
for(auto& controller : _controllers) {
|
||||
controller->SetForceFeedback(magnitude);
|
||||
controller->SetForceFeedback(magnitudeRight, magnitudeLeft);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -351,6 +351,7 @@ namespace Mesen.Config
|
|||
SnesMouse,
|
||||
SuperScope,
|
||||
Multitap,
|
||||
SnesRumbleController,
|
||||
|
||||
//NES controllers
|
||||
NesController,
|
||||
|
|
@ -417,6 +418,7 @@ namespace Mesen.Config
|
|||
{
|
||||
switch(type) {
|
||||
case ControllerType.SnesController:
|
||||
case ControllerType.SnesRumbleController:
|
||||
case ControllerType.NesController:
|
||||
case ControllerType.FamicomController:
|
||||
case ControllerType.FamicomControllerP2:
|
||||
|
|
@ -440,6 +442,7 @@ namespace Mesen.Config
|
|||
{
|
||||
switch(type) {
|
||||
case ControllerType.SnesController:
|
||||
case ControllerType.SnesRumbleController:
|
||||
case ControllerType.NesController:
|
||||
case ControllerType.FamicomController:
|
||||
case ControllerType.FamicomControllerP2:
|
||||
|
|
@ -461,6 +464,7 @@ namespace Mesen.Config
|
|||
{
|
||||
switch(type) {
|
||||
case ControllerType.SnesController:
|
||||
case ControllerType.SnesRumbleController:
|
||||
case ControllerType.NesController:
|
||||
case ControllerType.FamicomController:
|
||||
case ControllerType.FamicomControllerP2:
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ namespace Mesen.Config
|
|||
m.Left = InputApi.GetKeyCode("A");
|
||||
m.Right = InputApi.GetKeyCode("D");
|
||||
|
||||
if(type == ControllerType.SnesController) {
|
||||
if(type == ControllerType.SnesController || type == ControllerType.SnesRumbleController) {
|
||||
m.X = InputApi.GetKeyCode(";");
|
||||
m.Y = InputApi.GetKeyCode("M");
|
||||
m.L = InputApi.GetKeyCode("U");
|
||||
|
|
@ -79,7 +79,7 @@ namespace Mesen.Config
|
|||
m.Left = InputApi.GetKeyCode("Left Arrow");
|
||||
m.Right = InputApi.GetKeyCode("Right Arrow");
|
||||
|
||||
if(type == ControllerType.SnesController) {
|
||||
if(type == ControllerType.SnesController || type == ControllerType.SnesRumbleController) {
|
||||
m.X = InputApi.GetKeyCode("X");
|
||||
m.Y = InputApi.GetKeyCode("Z");
|
||||
m.L = InputApi.GetKeyCode("Q");
|
||||
|
|
@ -145,7 +145,7 @@ namespace Mesen.Config
|
|||
m.Left = InputApi.GetKeyCode(prefix + "Left");
|
||||
m.Right = InputApi.GetKeyCode(prefix + "Right");
|
||||
|
||||
if(type == ControllerType.SnesController || type == ControllerType.PceAvenuePad6 || type == ControllerType.GbaController) {
|
||||
if(type == ControllerType.SnesController || type == ControllerType.PceAvenuePad6 || type == ControllerType.GbaController || type == ControllerType.SnesRumbleController) {
|
||||
m.X = InputApi.GetKeyCode(prefix + "Y");
|
||||
m.Y = InputApi.GetKeyCode(prefix + "X");
|
||||
m.L = InputApi.GetKeyCode(prefix + "L1");
|
||||
|
|
@ -190,7 +190,7 @@ namespace Mesen.Config
|
|||
m.Down = InputApi.GetKeyCode(prefix + "DPad Down");
|
||||
m.Left = InputApi.GetKeyCode(prefix + "DPad Left");
|
||||
m.Right = InputApi.GetKeyCode(prefix + "DPad Right");
|
||||
if(type == ControllerType.SnesController || type == ControllerType.PceAvenuePad6 || type == ControllerType.GbaController) {
|
||||
if(type == ControllerType.SnesController || type == ControllerType.PceAvenuePad6 || type == ControllerType.GbaController || type == ControllerType.SnesRumbleController) {
|
||||
m.X = InputApi.GetKeyCode(prefix + "But4");
|
||||
m.Y = InputApi.GetKeyCode(prefix + "But1");
|
||||
m.L = InputApi.GetKeyCode(prefix + "But5");
|
||||
|
|
|
|||
|
|
@ -186,6 +186,7 @@ namespace Mesen.Config
|
|||
break;
|
||||
|
||||
case ControllerType.SnesController:
|
||||
case ControllerType.SnesRumbleController:
|
||||
case ControllerType.NesController:
|
||||
case ControllerType.FamicomController:
|
||||
case ControllerType.FamicomControllerP2:
|
||||
|
|
|
|||
|
|
@ -78,6 +78,7 @@ namespace Mesen.Config
|
|||
break;
|
||||
|
||||
case ControllerType.SnesController:
|
||||
case ControllerType.SnesRumbleController:
|
||||
base.ClearKeys(type);
|
||||
break;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2002,6 +2002,7 @@ E
|
|||
<Enum ID="ControllerType">
|
||||
<Value ID="None">None</Value>
|
||||
<Value ID="SnesController">SNES Controller</Value>
|
||||
<Value ID="SnesRumbleController">SNES Rumble</Value>
|
||||
<Value ID="SnesMouse">SNES Mouse</Value>
|
||||
<Value ID="SuperScope">Super Scope</Value>
|
||||
<Value ID="Multitap">Super Multitap</Value>
|
||||
|
|
|
|||
|
|
@ -20,6 +20,7 @@ namespace Mesen.ViewModels
|
|||
ControllerType.SnesMouse,
|
||||
ControllerType.SuperScope,
|
||||
ControllerType.Multitap,
|
||||
ControllerType.SnesRumbleController,
|
||||
};
|
||||
|
||||
public Enum[] AvailableControllerTypesMultitap => new Enum[] {
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ namespace Mesen.Views
|
|||
|
||||
if(mappings != null) {
|
||||
return mappings.Type switch {
|
||||
ControllerType.SnesController => new SnesControllerView(),
|
||||
ControllerType.SnesController or ControllerType.SnesRumbleController => new SnesControllerView(),
|
||||
ControllerType.NesController => new NesControllerView(),
|
||||
ControllerType.FamicomController => new NesControllerView(),
|
||||
ControllerType.FamicomControllerP2 => new NesControllerView(true),
|
||||
|
|
|
|||
|
|
@ -229,9 +229,9 @@ void WindowsKeyManager::SetDisabled(bool disabled)
|
|||
_disableAllKeys = disabled;
|
||||
}
|
||||
|
||||
void WindowsKeyManager::SetForceFeedback(uint16_t magnitude)
|
||||
void WindowsKeyManager::SetForceFeedback(uint16_t magnitudeRight, uint16_t magnitudeLeft)
|
||||
{
|
||||
_xInput->SetForceFeedback(magnitude);
|
||||
_xInput->SetForceFeedback(magnitudeRight, magnitudeLeft);
|
||||
}
|
||||
|
||||
void WindowsKeyManager::ResetKeyState()
|
||||
|
|
|
|||
|
|
@ -50,7 +50,7 @@ public:
|
|||
void ResetKeyState() override;
|
||||
void SetDisabled(bool disabled) override;
|
||||
|
||||
void SetForceFeedback(uint16_t magnitude) override;
|
||||
void SetForceFeedback(uint16_t magnitudeRight, uint16_t magnitudeLeft) override;
|
||||
|
||||
void UpdateDevices() override;
|
||||
};
|
||||
|
|
@ -95,11 +95,11 @@ optional<int16_t> XInputManager::GetAxisPosition(uint8_t port, int axis)
|
|||
return std::nullopt;
|
||||
}
|
||||
|
||||
void XInputManager::SetForceFeedback(uint16_t magnitude)
|
||||
void XInputManager::SetForceFeedback(uint16_t magnitudeRight, uint16_t magnitudeLeft)
|
||||
{
|
||||
XINPUT_VIBRATION settings = {};
|
||||
settings.wLeftMotorSpeed = magnitude;
|
||||
settings.wRightMotorSpeed = magnitude;
|
||||
settings.wRightMotorSpeed = magnitudeRight;
|
||||
settings.wLeftMotorSpeed = magnitudeLeft;
|
||||
|
||||
for(int i = 0; i < XUSER_MAX_COUNT; i++) {
|
||||
if(_enableForceFeedback[i]) {
|
||||
|
|
|
|||
|
|
@ -23,5 +23,5 @@ class XInputManager
|
|||
bool IsPressed(uint8_t gamepadPort, uint8_t button);
|
||||
optional<int16_t> GetAxisPosition(uint8_t gamepadPort, int axis);
|
||||
|
||||
void SetForceFeedback(uint16_t magnitude);
|
||||
void SetForceFeedback(uint16_t magnitudeRight, uint16_t magnitudeLeft);
|
||||
};
|
||||
|
|
|
|||
Loading…
Reference in New Issue