mirror of
https://github.com/SourMesen/Mesen2.git
synced 2025-04-02 10:21:44 -04:00
GB: MBC7 - Accelerometer and eeprom support
This commit is contained in:
parent
9ca0fe5922
commit
8f94cbe64f
22 changed files with 493 additions and 59 deletions
|
@ -27,10 +27,12 @@
|
|||
<ClInclude Include="Debugger\StepBackManager.h" />
|
||||
<ClInclude Include="Gameboy\APU\GbChannelDac.h" />
|
||||
<ClInclude Include="Gameboy\APU\GbEnvelope.h" />
|
||||
<ClInclude Include="Gameboy\Carts\Eeprom93Lc56.h" />
|
||||
<ClInclude Include="Gameboy\Carts\GbHuc1.h" />
|
||||
<ClInclude Include="Gameboy\Carts\GbMbc3Rtc.h" />
|
||||
<ClInclude Include="Gameboy\Carts\GbMbc6.h" />
|
||||
<ClInclude Include="Gameboy\Carts\GbMbc7.h" />
|
||||
<ClInclude Include="Gameboy\Carts\GbMbc7Accelerometer.h" />
|
||||
<ClInclude Include="Gameboy\Carts\GbWisdomTree.h" />
|
||||
<ClInclude Include="Gameboy\GbxFooter.h" />
|
||||
<ClInclude Include="GBA\APU\GbaApu.h" />
|
||||
|
|
|
@ -2817,6 +2817,12 @@
|
|||
<ClInclude Include="Gameboy\Carts\GbWisdomTree.h">
|
||||
<Filter>Gameboy\Carts</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Gameboy\Carts\Eeprom93Lc56.h">
|
||||
<Filter>Gameboy\Carts</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Gameboy\Carts\GbMbc7Accelerometer.h">
|
||||
<Filter>Gameboy\Carts</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="Shared\Video\RotateFilter.cpp">
|
||||
|
|
181
Core/Gameboy/Carts/Eeprom93Lc56.h
Normal file
181
Core/Gameboy/Carts/Eeprom93Lc56.h
Normal file
|
@ -0,0 +1,181 @@
|
|||
#pragma once
|
||||
#include "pch.h"
|
||||
#include "Utilities/ISerializable.h"
|
||||
#include "Utilities/Serializer.h"
|
||||
|
||||
class Eeprom93Lc56 final : public ISerializable
|
||||
{
|
||||
private:
|
||||
enum class Mode
|
||||
{
|
||||
Idle,
|
||||
Command,
|
||||
ReadCommand,
|
||||
WriteCommand,
|
||||
WriteAllCommand
|
||||
};
|
||||
|
||||
uint8_t* _saveRam = nullptr;
|
||||
|
||||
Mode _mode = Mode::Idle;
|
||||
|
||||
bool _chipSelect = false;
|
||||
bool _clk = false;
|
||||
uint8_t _dataIn = 0;
|
||||
bool _writeEnabled = false;
|
||||
|
||||
uint16_t _commandId = 0;
|
||||
uint8_t _bitCount = 0;
|
||||
|
||||
uint8_t _readAddress = 0;
|
||||
int8_t _readCounter = -1;
|
||||
|
||||
uint16_t _writeData = 0;
|
||||
uint8_t _writeCounter = 0;
|
||||
|
||||
public:
|
||||
void SetRam(uint8_t* saveRam)
|
||||
{
|
||||
_saveRam = saveRam;
|
||||
}
|
||||
|
||||
uint8_t Read()
|
||||
{
|
||||
uint8_t result = (
|
||||
(_chipSelect ? 0x80 : 0) |
|
||||
(_clk ? 0x40 : 0) |
|
||||
(_dataIn ? 0x02 : 0)
|
||||
);
|
||||
|
||||
if(_mode == Mode::ReadCommand) {
|
||||
if(_readCounter < 0) {
|
||||
return result | 0x01;
|
||||
}
|
||||
return result | ((_saveRam[(_readAddress << 1) + (_readCounter >= 8 ? 0 : 1)] >> (7 - (_readCounter & 0x07))) & 0x01);
|
||||
} else {
|
||||
return result | (_mode == Mode::Idle ? 1 : 0);
|
||||
}
|
||||
}
|
||||
|
||||
void Write(uint8_t value)
|
||||
{
|
||||
uint8_t prevClk = _clk;
|
||||
bool clk = (value & 0x40);
|
||||
_dataIn = (value & 0x02) >> 1;
|
||||
_chipSelect = value & 0x80;
|
||||
_clk = clk;
|
||||
|
||||
if(!_chipSelect) {
|
||||
//Chip select is disabled, force idle
|
||||
_mode = Mode::Idle;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if(!clk || prevClk) {
|
||||
//Not a rising clock
|
||||
return;
|
||||
}
|
||||
|
||||
switch(_mode) {
|
||||
case Mode::Idle:
|
||||
if(_dataIn) {
|
||||
_mode = Mode::Command;
|
||||
_commandId = 0;
|
||||
_bitCount = 0;
|
||||
_writeCounter = 0;
|
||||
_writeData = 0;
|
||||
_readCounter = -1;
|
||||
_readAddress = 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case Mode::Command:
|
||||
_commandId <<= 1;
|
||||
_commandId |= _dataIn;
|
||||
_bitCount++;
|
||||
|
||||
if(_bitCount >= 10) {
|
||||
uint8_t id = _commandId >> 6;
|
||||
if((id & 0b1100) == 0b1000) {
|
||||
_mode = Mode::ReadCommand;
|
||||
_readAddress = _commandId & 0x7F;
|
||||
} else if((id & 0b1100) == 0b0100) {
|
||||
_mode = Mode::WriteCommand;
|
||||
} else if((id & 0b1100) == 0b1100) {
|
||||
if(_writeEnabled) {
|
||||
uint8_t addr = _commandId & 0x7F;
|
||||
_saveRam[addr << 1] = 0xFF;
|
||||
_saveRam[(addr << 1) + 1] = 0xFF;
|
||||
}
|
||||
_mode = Mode::Idle;
|
||||
} else if((id & 0b1111) == 0b0000) {
|
||||
//Disable writes (EWDS)
|
||||
_writeEnabled = false;
|
||||
_mode = Mode::Idle;
|
||||
} else if((id & 0b1111) == 0b0011) {
|
||||
//Enable writes (EWEN)
|
||||
_writeEnabled = true;
|
||||
_mode = Mode::Idle;
|
||||
} else if((id & 0b1111) == 0b0010) {
|
||||
//Erase all (ERAL)
|
||||
if(_writeEnabled) {
|
||||
memset(_saveRam, 0xFF, 256);
|
||||
}
|
||||
_mode = Mode::Idle;
|
||||
} else if((id & 0b1111) == 0b0001) {
|
||||
//Write all (WRAL)
|
||||
_mode = Mode::WriteAllCommand;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case Mode::ReadCommand:
|
||||
_readCounter++;
|
||||
if(_readCounter == 16) {
|
||||
_readAddress = (_readAddress + 1) & 0x7F;
|
||||
_readCounter = 0;
|
||||
_mode = Mode::Idle;
|
||||
}
|
||||
break;
|
||||
|
||||
case Mode::WriteAllCommand:
|
||||
case Mode::WriteCommand: {
|
||||
_writeData <<= 1;
|
||||
_writeData |= _dataIn;
|
||||
_writeCounter++;
|
||||
if(_writeCounter >= 16) {
|
||||
if(_writeEnabled) {
|
||||
if(_mode == Mode::WriteAllCommand) {
|
||||
for(int i = 0; i < 0x80; i++) {
|
||||
_saveRam[i << 1] = _writeData;
|
||||
_saveRam[(i << 1) + 1] = _writeData >> 8;
|
||||
}
|
||||
} else {
|
||||
uint8_t addr = _commandId & 0x7F;
|
||||
_saveRam[addr << 1] = _writeData;
|
||||
_saveRam[(addr << 1) + 1] = _writeData >> 8;
|
||||
}
|
||||
}
|
||||
_mode = Mode::Idle;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Serialize(Serializer& s)
|
||||
{
|
||||
SV(_mode);
|
||||
SV(_chipSelect);
|
||||
SV(_clk);
|
||||
SV(_dataIn);
|
||||
SV(_writeEnabled);
|
||||
SV(_commandId);
|
||||
SV(_bitCount);
|
||||
SV(_readAddress);
|
||||
SV(_readCounter);
|
||||
SV(_writeData);
|
||||
SV(_writeCounter);
|
||||
}
|
||||
};
|
|
@ -1,23 +1,27 @@
|
|||
#pragma once
|
||||
#include "pch.h"
|
||||
#include "Gameboy/Carts/GbCart.h"
|
||||
#include "Gameboy/Carts/Eeprom93Lc56.h"
|
||||
#include "Gameboy/Carts/GbMbc7Accelerometer.h"
|
||||
#include "Gameboy/GbMemoryManager.h"
|
||||
#include "Utilities/Serializer.h"
|
||||
|
||||
class GbMbc7 : public GbCart
|
||||
{
|
||||
private:
|
||||
shared_ptr<GbMbc7Accelerometer> _accelerometer;
|
||||
Eeprom93Lc56 _eeprom;
|
||||
bool _ramEnabled = false;
|
||||
bool _ramEnabled2 = false;
|
||||
uint16_t _prgBank = 1;
|
||||
|
||||
uint16_t _xAccel = 0x8000;
|
||||
uint16_t _yAccel = 0x8000;
|
||||
bool _latched = false;
|
||||
|
||||
public:
|
||||
void InitCart() override
|
||||
{
|
||||
_accelerometer.reset(new GbMbc7Accelerometer(_gameboy->GetEmulator()));
|
||||
_gameboy->GetControlManager()->AddSystemControlDevice(_accelerometer);
|
||||
|
||||
_eeprom.SetRam(_cartRam);
|
||||
_memoryManager->MapRegisters(0x0000, 0x5FFF, RegisterAccess::Write);
|
||||
}
|
||||
|
||||
|
@ -36,20 +40,19 @@ public:
|
|||
}
|
||||
|
||||
switch(addr & 0xF0) {
|
||||
case 0x20: return _xAccel & 0xFF;
|
||||
case 0x30: return (_xAccel >> 8) & 0xFF;
|
||||
case 0x40: return _yAccel & 0xFF;
|
||||
case 0x50: return (_yAccel >> 8) & 0xFF;
|
||||
case 0x20:
|
||||
case 0x30:
|
||||
case 0x40:
|
||||
case 0x50:
|
||||
return _accelerometer->Read(addr);
|
||||
|
||||
//Always 0
|
||||
case 0x60: return 0;
|
||||
|
||||
//TODO EEPROM
|
||||
case 0x80: return 0x01;
|
||||
case 0x80: return _eeprom.Read();
|
||||
|
||||
default: return 0xFF;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void WriteRegister(uint16_t addr, uint8_t value) override
|
||||
|
@ -63,27 +66,13 @@ public:
|
|||
RefreshMappings();
|
||||
} else {
|
||||
switch(addr & 0xF0) {
|
||||
//Reset accelerometer latch
|
||||
case 0x00:
|
||||
if(value == 0x55) {
|
||||
_xAccel = 0x8000;
|
||||
_yAccel = 0x8000;
|
||||
_latched = false;
|
||||
}
|
||||
break;
|
||||
|
||||
//Latch accelerometer value
|
||||
case 0x10:
|
||||
if(!_latched && value == 0xAA) {
|
||||
//TODO accelerometer
|
||||
_xAccel = 0x81D0;
|
||||
_yAccel = 0x81D0;
|
||||
_latched = true;
|
||||
}
|
||||
_accelerometer->Write(addr, value);
|
||||
break;
|
||||
|
||||
case 0x80:
|
||||
//TODO EEPROM
|
||||
_eeprom.Write(value);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -94,8 +83,7 @@ public:
|
|||
SV(_ramEnabled);
|
||||
SV(_ramEnabled2);
|
||||
SV(_prgBank);
|
||||
SV(_xAccel);
|
||||
SV(_yAccel);
|
||||
SV(_latched);
|
||||
SV(_eeprom);
|
||||
SV(_accelerometer);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
|
108
Core/Gameboy/Carts/GbMbc7Accelerometer.h
Normal file
108
Core/Gameboy/Carts/GbMbc7Accelerometer.h
Normal file
|
@ -0,0 +1,108 @@
|
|||
#pragma once
|
||||
#include "pch.h"
|
||||
#include "Utilities/Serializer.h"
|
||||
#include "Shared/KeyManager.h"
|
||||
#include "Shared/BaseControlDevice.h"
|
||||
|
||||
class GbMbc7Accelerometer : public BaseControlDevice
|
||||
{
|
||||
private:
|
||||
vector<uint16_t> _xAxisCodes;
|
||||
vector<uint16_t> _yAxisCodes;
|
||||
|
||||
uint16_t _xAccel = 0x8000;
|
||||
uint16_t _yAccel = 0x8000;
|
||||
bool _latched = false;
|
||||
|
||||
protected:
|
||||
bool HasCoordinates() override { return true; }
|
||||
|
||||
void InternalSetStateFromInput() override
|
||||
{
|
||||
MouseMovement mov = {};
|
||||
|
||||
for(uint16_t code : _xAxisCodes) {
|
||||
if(code != 0) {
|
||||
optional<int16_t> xAxis = KeyManager::GetAxisPosition(code);
|
||||
if(xAxis.has_value()) {
|
||||
mov.dx = xAxis.value();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for(uint16_t code : _yAxisCodes) {
|
||||
if(code != 0) {
|
||||
optional<int16_t> yAxis = KeyManager::GetAxisPosition(code);
|
||||
if(yAxis.has_value()) {
|
||||
mov.dy = yAxis.value();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SetMovement(mov);
|
||||
}
|
||||
|
||||
void Serialize(Serializer& s) override
|
||||
{
|
||||
BaseControlDevice::Serialize(s);
|
||||
SV(_xAccel);
|
||||
SV(_yAccel);
|
||||
SV(_latched);
|
||||
}
|
||||
|
||||
public:
|
||||
GbMbc7Accelerometer(Emulator* emu) : BaseControlDevice(emu, ControllerType::GameboyAccelerometer, BaseControlDevice::MapperInputPort)
|
||||
{
|
||||
//TODO add configuration in UI
|
||||
_xAxisCodes = {
|
||||
KeyManager::GetKeyCode("Pad1 LT X"),
|
||||
KeyManager::GetKeyCode("Joy1 X"),
|
||||
KeyManager::GetKeyCode("Pad1 X"),
|
||||
};
|
||||
|
||||
_yAxisCodes = {
|
||||
KeyManager::GetKeyCode("Pad1 LT Y"),
|
||||
KeyManager::GetKeyCode("Joy1 Y"),
|
||||
KeyManager::GetKeyCode("Pad1 Y"),
|
||||
};
|
||||
}
|
||||
|
||||
uint8_t ReadRam(uint16_t addr) override { return 0; }
|
||||
void WriteRam(uint16_t addr, uint8_t value) override {}
|
||||
|
||||
uint8_t Read(uint16_t addr)
|
||||
{
|
||||
switch(addr & 0xF0) {
|
||||
case 0x20: return _xAccel & 0xFF;
|
||||
case 0x30: return (_xAccel >> 8) & 0xFF;
|
||||
case 0x40: return _yAccel & 0xFF;
|
||||
case 0x50: return (_yAccel >> 8) & 0xFF;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Write(uint16_t addr, uint8_t value)
|
||||
{
|
||||
switch(addr & 0xF0) {
|
||||
case 0x00:
|
||||
if(value == 0x55) {
|
||||
//Reset accelerometer latch
|
||||
_xAccel = 0x8000;
|
||||
_yAccel = 0x8000;
|
||||
_latched = false;
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x10:
|
||||
if(!_latched && value == 0xAA) {
|
||||
//Latch accelerometer value
|
||||
MouseMovement mov = GetMovement();
|
||||
_xAccel = -(mov.dx / 500) + 0x81D0;
|
||||
_yAccel = mov.dy / 500 + 0x81D0;
|
||||
_latched = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
|
@ -32,6 +32,11 @@ struct GameboyHeader
|
|||
return 0x200;
|
||||
}
|
||||
|
||||
if(CartType == 0x22) {
|
||||
//MBC7 has a 256-byte eeprom
|
||||
return 0x100;
|
||||
}
|
||||
|
||||
switch(CartRamSize) {
|
||||
case 0: return 0;
|
||||
case 1: return 0x800;
|
||||
|
|
|
@ -36,6 +36,7 @@ public:
|
|||
virtual void UpdateDevices() = 0;
|
||||
virtual bool IsMouseButtonPressed(MouseButton button) = 0;
|
||||
virtual bool IsKeyPressed(uint16_t keyCode) = 0;
|
||||
virtual optional<int16_t> GetAxisPosition(uint16_t keyCode) { return std::nullopt; }
|
||||
virtual vector<uint16_t> GetPressedKeys() = 0;
|
||||
virtual string GetKeyName(uint16_t keyCode) = 0;
|
||||
virtual uint16_t GetKeyCode(string keyName) = 0;
|
||||
|
|
|
@ -40,6 +40,14 @@ bool KeyManager::IsKeyPressed(uint16_t keyCode)
|
|||
return false;
|
||||
}
|
||||
|
||||
optional<int16_t> KeyManager::GetAxisPosition(uint16_t keyCode)
|
||||
{
|
||||
if(_keyManager != nullptr && _settings->IsInputEnabled()) {
|
||||
return _keyManager->GetAxisPosition(keyCode);
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
bool KeyManager::IsMouseButtonPressed(MouseButton button)
|
||||
{
|
||||
if(_keyManager != nullptr) {
|
||||
|
|
|
@ -22,6 +22,7 @@ public:
|
|||
|
||||
static void RefreshKeyState();
|
||||
static bool IsKeyPressed(uint16_t keyCode);
|
||||
static optional<int16_t> GetAxisPosition(uint16_t keyCode);
|
||||
static bool IsMouseButtonPressed(MouseButton button);
|
||||
static vector<uint16_t> GetPressedKeys();
|
||||
static string GetKeyName(uint16_t keyCode);
|
||||
|
|
|
@ -219,6 +219,7 @@ enum class ControllerType
|
|||
|
||||
//Game Boy
|
||||
GameboyController,
|
||||
GameboyAccelerometer,
|
||||
|
||||
//PC Engine
|
||||
PceController,
|
||||
|
|
|
@ -200,6 +200,34 @@ bool LinuxGameController::IsButtonPressed(int buttonNumber)
|
|||
return false;
|
||||
}
|
||||
|
||||
optional<int16_t> LinuxGameController::GetAxisPosition(int axis)
|
||||
{
|
||||
axis -= 55;
|
||||
|
||||
unsigned int code;
|
||||
switch(axis) {
|
||||
default: return std::nullopt;
|
||||
case 0: code = ABS_Y; break;
|
||||
case 1: code = ABS_X; break;
|
||||
case 2: code = ABS_RY; break;
|
||||
case 3: code = ABS_RX; break;
|
||||
case 4: code = ABS_Z; break;
|
||||
case 5: code = ABS_RZ; break;
|
||||
}
|
||||
|
||||
int min = libevdev_get_abs_minimum(_device, code);
|
||||
int max = libevdev_get_abs_maximum(_device, code);
|
||||
|
||||
int value = libevdev_get_event_value(_device, EV_ABS, code);
|
||||
|
||||
int range = max - min;
|
||||
int offset = value - min;
|
||||
double ratio = (double)offset / range;
|
||||
|
||||
int16_t axisValue = (ratio - 0.5) * 2 * INT16_MAX;
|
||||
return axis & 0x01 ? axisValue : -axisValue;
|
||||
}
|
||||
|
||||
bool LinuxGameController::IsDisconnected()
|
||||
{
|
||||
return _disconnected;
|
||||
|
|
|
@ -29,4 +29,5 @@ public:
|
|||
bool IsDisconnected();
|
||||
int GetDeviceID();
|
||||
bool IsButtonPressed(int buttonNumber);
|
||||
optional<int16_t> GetAxisPosition(int axis);
|
||||
};
|
|
@ -23,7 +23,8 @@ LinuxKeyManager::LinuxKeyManager(Emulator* emu)
|
|||
"Right 4", "Left 4", "Down 4", "Up 4",
|
||||
"Trigger", "Thumb", "Thumb2", "Top", "Top2",
|
||||
"Pinkie", "Base", "Base2", "Base3", "Base4",
|
||||
"Base5", "Base6", "Dead"
|
||||
"Base5", "Base6", "Dead",
|
||||
"Y", "X", "Y2", "X2", "Z", "Z2"
|
||||
};
|
||||
|
||||
for(int i = 0; i < 20; i++) {
|
||||
|
@ -75,6 +76,16 @@ bool LinuxKeyManager::IsKeyPressed(uint16_t key)
|
|||
return false;
|
||||
}
|
||||
|
||||
optional<int16_t> LinuxKeyManager::GetAxisPosition(uint16_t key)
|
||||
{
|
||||
if(key >= LinuxKeyManager::BaseGamepadIndex) {
|
||||
uint8_t port = (key - LinuxKeyManager::BaseGamepadIndex) / 0x100;
|
||||
uint8_t button = (key - LinuxKeyManager::BaseGamepadIndex) % 0x100;
|
||||
return _controllers[port]->GetAxisPosition(button);
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
bool LinuxKeyManager::IsMouseButtonPressed(MouseButton button)
|
||||
{
|
||||
return _keyState[LinuxKeyManager::BaseMouseButtonIndex + (int)button];
|
||||
|
|
|
@ -32,16 +32,17 @@ public:
|
|||
LinuxKeyManager(Emulator* emu);
|
||||
virtual ~LinuxKeyManager();
|
||||
|
||||
void RefreshState();
|
||||
bool IsKeyPressed(uint16_t key);
|
||||
bool IsMouseButtonPressed(MouseButton button);
|
||||
std::vector<uint16_t> GetPressedKeys();
|
||||
string GetKeyName(uint16_t key);
|
||||
uint16_t GetKeyCode(string keyName);
|
||||
void RefreshState() override;
|
||||
bool IsKeyPressed(uint16_t key) override;
|
||||
optional<int16_t> GetAxisPosition(uint16_t key) override;
|
||||
bool IsMouseButtonPressed(MouseButton button) override;
|
||||
std::vector<uint16_t> GetPressedKeys() override;
|
||||
string GetKeyName(uint16_t key) override;
|
||||
uint16_t GetKeyCode(string keyName) override;
|
||||
|
||||
void UpdateDevices();
|
||||
bool SetKeyState(uint16_t scanCode, bool state);
|
||||
void ResetKeyState();
|
||||
void UpdateDevices() override;
|
||||
bool SetKeyState(uint16_t scanCode, bool state) override;
|
||||
void ResetKeyState() override;
|
||||
|
||||
void SetDisabled(bool disabled);
|
||||
void SetDisabled(bool disabled) override;
|
||||
};
|
||||
|
|
|
@ -329,6 +329,7 @@ namespace Mesen.Config
|
|||
|
||||
//Game Boy
|
||||
GameboyController,
|
||||
GameboyAccelerometer,
|
||||
|
||||
//PC Engine
|
||||
PceController,
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
#include <stdio.h>
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <vector>
|
||||
#include <atomic>
|
||||
#include <cstring>
|
||||
|
@ -25,6 +26,7 @@ using std::atomic;
|
|||
using std::atomic_flag;
|
||||
using std::unordered_map;
|
||||
using std::unordered_set;
|
||||
using std::optional;
|
||||
|
||||
#ifndef _MSC_VER
|
||||
// Some headers have functions marked as `__forceinline` but don't provide the bodies;
|
||||
|
|
|
@ -286,8 +286,8 @@ int DirectInputManager::EnumObjectsCallback(const DIDEVICEOBJECTINSTANCE* pdidoi
|
|||
diprg.diph.dwHeaderSize = sizeof(DIPROPHEADER);
|
||||
diprg.diph.dwHow = DIPH_BYID;
|
||||
diprg.diph.dwObj = pdidoi->dwType; // Specify the enumerated axis
|
||||
diprg.lMin = -1000;
|
||||
diprg.lMax = +1000;
|
||||
diprg.lMin = INT16_MIN;
|
||||
diprg.lMax = INT16_MAX;
|
||||
|
||||
// Set the range for the axis
|
||||
if(FAILED(joystick->SetProperty(DIPROP_RANGE, &diprg.diph))) {
|
||||
|
@ -354,7 +354,7 @@ bool DirectInputManager::IsPressed(int port, int button)
|
|||
|
||||
DIJOYSTATE2& state = _joysticks[port].state;
|
||||
DIJOYSTATE2& defaultState = _joysticks[port].defaultState;
|
||||
int deadRange = (int)(500 * _emu->GetSettings()->GetControllerDeadzoneRatio());
|
||||
int deadRange = (int)(INT16_MAX / 2 * _emu->GetSettings()->GetControllerDeadzoneRatio());
|
||||
|
||||
int povDirection = state.rgdwPOV[0] / 4500;
|
||||
bool povCentered = (LOWORD(state.rgdwPOV[0]) == 0xFFFF) || povDirection >= 8;
|
||||
|
@ -376,12 +376,34 @@ bool DirectInputManager::IsPressed(int port, int button)
|
|||
case 0x0D: return !povCentered && (povDirection >= 3 && povDirection <= 5);
|
||||
case 0x0E: return !povCentered && (povDirection >= 1 && povDirection <= 3);
|
||||
case 0x0F: return !povCentered && (povDirection >= 5 && povDirection <= 7);
|
||||
default: return state.rgbButtons[button - 0x10] != 0;
|
||||
default:
|
||||
if(button < 128 + 16) {
|
||||
return state.rgbButtons[button - 0x10] != 0;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
optional<int16_t> DirectInputManager::GetAxisPosition(int port, int axis)
|
||||
{
|
||||
if(port >= (int)_joysticks.size() || !_joysticks[port].stateValid) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
DIJOYSTATE2& state = _joysticks[port].state;
|
||||
|
||||
switch(axis - 128 - 16) {
|
||||
case 0x00: return state.lX;
|
||||
case 0x01: return state.lY;
|
||||
case 0x02: return state.lRx;
|
||||
case 0x03: return state.lRy;
|
||||
case 0x04: return state.lZ;
|
||||
case 0x05: return state.lRz;
|
||||
default: return std::nullopt;
|
||||
}
|
||||
}
|
||||
|
||||
void DirectInputManager::UpdateInputState(DirectInputData &data)
|
||||
{
|
||||
DIJOYSTATE2 newState;
|
||||
|
|
|
@ -44,4 +44,5 @@ public:
|
|||
void UpdateDeviceList();
|
||||
int GetJoystickCount();
|
||||
bool IsPressed(int port, int button);
|
||||
optional<int16_t> GetAxisPosition(int port, int axis);
|
||||
};
|
||||
|
|
|
@ -12,7 +12,18 @@ WindowsKeyManager::WindowsKeyManager(Emulator* emu, HWND hWnd)
|
|||
_keyDefinitions = KeyDefinition::GetSharedKeyDefinitions();
|
||||
|
||||
//Init XInput buttons
|
||||
vector<string> buttonNames = { "Up", "Down", "Left", "Right", "Start", "Back", "L3", "R3", "L1", "R1", "?", "?", "A", "B", "X", "Y", "L2", "R2", "RT Up", "RT Down", "RT Left", "RT Right", "LT Up", "LT Down", "LT Left", "LT Right" };
|
||||
vector<string> buttonNames = {
|
||||
"Up", "Down", "Left", "Right",
|
||||
"Start", "Back",
|
||||
"L3", "R3", "L1", "R1",
|
||||
"?", "?",
|
||||
"A", "B", "X", "Y",
|
||||
"L2", "R2",
|
||||
"RT Up", "RT Down", "RT Left", "RT Right",
|
||||
"LT Up", "LT Down", "LT Left", "LT Right",
|
||||
"LT Y", "LT X", "RT Y", "RT X"
|
||||
};
|
||||
|
||||
for(int i = 0; i < 4; i++) {
|
||||
for(int j = 0; j < (int)buttonNames.size(); j++) {
|
||||
_keyDefinitions.push_back({ "Pad" + std::to_string(i + 1) + " " + buttonNames[j], (uint32_t)(WindowsKeyManager::BaseGamepadIndex + i * 0x100 + j + 1) });
|
||||
|
@ -20,14 +31,29 @@ WindowsKeyManager::WindowsKeyManager(Emulator* emu, HWND hWnd)
|
|||
}
|
||||
|
||||
//Init DirectInput buttons
|
||||
vector<string> diButtonNames = { "Y+", "Y-", "X-", "X+", "Y2+", "Y2-", "X2-", "X2+", "Z+", "Z-", "Z2+", "Z2-", "DPad Up", "DPad Down", "DPad Right", "DPad Left" };
|
||||
vector<string> diButtonNames = {
|
||||
"Y+", "Y-",
|
||||
"X-", "X+",
|
||||
"Y2+", "Y2-",
|
||||
"X2-", "X2+",
|
||||
"Z+", "Z-",
|
||||
"Z2+", "Z2-",
|
||||
"DPad Up", "DPad Down", "DPad Right", "DPad Left"
|
||||
};
|
||||
vector<string> axisNames = {
|
||||
"Y", "X", "Y2", "X2", "Z", "Z2"
|
||||
};
|
||||
for(int i = 0; i < 16; i++) {
|
||||
for(int j = 0; j < (int)diButtonNames.size(); j++) {
|
||||
_keyDefinitions.push_back({ "Joy" + std::to_string(i + 1) + " " + diButtonNames[j], (uint32_t)(WindowsKeyManager::BaseDirectInputIndex + i * 0x100 + j) });
|
||||
}
|
||||
|
||||
for(int j = 0; j < 128; j++) {
|
||||
_keyDefinitions.push_back({ "Joy" + std::to_string(i + 1) + " But" + std::to_string(j + 1), (uint32_t)(WindowsKeyManager::BaseDirectInputIndex + i * 0x100 + j + diButtonNames.size())});
|
||||
_keyDefinitions.push_back({ "Joy" + std::to_string(i + 1) + " But" + std::to_string(j + 1), (uint32_t)(WindowsKeyManager::BaseDirectInputIndex + i * 0x100 + j + diButtonNames.size()) });
|
||||
}
|
||||
|
||||
for(int j = 0; j < (int)axisNames.size(); j++) {
|
||||
_keyDefinitions.push_back({ "Joy" + std::to_string(i + 1) + " " + axisNames[j], (uint32_t)(WindowsKeyManager::BaseDirectInputIndex + i * 0x100 + j + diButtonNames.size() + 0x100) });
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -101,6 +127,28 @@ bool WindowsKeyManager::IsKeyPressed(uint16_t key)
|
|||
return false;
|
||||
}
|
||||
|
||||
optional<int16_t> WindowsKeyManager::GetAxisPosition(uint16_t key)
|
||||
{
|
||||
if(key >= WindowsKeyManager::BaseGamepadIndex) {
|
||||
if(!_xInput || !_directInput) {
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
if(key >= WindowsKeyManager::BaseDirectInputIndex) {
|
||||
//Directinput key
|
||||
uint8_t port = (key - WindowsKeyManager::BaseDirectInputIndex) / 0x100;
|
||||
uint8_t button = (key - WindowsKeyManager::BaseDirectInputIndex) % 0x100;
|
||||
return _directInput->GetAxisPosition(port, button);
|
||||
} else {
|
||||
//XInput key
|
||||
uint8_t port = (key - WindowsKeyManager::BaseGamepadIndex) / 0x100;
|
||||
uint8_t button = (key - WindowsKeyManager::BaseGamepadIndex) % 0x100;
|
||||
return _xInput->GetAxisPosition(port, button);
|
||||
}
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
bool WindowsKeyManager::IsMouseButtonPressed(MouseButton button)
|
||||
{
|
||||
return _keyState[WindowsKeyManager::BaseMouseButtonIndex + (int)button];
|
||||
|
|
|
@ -38,16 +38,17 @@ public:
|
|||
WindowsKeyManager(Emulator* emu, HWND hWnd);
|
||||
~WindowsKeyManager();
|
||||
|
||||
void RefreshState();
|
||||
bool IsKeyPressed(uint16_t key);
|
||||
bool IsMouseButtonPressed(MouseButton button);
|
||||
vector<uint16_t> GetPressedKeys();
|
||||
string GetKeyName(uint16_t key);
|
||||
uint16_t GetKeyCode(string keyName);
|
||||
void RefreshState() override;
|
||||
bool IsKeyPressed(uint16_t key) override;
|
||||
optional<int16_t> GetAxisPosition(uint16_t key) override;
|
||||
bool IsMouseButtonPressed(MouseButton button) override;
|
||||
vector<uint16_t> GetPressedKeys() override;
|
||||
string GetKeyName(uint16_t key) override;
|
||||
uint16_t GetKeyCode(string keyName) override;
|
||||
|
||||
bool SetKeyState(uint16_t scanCode, bool state);
|
||||
void ResetKeyState();
|
||||
void SetDisabled(bool disabled);
|
||||
bool SetKeyState(uint16_t scanCode, bool state) override;
|
||||
void ResetKeyState() override;
|
||||
void SetDisabled(bool disabled) override;
|
||||
|
||||
void UpdateDevices();
|
||||
void UpdateDevices() override;
|
||||
};
|
|
@ -75,3 +75,18 @@ bool XInputManager::IsPressed(uint8_t gamepadPort, uint8_t button)
|
|||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
optional<int16_t> XInputManager::GetAxisPosition(uint8_t port, int axis)
|
||||
{
|
||||
if(_gamePadConnected[port]) {
|
||||
XINPUT_GAMEPAD& gamepad = _gamePadStates[port]->Gamepad;
|
||||
switch(axis - 27) {
|
||||
case 0: return gamepad.sThumbLY;
|
||||
case 1: return gamepad.sThumbLX;
|
||||
case 2: return gamepad.sThumbRY;
|
||||
case 3: return gamepad.sThumbRX;
|
||||
}
|
||||
}
|
||||
|
||||
return std::nullopt;
|
||||
}
|
|
@ -1,5 +1,6 @@
|
|||
#pragma once
|
||||
|
||||
#include "pch.h"
|
||||
#include "Common.h"
|
||||
#include <Xinput.h>
|
||||
|
||||
|
@ -19,4 +20,5 @@ class XInputManager
|
|||
void UpdateDeviceList();
|
||||
void RefreshState();
|
||||
bool IsPressed(uint8_t gamepadPort, uint8_t button);
|
||||
optional<int16_t> GetAxisPosition(uint8_t gamepadPort, int axis);
|
||||
};
|
||||
|
|
Loading…
Add table
Reference in a new issue