GB: MBC7 - Accelerometer and eeprom support

This commit is contained in:
Sour 2024-07-07 20:36:45 +09:00
parent 9ca0fe5922
commit 8f94cbe64f
22 changed files with 493 additions and 59 deletions

View file

@ -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" />

View file

@ -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">

View 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);
}
};

View file

@ -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);
}
};
};

View 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;
}
}
};

View file

@ -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;

View file

@ -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;

View file

@ -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) {

View file

@ -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);

View file

@ -219,6 +219,7 @@ enum class ControllerType
//Game Boy
GameboyController,
GameboyAccelerometer,
//PC Engine
PceController,

View file

@ -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;

View file

@ -29,4 +29,5 @@ public:
bool IsDisconnected();
int GetDeviceID();
bool IsButtonPressed(int buttonNumber);
optional<int16_t> GetAxisPosition(int axis);
};

View file

@ -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];

View file

@ -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;
};

View file

@ -329,6 +329,7 @@ namespace Mesen.Config
//Game Boy
GameboyController,
GameboyAccelerometer,
//PC Engine
PceController,

View file

@ -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;

View file

@ -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;

View file

@ -44,4 +44,5 @@ public:
void UpdateDeviceList();
int GetJoystickCount();
bool IsPressed(int port, int button);
optional<int16_t> GetAxisPosition(int port, int axis);
};

View file

@ -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];

View file

@ -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;
};

View file

@ -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;
}

View file

@ -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);
};