Merge pull request #1560 from magcius/pad-cleanup-1

Pad cleanup 1
This commit is contained in:
Ryan Houdek
2014-12-07 01:22:03 -06:00
36 changed files with 275 additions and 1249 deletions
+4 -54
View File
@@ -64,68 +64,18 @@ void GetStatus(u8 _numPAD, GCPadStatus* _pPADStatus)
return;
}
// if we are on the next input cycle, update output and input
// if we can get a lock
static int _last_numPAD = 4;
if (_numPAD <= _last_numPAD)
{
g_controller_interface.UpdateOutput();
g_controller_interface.UpdateInput();
}
_last_numPAD = _numPAD;
// get input
((GCPad*)s_config.controllers[_numPAD])->GetInput(_pPADStatus);
}
// __________________________________________________________________________________________________
// Function: Rumble
// Purpose: Pad rumble!
// input: _numPad - Which pad to rumble.
// _uType - Command type (Stop=0, Rumble=1, Stop Hard=2).
// _uStrength - Strength of the Rumble
// output: none
//
void Rumble(u8 _numPAD, unsigned int _uType, unsigned int _uStrength)
void Rumble(u8 _numPAD, const ControlState strength)
{
std::unique_lock<std::recursive_mutex> lk(s_config.controls_lock, std::try_to_lock);
if (lk.owns_lock())
{
// TODO: this has potential to not stop rumble if user is messing with GUI at the perfect time
// set rumble
if (1 == _uType && _uStrength > 2)
{
((GCPad*)s_config.controllers[ _numPAD ])->SetOutput(255);
}
else
{
((GCPad*)s_config.controllers[ _numPAD ])->SetOutput(0);
}
}
}
if (!lk.owns_lock())
return;
// __________________________________________________________________________________________________
// Function: Motor
// Purpose: For devices with constant Force feedback
// input: _numPAD - The pad to operate on
// _uType - 06 = Motor On, 04 = Motor Off
// _uStrength - 00 = Left Strong, 127 = Left Weak, 128 = Right Weak, 255 = Right Strong
// output: none
//
void Motor(u8 _numPAD, unsigned int _uType, unsigned int _uStrength)
{
std::unique_lock<std::recursive_mutex> lk(s_config.controls_lock, std::try_to_lock);
if (lk.owns_lock())
{
// TODO: this has potential to not stop rumble if user is messing with GUI at the perfect time
// set rumble
if (_uType == 6)
{
((GCPad*)s_config.controllers[ _numPAD ])->SetMotor(_uStrength);
}
}
((GCPad*)s_config.controllers[ _numPAD ])->SetOutput(strength);
}
bool GetMicButton(u8 pad)
+1 -2
View File
@@ -17,8 +17,7 @@ void Initialize(void* const hwnd);
InputConfig* GetConfig();
void GetStatus(u8 _numPAD, GCPadStatus* _pPADStatus);
void Rumble(u8 _numPAD, unsigned int _uType, unsigned int _uStrength);
void Motor(u8 _numPAD, unsigned int _uType, unsigned int _uStrength);
void Rumble(u8 _numPAD, const ControlState strength);
bool GetMicButton(u8 pad);
}
+2 -9
View File
@@ -120,16 +120,9 @@ void GCPad::GetInput(GCPadStatus* const pad)
pad->triggerRight = static_cast<u8>(triggers[1] * 0xFF);
}
void GCPad::SetMotor(const u8 on)
void GCPad::SetOutput(const ControlState strength)
{
// map 0..255 to -1.0..1.0
ControlState force = on / 127.5 - 1;
m_rumble->controls[0]->control_ref->State(force);
}
void GCPad::SetOutput(const u8 on)
{
m_rumble->controls[0]->control_ref->State(on);
m_rumble->controls[0]->control_ref->State(strength);
}
void GCPad::LoadDefaults(const ControllerInterface& ciface)
+1 -2
View File
@@ -14,8 +14,7 @@ public:
GCPad(const unsigned int index);
void GetInput(GCPadStatus* const pad);
void SetOutput(const u8 on);
void SetMotor(const u8 on);
void SetOutput(const ControlState strength);
bool GetMicButton() const;
+15 -225
View File
@@ -2,250 +2,40 @@
// Licensed under GPLv2
// Refer to the license.txt file included.
#include "Core/Core.h"
#include "Core/CoreTiming.h"
#include "Core/Movie.h"
#include "Core/HW/EXI_Device.h"
#include "Core/HW/EXI_DeviceMic.h"
#include "Core/HW/GCPad.h"
#include "Core/HW/ProcessorInterface.h"
#include "Core/HW/SI.h"
#include "Core/HW/SI_Device.h"
#include "Core/HW/SI_DeviceDanceMat.h"
#include "Core/HW/SystemTimers.h"
// --- Dance mat GameCube controller ---
CSIDevice_DanceMat::CSIDevice_DanceMat(SIDevices device, int _iDeviceNumber)
: ISIDevice(device, _iDeviceNumber)
, m_TButtonComboStart(0)
, m_TButtonCombo(0)
, m_LastButtonCombo(COMBO_NONE)
: CSIDevice_GCController(device, _iDeviceNumber) {}
u32 CSIDevice_DanceMat::MapPadStatus(const GCPadStatus& pad_status)
{
memset(&m_Origin, 0, sizeof(SOrigin));
m_Origin.uCommand = CMD_ORIGIN;
m_Origin.uOriginStickX = 0x80; // center
m_Origin.uOriginStickY = 0x80;
m_Origin.uSubStickStickX = 0x80;
m_Origin.uSubStickStickY = 0x80;
m_Origin.uTrigger_L = 0x00;
m_Origin.uTrigger_R = 0x00;
// Dunno if we need to do this, game/lib should set it?
m_Mode = 0x03;
}
int CSIDevice_DanceMat::RunBuffer(u8* _pBuffer, int _iLength)
{
// For debug logging only
ISIDevice::RunBuffer(_pBuffer, _iLength);
// Read the command
EBufferCommands command = static_cast<EBufferCommands>(_pBuffer[3]);
// Handle it
switch (command)
{
case CMD_RESET:
*(u32*)&_pBuffer[0] = SI_DANCEMAT;
break;
case CMD_DIRECT:
{
INFO_LOG(SERIALINTERFACE, "PAD - Direct (Length: %d)", _iLength);
u32 high, low;
GetData(high, low);
for (int i = 0; i < (_iLength - 1) / 2; i++)
{
_pBuffer[i + 0] = (high >> (i * 8)) & 0xff;
_pBuffer[i + 4] = (low >> (i * 8)) & 0xff;
}
}
break;
case CMD_ORIGIN:
{
INFO_LOG(SERIALINTERFACE, "PAD - Get Origin");
u8* pCalibration = reinterpret_cast<u8*>(&m_Origin);
for (int i = 0; i < (int)sizeof(SOrigin); i++)
{
_pBuffer[i ^ 3] = *pCalibration++;
}
}
break;
// Recalibrate (FiRES: i am not 100 percent sure about this)
case CMD_RECALIBRATE:
{
INFO_LOG(SERIALINTERFACE, "PAD - Recalibrate");
u8* pCalibration = reinterpret_cast<u8*>(&m_Origin);
for (int i = 0; i < (int)sizeof(SOrigin); i++)
{
_pBuffer[i ^ 3] = *pCalibration++;
}
}
break;
// DEFAULT
default:
{
ERROR_LOG(SERIALINTERFACE, "Unknown SI command (0x%x)", command);
PanicAlert("SI: Unknown command (0x%x)", command);
}
break;
}
return _iLength;
}
// GetData
// Return true on new data (max 7 Bytes and 6 bits ;)
// [00?SYXBA] [1LRZUDRL] [x] [y] [cx] [cy] [l] [r]
// |\_ ERR_LATCH (error latched - check SISR)
// |_ ERR_STATUS (error on last GetData or SendCmd?)
bool CSIDevice_DanceMat::GetData(u32& _Hi, u32& _Low)
{
GCPadStatus PadStatus;
memset(&PadStatus, 0, sizeof(PadStatus));
Pad::GetStatus(ISIDevice::m_iDeviceNumber, &PadStatus);
Movie::CallGCInputManip(&PadStatus, ISIDevice::m_iDeviceNumber);
Movie::SetPolledDevice();
if (NetPlay_GetInput(ISIDevice::m_iDeviceNumber, &PadStatus))
{
}
else if (Movie::IsPlayingInput())
{
Movie::PlayController(&PadStatus, ISIDevice::m_iDeviceNumber);
Movie::InputUpdate();
}
else if (Movie::IsRecordingInput())
{
Movie::RecordInput(&PadStatus, ISIDevice::m_iDeviceNumber);
Movie::InputUpdate();
}
else
{
Movie::CheckPadStatus(&PadStatus, ISIDevice::m_iDeviceNumber);
}
// Map the dpad to the blue arrows, the buttons to the orange arrows
// Z = + button, Start = - button
u16 map = 0;
if (PadStatus.button & PAD_BUTTON_UP)
if (pad_status.button & PAD_BUTTON_UP)
map |= 0x1000;
if (PadStatus.button & PAD_BUTTON_DOWN)
if (pad_status.button & PAD_BUTTON_DOWN)
map |= 0x2;
if (PadStatus.button & PAD_BUTTON_LEFT)
if (pad_status.button & PAD_BUTTON_LEFT)
map |= 0x8;
if (PadStatus.button & PAD_BUTTON_RIGHT)
if (pad_status.button & PAD_BUTTON_RIGHT)
map |= 0x4;
if (PadStatus.button & PAD_BUTTON_Y)
if (pad_status.button & PAD_BUTTON_Y)
map |= 0x200;
if (PadStatus.button & PAD_BUTTON_A)
if (pad_status.button & PAD_BUTTON_A)
map |= 0x10;
if (PadStatus.button & PAD_BUTTON_B)
if (pad_status.button & PAD_BUTTON_B)
map |= 0x100;
if (PadStatus.button & PAD_BUTTON_X)
if (pad_status.button & PAD_BUTTON_X)
map |= 0x800;
if (PadStatus.button & PAD_TRIGGER_Z)
if (pad_status.button & PAD_TRIGGER_Z)
map |= 0x400;
if (PadStatus.button & PAD_BUTTON_START)
if (pad_status.button & PAD_BUTTON_START)
map |= 0x1;
_Hi = (u32)(map << 16) | 0x8080;
// Low bits are packed differently per mode
if (m_Mode == 0 || m_Mode == 5 || m_Mode == 6 || m_Mode == 7)
{
_Low = (u8)(PadStatus.analogB >> 4); // Top 4 bits
_Low |= (u32)((u8)(PadStatus.analogA >> 4) << 4); // Top 4 bits
_Low |= (u32)((u8)(PadStatus.triggerRight >> 4) << 8); // Top 4 bits
_Low |= (u32)((u8)(PadStatus.triggerLeft >> 4) << 12); // Top 4 bits
_Low |= (u32)((u8)(PadStatus.substickY) << 16); // All 8 bits
_Low |= (u32)((u8)(PadStatus.substickX) << 24); // All 8 bits
}
else if (m_Mode == 1)
{
_Low = (u8)(PadStatus.analogB >> 4); // Top 4 bits
_Low |= (u32)((u8)(PadStatus.analogA >> 4) << 4); // Top 4 bits
_Low |= (u32)((u8)PadStatus.triggerRight << 8); // All 8 bits
_Low |= (u32)((u8)PadStatus.triggerLeft << 16); // All 8 bits
_Low |= (u32)((u8)PadStatus.substickY << 24); // Top 4 bits
_Low |= (u32)((u8)PadStatus.substickX << 28); // Top 4 bits
}
else if (m_Mode == 2)
{
// Identifies the dance mat
_Low = 0x8080ffff;
}
else if (m_Mode == 3)
{
// Analog A/B are always 0
_Low = (u8)PadStatus.triggerRight; // All 8 bits
_Low |= (u32)((u8)PadStatus.triggerLeft << 8); // All 8 bits
_Low |= (u32)((u8)PadStatus.substickY << 16); // All 8 bits
_Low |= (u32)((u8)PadStatus.substickX << 24); // All 8 bits
}
else if (m_Mode == 4)
{
_Low = (u8)(PadStatus.analogB); // All 8 bits
_Low |= (u32)((u8)(PadStatus.analogA) << 8); // All 8 bits
// triggerLeft/Right are always 0
_Low |= (u32)((u8)PadStatus.substickY << 16); // All 8 bits
_Low |= (u32)((u8)PadStatus.substickX << 24); // All 8 bits
}
return true;
return (u32)(map << 16) | 0x8080;
}
// SendCommand
void CSIDevice_DanceMat::SendCommand(u32 _Cmd, u8 _Poll)
void CSIDevice_DanceMat::HandleButtonCombos(const GCPadStatus& pad_status)
{
UCommand command(_Cmd);
switch (command.Command)
{
// Costis sent it in some demos :)
case 0x00:
break;
case CMD_WRITE:
{
unsigned int uType = command.Parameter1; // 0 = stop, 1 = rumble, 2 = stop hard
unsigned int uStrength = command.Parameter2;
// get the correct pad number that should rumble locally when using netplay
const u8 numPAD = NetPlay_InGamePadToLocalPad(ISIDevice::m_iDeviceNumber);
if (numPAD < 4)
Pad::Rumble(numPAD, uType, uStrength);
if (!_Poll)
{
m_Mode = command.Parameter2;
INFO_LOG(SERIALINTERFACE, "PAD %i set to mode %i", ISIDevice::m_iDeviceNumber, m_Mode);
}
}
break;
default:
{
ERROR_LOG(SERIALINTERFACE, "Unknown direct command (0x%x)", _Cmd);
PanicAlert("SI: Unknown direct command");
}
break;
}
}
// Savestate support
void CSIDevice_DanceMat::DoState(PointerWrap& p)
{
p.Do(m_Origin);
p.Do(m_Mode);
p.Do(m_TButtonComboStart);
p.Do(m_TButtonCombo);
p.Do(m_LastButtonCombo);
}
+4 -90
View File
@@ -4,98 +4,12 @@
#pragma once
#include "Core/HW/SI_Device.h"
#include "InputCommon/GCPadStatus.h"
#include "Core/HW/SI_DeviceGCController.h"
// standard GameCube controller
class CSIDevice_DanceMat : public ISIDevice
class CSIDevice_DanceMat : public CSIDevice_GCController
{
private:
// Commands
enum EBufferCommands
{
CMD_RESET = 0x00,
CMD_DIRECT = 0x40,
CMD_ORIGIN = 0x41,
CMD_RECALIBRATE = 0x42,
};
struct SOrigin
{
u8 uCommand;// Maybe should be button bits?
u8 unk_1; // ..and this would be the other half
u8 uOriginStickX;
u8 uOriginStickY;
u8 uSubStickStickX;
u8 uSubStickStickY;
u8 uTrigger_L;
u8 uTrigger_R;
u8 unk_4;
u8 unk_5;
u8 unk_6;
u8 unk_7;
};
enum EDirectCommands
{
CMD_WRITE = 0x40
};
union UCommand
{
u32 Hex;
struct
{
u32 Parameter1 : 8;
u32 Parameter2 : 8;
u32 Command : 8;
u32 : 8;
};
UCommand() {Hex = 0;}
UCommand(u32 _iValue) {Hex = _iValue;}
};
enum EButtonCombo
{
COMBO_NONE = 0,
COMBO_ORIGIN,
COMBO_RESET
};
// struct to compare input against
// Set on connection and (standard pad only) on button combo
SOrigin m_Origin;
// PADAnalogMode
u8 m_Mode;
// Timer to track special button combos:
// y, X, start for 3 seconds updates origin with current status
// Technically, the above is only on standard pad, wavebird does not support it for example
// b, x, start for 3 seconds triggers reset (PI reset button interrupt)
u64 m_TButtonComboStart, m_TButtonCombo;
// Type of button combo from the last/current poll
EButtonCombo m_LastButtonCombo;
public:
// Constructor
CSIDevice_DanceMat(SIDevices device, int _iDeviceNumber);
// Run the SI Buffer
virtual int RunBuffer(u8* _pBuffer, int _iLength) override;
// Send and Receive pad input from network
static bool NetPlay_GetInput(u8 numPAD, GCPadStatus* status);
static u8 NetPlay_InGamePadToLocalPad(u8 numPAD);
// Return true on new data
virtual bool GetData(u32& _Hi, u32& _Low) override;
// Send a command directly
virtual void SendCommand(u32 _Cmd, u8 _Poll) override;
// Savestate support
virtual void DoState(PointerWrap& p) override;
virtual u32 MapPadStatus(const GCPadStatus& pad_status) override;
virtual void HandleButtonCombos(const GCPadStatus& pad_status) override;
};
+31 -16
View File
@@ -131,10 +131,7 @@ bool CSIDevice_GCController::GetData(u32& _Hi, u32& _Low)
Movie::CheckPadStatus(&PadStatus, ISIDevice::m_iDeviceNumber);
}
// Thankfully changing mode does not change the high bits ;)
_Hi = (u32)((u8)PadStatus.stickY);
_Hi |= (u32)((u8)PadStatus.stickX << 8);
_Hi |= (u32)((u16)(PadStatus.button | PAD_USE_ORIGIN) << 16);
_Hi = MapPadStatus(PadStatus);
// Low bits are packed differently per mode
if (m_Mode == 0 || m_Mode == 5 || m_Mode == 6 || m_Mode == 7)
@@ -181,11 +178,27 @@ bool CSIDevice_GCController::GetData(u32& _Hi, u32& _Low)
_Low |= (u32)((u8)PadStatus.substickX << 24); // All 8 bits
}
HandleButtonCombos(PadStatus);
return true;
}
u32 CSIDevice_GCController::MapPadStatus(const GCPadStatus& pad_status)
{
// Thankfully changing mode does not change the high bits ;)
u32 _Hi = 0;
_Hi = (u32)((u8)pad_status.stickY);
_Hi |= (u32)((u8)pad_status.stickX << 8);
_Hi |= (u32)((u16)(pad_status.button | PAD_USE_ORIGIN) << 16);
return _Hi;
}
void CSIDevice_GCController::HandleButtonCombos(const GCPadStatus& pad_status)
{
// Keep track of the special button combos (embedded in controller hardware... :( )
EButtonCombo tempCombo;
if ((PadStatus.button & 0xff00) == (PAD_BUTTON_Y|PAD_BUTTON_X|PAD_BUTTON_START))
if ((pad_status.button & 0xff00) == (PAD_BUTTON_Y|PAD_BUTTON_X|PAD_BUTTON_START))
tempCombo = COMBO_ORIGIN;
else if ((PadStatus.button & 0xff00) == (PAD_BUTTON_B|PAD_BUTTON_X|PAD_BUTTON_START))
else if ((pad_status.button & 0xff00) == (PAD_BUTTON_B|PAD_BUTTON_X|PAD_BUTTON_START))
tempCombo = COMBO_RESET;
else
tempCombo = COMBO_NONE;
@@ -204,21 +217,18 @@ bool CSIDevice_GCController::GetData(u32& _Hi, u32& _Low)
ProcessorInterface::ResetButton_Tap();
else if (m_LastButtonCombo == COMBO_ORIGIN)
{
m_Origin.uOriginStickX = PadStatus.stickX;
m_Origin.uOriginStickY = PadStatus.stickY;
m_Origin.uSubStickStickX = PadStatus.substickX;
m_Origin.uSubStickStickY = PadStatus.substickY;
m_Origin.uTrigger_L = PadStatus.triggerLeft;
m_Origin.uTrigger_R = PadStatus.triggerRight;
m_Origin.uOriginStickX = pad_status.stickX;
m_Origin.uOriginStickY = pad_status.stickY;
m_Origin.uSubStickStickX = pad_status.substickX;
m_Origin.uSubStickStickY = pad_status.substickY;
m_Origin.uTrigger_L = pad_status.triggerLeft;
m_Origin.uTrigger_R = pad_status.triggerRight;
}
m_LastButtonCombo = COMBO_NONE;
}
}
return true;
}
// SendCommand
void CSIDevice_GCController::SendCommand(u32 _Cmd, u8 _Poll)
{
@@ -239,7 +249,12 @@ void CSIDevice_GCController::SendCommand(u32 _Cmd, u8 _Poll)
const u8 numPAD = NetPlay_InGamePadToLocalPad(ISIDevice::m_iDeviceNumber);
if (numPAD < 4)
Pad::Rumble(numPAD, uType, uStrength);
{
if (uType == 1 && uStrength > 2)
Pad::Rumble(numPAD, 1.0);
else
Pad::Rumble(numPAD, 0.0);
}
if (!_Poll)
{
+6 -5
View File
@@ -7,11 +7,9 @@
#include "Core/HW/SI_Device.h"
#include "InputCommon/GCPadStatus.h"
// standard GameCube controller
class CSIDevice_GCController : public ISIDevice
{
private:
protected:
// Commands
enum EBufferCommands
@@ -24,8 +22,8 @@ private:
struct SOrigin
{
u8 uCommand;// Maybe should be button bits?
u8 unk_1; // ..and this would be the other half
u8 uCommand; // Maybe should be button bits?
u8 unk_1; // ..and this would be the other half
u8 uOriginStickX;
u8 uOriginStickY;
u8 uSubStickStickX;
@@ -94,6 +92,9 @@ public:
// Return true on new data
virtual bool GetData(u32& _Hi, u32& _Low) override;
virtual u32 MapPadStatus(const GCPadStatus& pad_status);
virtual void HandleButtonCombos(const GCPadStatus& pad_status);
// Send a command directly
virtual void SendCommand(u32 _Cmd, u8 _Poll) override;
+24 -269
View File
@@ -2,292 +2,47 @@
// Licensed under GPLv2
// Refer to the license.txt file included.
#include "Core/Core.h"
#include "Core/CoreTiming.h"
#include "Core/Movie.h"
#include "Core/HW/EXI_Device.h"
#include "Core/HW/EXI_DeviceMic.h"
#include "Core/HW/GCPad.h"
#include "Core/HW/ProcessorInterface.h"
#include "Core/HW/SI.h"
#include "Core/HW/SI_Device.h"
#include "Core/HW/SI_DeviceGCSteeringWheel.h"
#include "Core/HW/SystemTimers.h"
// --- standard GameCube controller ---
CSIDevice_GCSteeringWheel::CSIDevice_GCSteeringWheel(SIDevices device, int _iDeviceNumber)
: ISIDevice(device, _iDeviceNumber)
, m_TButtonComboStart(0)
, m_TButtonCombo(0)
, m_LastButtonCombo(COMBO_NONE)
{
memset(&m_Origin, 0, sizeof(SOrigin));
m_Origin.uCommand = CMD_ORIGIN;
m_Origin.uOriginStickX = 0x80; // center
m_Origin.uOriginStickY = 0x80;
m_Origin.uSubStickStickX = 0x80;
m_Origin.uSubStickStickY = 0x80;
m_Origin.uTrigger_L = 0x1F; // 0-30 is the lower deadzone
m_Origin.uTrigger_R = 0x1F;
: CSIDevice_GCController(device, _iDeviceNumber)
{}
// Dunno if we need to do this, game/lib should set it?
m_Mode = 0x03;
}
int CSIDevice_GCSteeringWheel::RunBuffer(u8* _pBuffer, int _iLength)
{
// For debug logging only
ISIDevice::RunBuffer(_pBuffer, _iLength);
// Read the command
EBufferCommands command = static_cast<EBufferCommands>(_pBuffer[3]);
// Handle it
switch (command)
{
case CMD_RESET:
*(u32*)&_pBuffer[0] = SI_GC_STEERING;
break;
case CMD_ORIGIN:
{
INFO_LOG(SERIALINTERFACE, "PAD - Get Origin");
u8* pCalibration = reinterpret_cast<u8*>(&m_Origin);
for (int i = 0; i < (int)sizeof(SOrigin); i++)
{
_pBuffer[i ^ 3] = *pCalibration++;
}
}
break;
// Recalibrate (FiRES: i am not 100 percent sure about this)
case CMD_RECALIBRATE:
{
INFO_LOG(SERIALINTERFACE, "PAD - Recalibrate");
u8* pCalibration = reinterpret_cast<u8*>(&m_Origin);
for (int i = 0; i < (int)sizeof(SOrigin); i++)
{
_pBuffer[i ^ 3] = *pCalibration++;
}
}
break;
// Seen in F-Zero GX
case CMD_MOTOR_OFF:
break;
// DEFAULT
default:
{
ERROR_LOG(SERIALINTERFACE, "Unknown SI command (0x%x)", command);
}
break;
}
return _iLength;
}
// GetData
// Return true on new data (max 7 Bytes and 6 bits ;)
// [00?SYXBA] [1LRZUDRL] [x] [y] [cx] [cy] [l] [r]
// |\_ ERR_LATCH (error latched - check SISR)
// |_ ERR_STATUS (error on last GetData or SendCmd?)
bool CSIDevice_GCSteeringWheel::GetData(u32& _Hi, u32& _Low)
{
GCPadStatus PadStatus;
memset(&PadStatus, 0, sizeof(PadStatus));
Pad::GetStatus(ISIDevice::m_iDeviceNumber, &PadStatus);
Movie::CallGCInputManip(&PadStatus, ISIDevice::m_iDeviceNumber);
Movie::SetPolledDevice();
if (NetPlay_GetInput(ISIDevice::m_iDeviceNumber, &PadStatus))
{
}
else if (Movie::IsPlayingInput())
{
Movie::PlayController(&PadStatus, ISIDevice::m_iDeviceNumber);
Movie::InputUpdate();
}
else if (Movie::IsRecordingInput())
{
Movie::RecordInput(&PadStatus, ISIDevice::m_iDeviceNumber);
Movie::InputUpdate();
}
else
{
Movie::CheckPadStatus(&PadStatus, ISIDevice::m_iDeviceNumber);
}
// Thankfully changing mode does not change the high bits ;)
_Hi = (u32)((u8)PadStatus.stickX); // Steering
_Hi |= 0x800; // Pedal connected flag
_Hi |= (u32)((u16)(PadStatus.button | PAD_USE_ORIGIN) << 16);
// Low bits are packed differently per mode
if (m_Mode == 0 || m_Mode == 5 || m_Mode == 7)
{
_Low = (u8)(PadStatus.analogB >> 4); // Top 4 bits
_Low |= (u32)((u8)(PadStatus.analogA >> 4) << 4); // Top 4 bits
_Low |= (u32)((u8)(PadStatus.triggerRight >> 4) << 8); // Top 4 bits
_Low |= (u32)((u8)(PadStatus.triggerLeft >> 4) << 12); // Top 4 bits
_Low |= (u32)((u8)(PadStatus.substickY) << 16); // All 8 bits
_Low |= (u32)((u8)(PadStatus.substickX) << 24); // All 8 bits
}
else if (m_Mode == 1)
{
_Low = (u8)(PadStatus.analogB >> 4); // Top 4 bits
_Low |= (u32)((u8)(PadStatus.analogA >> 4) << 4); // Top 4 bits
_Low |= (u32)((u8)PadStatus.triggerRight << 8); // All 8 bits
_Low |= (u32)((u8)PadStatus.triggerLeft << 16); // All 8 bits
_Low |= (u32)((u8)PadStatus.substickY << 24); // Top 4 bits
_Low |= (u32)((u8)PadStatus.substickX << 28); // Top 4 bits
}
else if (m_Mode == 2)
{
_Low = (u8)(PadStatus.analogB); // All 8 bits
_Low |= (u32)((u8)(PadStatus.analogA) << 8); // All 8 bits
_Low |= (u32)((u8)(PadStatus.triggerRight >> 4) << 16); // Top 4 bits
_Low |= (u32)((u8)(PadStatus.triggerLeft >> 4) << 20); // Top 4 bits
_Low |= (u32)((u8)PadStatus.substickY << 24); // Top 4 bits
_Low |= (u32)((u8)PadStatus.substickX << 28); // Top 4 bits
}
else if (m_Mode == 3)
{
// Analog A/B are always 0
_Low = (u8)PadStatus.triggerRight; // All 8 bits
_Low |= (u32)((u8)PadStatus.triggerLeft << 8); // All 8 bits
_Low |= (u32)((u8)PadStatus.substickY << 16); // All 8 bits
_Low |= (u32)((u8)PadStatus.substickX << 24); // All 8 bits
}
else if (m_Mode == 4)
{
_Low = (u8)(PadStatus.analogB); // All 8 bits
_Low |= (u32)((u8)(PadStatus.analogA) << 8); // All 8 bits
// triggerLeft/Right are always 0
_Low |= (u32)((u8)PadStatus.substickY << 16); // All 8 bits
_Low |= (u32)((u8)PadStatus.substickX << 24); // All 8 bits
}
else if (m_Mode == 6)
{
_Low = (u8)PadStatus.triggerRight; // All 8 bits
_Low |= (u32)((u8)PadStatus.triggerLeft << 8); // All 8 bits
// The GC Steering Wheel appears to have combined pedals
// (both the Accelerate and Brake pedals are mapped to a single axis)
// We use the stickY axis for the pedals.
if (PadStatus.stickY < 128)
_Low |= (u32)((u8)(255 - ((PadStatus.stickY & 0x7f) * 2)) << 16); // All 8 bits (Brake)
if (PadStatus.stickY >= 128)
_Low |= (u32)((u8)((PadStatus.stickY & 0x7f) * 2) << 24); // All 8 bits (Accelerate)
}
// Keep track of the special button combos (embedded in controller hardware... :( )
EButtonCombo tempCombo;
if ((PadStatus.button & 0xff00) == (PAD_BUTTON_Y|PAD_BUTTON_X|PAD_BUTTON_START))
tempCombo = COMBO_ORIGIN;
else if ((PadStatus.button & 0xff00) == (PAD_BUTTON_B|PAD_BUTTON_X|PAD_BUTTON_START))
tempCombo = COMBO_RESET;
else
tempCombo = COMBO_NONE;
if (tempCombo != m_LastButtonCombo)
{
m_LastButtonCombo = tempCombo;
if (m_LastButtonCombo != COMBO_NONE)
m_TButtonComboStart = CoreTiming::GetTicks();
}
if (m_LastButtonCombo != COMBO_NONE)
{
m_TButtonCombo = CoreTiming::GetTicks();
if ((m_TButtonCombo - m_TButtonComboStart) > SystemTimers::GetTicksPerSecond() * 3)
{
if (m_LastButtonCombo == COMBO_RESET)
{
ProcessorInterface::ResetButton_Tap();
}
else if (m_LastButtonCombo == COMBO_ORIGIN)
{
m_Origin.uOriginStickX = PadStatus.stickX;
m_Origin.uOriginStickY = PadStatus.stickY;
m_Origin.uSubStickStickX = PadStatus.substickX;
m_Origin.uSubStickStickY = PadStatus.substickY;
m_Origin.uTrigger_L = PadStatus.triggerLeft;
m_Origin.uTrigger_R = PadStatus.triggerRight;
}
m_LastButtonCombo = COMBO_NONE;
}
}
return true;
}
// SendCommand
void CSIDevice_GCSteeringWheel::SendCommand(u32 _Cmd, u8 _Poll)
{
UCommand command(_Cmd);
switch (command.Command)
if (command.Command == CMD_FORCE)
{
// Costis sent it in some demos :)
case 0x00:
break;
unsigned int uStrength = command.Parameter1; // 0 = left strong, 127 = left weak, 128 = right weak, 255 = right strong
unsigned int uType = command.Parameter2; // 06 = motor on, 04 = motor off
case CMD_FORCE:
// get the correct pad number that should rumble locally when using netplay
const u8 numPAD = NetPlay_InGamePadToLocalPad(ISIDevice::m_iDeviceNumber);
if (numPAD < 4)
{
unsigned int uStrength = command.Parameter1; // 0 = left strong, 127 = left weak, 128 = right weak, 255 = right strong
unsigned int uType = command.Parameter2; // 06 = motor on, 04 = motor off
// get the correct pad number that should rumble locally when using netplay
const u8 numPAD = NetPlay_InGamePadToLocalPad(ISIDevice::m_iDeviceNumber);
if (numPAD < 4)
Pad::Motor(numPAD, uType, uStrength);
if (!_Poll)
if (uType == 0x06)
{
m_Mode = command.Parameter2;
INFO_LOG(SERIALINTERFACE, "PAD %i set to mode %i", ISIDevice::m_iDeviceNumber, m_Mode);
// map 0..255 to -1.0..1.0
ControlState strength = uStrength / 127.5 - 1;
Pad::Rumble(numPAD, strength);
}
else
{
Pad::Rumble(numPAD, 0);
}
}
break;
case CMD_WRITE:
if (!_Poll)
{
unsigned int uType = command.Parameter1; // 0 = stop, 1 = rumble, 2 = stop hard
unsigned int uStrength = command.Parameter2;
// get the correct pad number that should rumble locally when using netplay
const u8 numPAD = NetPlay_InGamePadToLocalPad(ISIDevice::m_iDeviceNumber);
if (numPAD < 4)
Pad::Rumble(numPAD, uType, uStrength);
if (!_Poll)
{
m_Mode = command.Parameter2;
INFO_LOG(SERIALINTERFACE, "PAD %i set to mode %i", ISIDevice::m_iDeviceNumber, m_Mode);
}
m_Mode = command.Parameter2;
INFO_LOG(SERIALINTERFACE, "PAD %i set to mode %i", ISIDevice::m_iDeviceNumber, m_Mode);
}
break;
default:
{
ERROR_LOG(SERIALINTERFACE, "Unknown direct command (0x%x)", _Cmd);
}
break;
}
else
{
return CSIDevice_GCController::SendCommand(_Cmd, _Poll);
}
}
// Savestate support
void CSIDevice_GCSteeringWheel::DoState(PointerWrap& p)
{
p.Do(m_Origin);
p.Do(m_Mode);
p.Do(m_TButtonComboStart);
p.Do(m_TButtonCombo);
p.Do(m_LastButtonCombo);
}
+3 -75
View File
@@ -4,14 +4,11 @@
#pragma once
#include "Core/HW/SI_Device.h"
#include "InputCommon/GCPadStatus.h"
#include "Core/HW/SI_DeviceGCController.h"
// standard GameCube controller
class CSIDevice_GCSteeringWheel : public ISIDevice
class CSIDevice_GCSteeringWheel : public CSIDevice_GCController
{
private:
// Commands
enum EBufferCommands
{
@@ -21,82 +18,13 @@ private:
CMD_MOTOR_OFF = 0xff,
};
struct SOrigin
{
u8 uCommand;// Maybe should be button bits?
u8 unk_1; // ..and this would be the other half
u8 uOriginStickX;
u8 uOriginStickY;
u8 uSubStickStickX;
u8 uSubStickStickY;
u8 uTrigger_L;
u8 uTrigger_R;
u8 unk_4;
u8 unk_5;
u8 unk_6;
u8 unk_7;
};
enum EDirectCommands
{
CMD_FORCE = 0x30,
CMD_WRITE = 0x40
};
union UCommand
{
u32 Hex;
struct
{
u32 Parameter1 : 8;
u32 Parameter2 : 8;
u32 Command : 8;
u32 : 8;
};
UCommand() {Hex = 0;}
UCommand(u32 _iValue) {Hex = _iValue;}
};
enum EButtonCombo
{
COMBO_NONE = 0,
COMBO_ORIGIN,
COMBO_RESET
};
// struct to compare input against
// Set on connection and (standard pad only) on button combo
SOrigin m_Origin;
// PADAnalogMode
u8 m_Mode;
// Timer to track special button combos:
// y, X, start for 3 seconds updates origin with current status
// Technically, the above is only on standard pad, wavebird does not support it for example
// b, x, start for 3 seconds triggers reset (PI reset button interrupt)
u64 m_TButtonComboStart, m_TButtonCombo;
// Type of button combo from the last/current poll
EButtonCombo m_LastButtonCombo;
public:
// Constructor
CSIDevice_GCSteeringWheel(SIDevices device, int _iDeviceNumber);
// Run the SI Buffer
virtual int RunBuffer(u8* _pBuffer, int _iLength) override;
// Send and Receive pad input from network
static bool NetPlay_GetInput(u8 numPAD, GCPadStatus* status);
static u8 NetPlay_InGamePadToLocalPad(u8 numPAD);
// Return true on new data
virtual bool GetData(u32& _Hi, u32& _Low) override;
// Send a command directly
virtual void SendCommand(u32 _Cmd, u8 _Poll) override;
// Savestate support
virtual void DoState(PointerWrap& p) override;
virtual void SendCommand(u32 _Cmd, u8 _Poll);
};
+14
View File
@@ -61,6 +61,8 @@ IPC_HLE_PERIOD: For the Wiimote this is the call schedule:
#include "Core/IPC_HLE/WII_IPC_HLE.h"
#include "Core/PowerPC/PowerPC.h"
#include "InputCommon/ControllerInterface/ControllerInterface.h"
#include "VideoCommon/CommandProcessor.h"
#include "VideoCommon/VideoBackendBase.h"
@@ -79,6 +81,7 @@ static int et_DSP;
static int et_IPC_HLE;
static int et_PatchEngine; // PatchEngine updates every 1/60th of a second by default
static int et_Throttle;
static int et_UpdateInput;
// These are badly educated guesses
// Feel free to experiment. Set these in Init below.
@@ -132,6 +135,14 @@ static void VICallback(u64 userdata, int cyclesLate)
CoreTiming::ScheduleEvent(VideoInterface::GetTicksPerLine() - cyclesLate, et_VI);
}
static void UpdateInputCallback(u64 userdata, int cyclesLate)
{
g_controller_interface.UpdateInput();
// Poll system input every 1/60th of a second.
CoreTiming::ScheduleEvent(SystemTimers::GetTicksPerSecond() / 60 - cyclesLate, et_UpdateInput);
}
static void SICallback(u64 userdata, int cyclesLate)
{
SerialInterface::UpdateDevices();
@@ -258,6 +269,7 @@ void Init()
et_IPC_HLE = CoreTiming::RegisterEvent("IPC_HLE_UpdateCallback", IPC_HLE_UpdateCallback);
et_PatchEngine = CoreTiming::RegisterEvent("PatchEngine", PatchEngineCallback);
et_Throttle = CoreTiming::RegisterEvent("Throttle", ThrottleCallback);
et_UpdateInput = CoreTiming::RegisterEvent("UpdateInput", UpdateInputCallback);
CoreTiming::ScheduleEvent(VideoInterface::GetTicksPerLine(), et_VI);
CoreTiming::ScheduleEvent(0, et_DSP);
@@ -271,6 +283,8 @@ void Init()
if (SConfig::GetInstance().m_LocalCoreStartupParameter.bWii)
CoreTiming::ScheduleEvent(IPC_HLE_PERIOD, et_IPC_HLE);
CoreTiming::ScheduleEvent(0, et_UpdateInput);
}
void Shutdown()
-9
View File
@@ -17,7 +17,6 @@ namespace Wiimote
{
static InputConfig s_config(WIIMOTE_INI_NAME, _trans("Wiimote"), "Wiimote");
static int s_last_number = 4;
InputConfig* GetConfig()
{
@@ -115,13 +114,6 @@ void Update(int _number)
// TODO: change this to a try_to_lock, and make it give empty input on failure
std::lock_guard<std::recursive_mutex> lk(s_config.controls_lock);
if (_number <= s_last_number)
{
g_controller_interface.UpdateOutput();
g_controller_interface.UpdateInput();
}
s_last_number = _number;
if (WIIMOTE_SRC_EMU & g_wiimote_sources[_number])
((WiimoteEmu::Wiimote*)s_config.controllers[_number])->Update();
else
@@ -154,7 +146,6 @@ void DoState(u8 **ptr, PointerWrap::Mode mode)
// TODO:
PointerWrap p(ptr, mode);
p.Do(s_last_number);
for (unsigned int i=0; i<MAX_BBMOTES; ++i)
((WiimoteEmu::Wiimote*)s_config.controllers[i])->DoState(p);
}
-20
View File
@@ -835,16 +835,6 @@ bool WiimoteEmu::Wiimote::NetPlay_GetWiimoteData(int wiimote, u8* data, u8 size)
return false;
}
bool CSIDevice_GCSteeringWheel::NetPlay_GetInput(u8 numPAD, GCPadStatus* PadStatus)
{
return false;
}
bool CSIDevice_DanceMat::NetPlay_GetInput(u8 numPAD, GCPadStatus* PadStatus)
{
return false;
}
// called from ---CPU--- thread
// so all players' games get the same time
u32 CEXIIPL::NetPlay_GetGCTime()
@@ -869,16 +859,6 @@ u8 CSIDevice_GCController::NetPlay_InGamePadToLocalPad(u8 numPAD)
return numPAD;
}
u8 CSIDevice_GCSteeringWheel::NetPlay_InGamePadToLocalPad(u8 numPAD)
{
return CSIDevice_GCController::NetPlay_InGamePadToLocalPad(numPAD);
}
u8 CSIDevice_DanceMat::NetPlay_InGamePadToLocalPad(u8 numPAD)
{
return CSIDevice_GCController::NetPlay_InGamePadToLocalPad(numPAD);
}
bool NetPlay::IsNetPlayRunning()
{
return netplay_client != nullptr;
@@ -39,9 +39,6 @@ private:
};
public:
bool UpdateInput() { return true; }
bool UpdateOutput() { return true; }
Touchscreen(int padID);
~Touchscreen() {}
@@ -98,9 +98,6 @@ void ControllerInterface::Shutdown()
for (ciface::Core::Device::Output* o : d->Outputs())
o->SetState(0);
// Update output
d->UpdateOutput();
// Delete device
delete d;
}
@@ -135,52 +132,15 @@ void ControllerInterface::Shutdown()
//
// Update input for all devices, return true if all devices returned successful
//
bool ControllerInterface::UpdateInput(const bool force)
void ControllerInterface::UpdateInput()
{
std::unique_lock<std::recursive_mutex> lk(update_lock, std::defer_lock);
if (force)
lk.lock();
else if (!lk.try_lock())
return false;
size_t ok_count = 0;
if (!lk.try_lock())
return;
for (ciface::Core::Device* d : m_devices)
{
if (d->UpdateInput())
++ok_count;
//else
// disabled. it might be causing problems
//(*d)->ClearInputState();
}
return (m_devices.size() == ok_count);
}
//
// UpdateOutput
//
// Update output for all devices, return true if all devices returned successful
//
bool ControllerInterface::UpdateOutput(const bool force)
{
std::unique_lock<std::recursive_mutex> lk(update_lock, std::defer_lock);
if (force)
lk.lock();
else if (!lk.try_lock())
return false;
size_t ok_count = 0;
for (ciface::Core::Device* d : m_devices)
{
if (d->UpdateOutput())
++ok_count;
}
return (m_devices.size() == ok_count);
d->UpdateInput();
}
//
@@ -299,14 +259,9 @@ ciface::Core::Device::Control* ControllerInterface::OutputReference::Detect(cons
// this loop is to make stuff like flashing keyboard LEDs work
while (ms > (slept += 10))
{
// TODO: improve this to update more than just the default device's output
device->UpdateOutput();
Common::SleepCurrentThread(10);
}
State(0);
device->UpdateOutput();
}
return nullptr;
}
@@ -120,8 +120,7 @@ public:
bool IsInit() const { return m_is_init; }
void UpdateReference(ControlReference* control, const ciface::Core::DeviceQualifier& default_device) const;
bool UpdateInput(const bool force = false);
bool UpdateOutput(const bool force = false);
void UpdateInput();
std::recursive_mutex update_lock;
@@ -149,7 +149,9 @@ Joystick::Joystick( /*const LPCDIDEVICEINSTANCE lpddi, */const LPDIRECTINPUTDEVI
InitForceFeedback(m_device, (int)objects.size());
}
ClearInputState();
ZeroMemory(&m_state_in, sizeof(m_state_in));
// set hats to center
memset(m_state_in.rgdwPOV, 0xFF, sizeof(m_state_in.rgdwPOV));
}
Joystick::~Joystick()
@@ -158,13 +160,6 @@ Joystick::~Joystick()
m_device->Release();
}
void Joystick::ClearInputState()
{
ZeroMemory(&m_state_in, sizeof(m_state_in));
// set hats to center
memset(m_state_in.rgdwPOV, 0xFF, sizeof(m_state_in.rgdwPOV));
}
std::string Joystick::GetName() const
{
return GetDeviceName(m_device);
@@ -182,7 +177,7 @@ std::string Joystick::GetSource() const
// update IO
bool Joystick::UpdateInput()
void Joystick::UpdateInput()
{
HRESULT hr = 0;
@@ -220,9 +215,7 @@ bool Joystick::UpdateInput()
// try reacquire if input lost
if (DIERR_INPUTLOST == hr || DIERR_NOTACQUIRED == hr)
hr = m_device->Acquire();
return SUCCEEDED(hr);
m_device->Acquire();
}
// get name
@@ -52,9 +52,7 @@ private:
};
public:
bool UpdateInput();
void ClearInputState();
void UpdateInput() override;
Joystick(const LPDIRECTINPUTDEVICE8 device, const unsigned int index);
~Joystick();
@@ -30,17 +30,6 @@ static const struct
#include "InputCommon/ControllerInterface/DInput/NamedKeys.h" // NOLINT
};
static const struct
{
const BYTE code;
const char* const name;
} named_lights[] =
{
{ VK_NUMLOCK, "NUM LOCK" },
{ VK_CAPITAL, "CAPS LOCK" },
{ VK_SCROLL, "SCROLL LOCK" }
};
// lil silly
static HWND hwnd;
@@ -102,16 +91,11 @@ KeyboardMouse::KeyboardMouse(const LPDIRECTINPUTDEVICE8 kb_device, const LPDIREC
m_last_update = GetTickCount();
ZeroMemory(&m_state_in, sizeof(m_state_in));
ZeroMemory(m_state_out, sizeof(m_state_out));
ZeroMemory(&m_current_state_out, sizeof(m_current_state_out));
// KEYBOARD
// add keys
for (u8 i = 0; i < sizeof(named_keys)/sizeof(*named_keys); ++i)
AddInput(new Key(i, m_state_in.keyboard[named_keys[i].code]));
// add lights
for (u8 i = 0; i < sizeof(named_lights)/sizeof(*named_lights); ++i)
AddOutput(new Light(i));
// MOUSE
// get caps
@@ -155,7 +139,7 @@ void GetMousePos(ControlState* const x, ControlState* const y)
*y = (ControlState)point.y / (ControlState)win_height * 2 - 1;
}
bool KeyboardMouse::UpdateInput()
void KeyboardMouse::UpdateInput()
{
DIMOUSESTATE2 tmp_mouse;
@@ -191,50 +175,7 @@ bool KeyboardMouse::UpdateInput()
// update mouse cursor
GetMousePos(&m_state_in.cursor.x, &m_state_in.cursor.y);
return true;
}
return false;
}
bool KeyboardMouse::UpdateOutput()
{
class KInput : public INPUT
{
public:
KInput( const unsigned char key, const bool up = false )
{
memset( this, 0, sizeof(*this) );
type = INPUT_KEYBOARD;
ki.wVk = key;
if (up)
ki.dwFlags = KEYEVENTF_KEYUP;
}
};
std::vector< KInput > kbinputs;
for (unsigned int i = 0; i < sizeof(m_state_out)/sizeof(*m_state_out); ++i)
{
bool want_on = false;
if (m_state_out[i])
want_on = m_state_out[i] > GetTickCount() % 255 ; // light should flash when output is 0.5
// lights are set to their original state when output is zero
if (want_on ^ m_current_state_out[i])
{
kbinputs.push_back(KInput(named_lights[i].code)); // press
kbinputs.push_back(KInput(named_lights[i].code, true)); // release
m_current_state_out[i] ^= 1;
}
}
if (kbinputs.size())
return ( kbinputs.size() == SendInput( (UINT)kbinputs.size(), &kbinputs[0], sizeof( kbinputs[0] ) ) );
else
return true;
}
std::string KeyboardMouse::GetName() const
@@ -280,11 +221,6 @@ std::string KeyboardMouse::Cursor::GetName() const
return tmpstr;
}
std::string KeyboardMouse::Light::GetName() const
{
return named_lights[m_index].name;
}
// get/set state
ControlState KeyboardMouse::Key::GetState() const
{
@@ -306,10 +242,5 @@ ControlState KeyboardMouse::Cursor::GetState() const
return std::max(0.0, ControlState(m_axis) / (m_positive ? 1.0 : -1.0));
}
void KeyboardMouse::Light::SetState(const ControlState state)
{
//state_out[m_index] = (unsigned char)(state * 255);
}
}
}
@@ -76,19 +76,8 @@ private:
const bool m_positive;
};
class Light : public Output
{
public:
std::string GetName() const;
Light(u8 index) : m_index(index) {}
void SetState(ControlState state);
private:
const u8 m_index;
};
public:
bool UpdateInput();
bool UpdateOutput();
void UpdateInput() override;
KeyboardMouse(const LPDIRECTINPUTDEVICE8 kb_device, const LPDIRECTINPUTDEVICE8 mo_device);
~KeyboardMouse();
@@ -103,8 +92,6 @@ private:
DWORD m_last_update;
State m_state_in;
unsigned char m_state_out[3]; // NUM CAPS SCROLL
bool m_current_state_out[3]; // NUM CAPS SCROLL
};
}

Some files were not shown because too many files have changed in this diff Show More