Integrate NES input devices

This commit is contained in:
Sour 2021-04-20 22:51:15 -04:00
parent 8a1ea20e98
commit add120abdb
47 changed files with 2110 additions and 113 deletions

View file

@ -44,6 +44,29 @@
</ItemGroup>
<ItemGroup>
<ClInclude Include="Debugger\stdafx.h" />
<ClInclude Include="NES\Input\ArkanoidController.h" />
<ClInclude Include="NES\Input\AsciiTurboFile.h" />
<ClInclude Include="NES\Input\BandaiHyperShot.h" />
<ClInclude Include="NES\Input\BarcodeBattlerReader.h" />
<ClInclude Include="NES\Input\BattleBox.h" />
<ClInclude Include="NES\Input\ExcitingBoxingController.h" />
<ClInclude Include="NES\Input\FamilyBasicDataRecorder.h" />
<ClInclude Include="NES\Input\FamilyBasicKeyboard.h" />
<ClInclude Include="NES\Input\FamilyMatTrainer.h" />
<ClInclude Include="NES\Input\FourScore.h" />
<ClInclude Include="NES\Input\HoriTrack.h" />
<ClInclude Include="NES\Input\IBarcodeReader.h" />
<ClInclude Include="NES\Input\JissenMahjongController.h" />
<ClInclude Include="NES\Input\KonamiHyperShot.h" />
<ClInclude Include="NES\Input\OekaKidsTablet.h" />
<ClInclude Include="NES\Input\PachinkoController.h" />
<ClInclude Include="NES\Input\PartyTap.h" />
<ClInclude Include="NES\Input\PowerPad.h" />
<ClInclude Include="NES\Input\SuborKeyboard.h" />
<ClInclude Include="NES\Input\SuborMouse.h" />
<ClInclude Include="NES\Input\VirtualBoyController.h" />
<ClInclude Include="NES\Input\VsZapper.h" />
<ClInclude Include="NES\Input\Zapper.h" />
<ClInclude Include="Netplay\stdafx.h" />
<ClInclude Include="Shared\Audio\stdafx.h" />
<ClInclude Include="Shared\BaseControlManager.h" />
@ -51,6 +74,7 @@
<ClInclude Include="Gameboy\GbControlManager.h" />
<ClInclude Include="Gameboy\stdafx.h" />
<ClInclude Include="Shared\Interfaces\IAudioProvider.h" />
<ClInclude Include="Shared\Interfaces\IBattery.h" />
<ClInclude Include="Shared\Interfaces\IControlManager.h" />
<ClInclude Include="MemoryOperationType.h" />
<ClInclude Include="Shared\Interfaces\stdafx.h" />

View file

@ -734,6 +734,30 @@
<ClInclude Include="Netplay\stdafx.h" />
<ClInclude Include="Shared\BaseControlManager.h" />
<ClInclude Include="Shared\RomInfo.h" />
<ClInclude Include="NES\Input\AsciiTurboFile.h" />
<ClInclude Include="NES\Input\BandaiHyperShot.h" />
<ClInclude Include="NES\Input\BarcodeBattlerReader.h" />
<ClInclude Include="NES\Input\BattleBox.h" />
<ClInclude Include="NES\Input\ExcitingBoxingController.h" />
<ClInclude Include="NES\Input\FamilyBasicDataRecorder.h" />
<ClInclude Include="NES\Input\FamilyBasicKeyboard.h" />
<ClInclude Include="NES\Input\FamilyMatTrainer.h" />
<ClInclude Include="NES\Input\FourScore.h" />
<ClInclude Include="NES\Input\HoriTrack.h" />
<ClInclude Include="NES\Input\OekaKidsTablet.h" />
<ClInclude Include="NES\Input\PachinkoController.h" />
<ClInclude Include="NES\Input\PartyTap.h" />
<ClInclude Include="NES\Input\PowerPad.h" />
<ClInclude Include="NES\Input\VirtualBoyController.h" />
<ClInclude Include="NES\Input\VsZapper.h" />
<ClInclude Include="NES\Input\Zapper.h" />
<ClInclude Include="NES\Input\ArkanoidController.h" />
<ClInclude Include="NES\Input\JissenMahjongController.h" />
<ClInclude Include="NES\Input\KonamiHyperShot.h" />
<ClInclude Include="NES\Input\SuborKeyboard.h" />
<ClInclude Include="NES\Input\SuborMouse.h" />
<ClInclude Include="NES\Input\IBarcodeReader.h" />
<ClInclude Include="Shared\Interfaces\IBattery.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="SNES\Cpu.cpp">

View file

@ -463,3 +463,8 @@ uint64_t Gameboy::GetMasterClock()
{
return _memoryManager->GetCycleCount();
}
uint32_t Gameboy::GetMasterClockRate()
{
return 20971520;
}

View file

@ -117,5 +117,6 @@ public:
virtual AddressInfo GetRelativeAddress(AddressInfo absAddress, CpuType cpuType) override;
// Inherited via IConsole
virtual uint64_t GetMasterClock() override;
uint64_t GetMasterClock() override;
uint32_t GetMasterClockRate() override;
};

View file

@ -0,0 +1,90 @@
#pragma once
#include "stdafx.h"
#include "Shared/BaseControlDevice.h"
#include "Shared/KeyManager.h"
#include "Shared/Emulator.h"
#include "Shared/EmuSettings.h"
#include "Utilities/Serializer.h"
class ArkanoidController : public BaseControlDevice
{
private:
uint32_t _currentValue = (0xF4 - 0x54) / 2;
uint32_t _stateBuffer = 0;
enum Buttons { Fire };
protected:
bool HasCoordinates() override { return true; }
string GetKeyNames() override
{
return "F";
}
void InternalSetStateFromInput() override
{
if(_emu->GetSettings()->IsInputEnabled()) {
SetPressedState(Buttons::Fire, KeyManager::IsMouseButtonPressed(MouseButton::LeftButton));
SetMovement(KeyManager::GetMouseMovement(
_emu->GetSettings()->GetVideoConfig().VideoScale,
_emu->GetSettings()->GetInputConfig().MouseSensitivity + 1
));
}
}
void Serialize(Serializer& s) override
{
BaseControlDevice::Serialize(s);
s.Stream(_stateBuffer, _currentValue);
}
void RefreshStateBuffer() override
{
MouseMovement mov = GetMovement();
_currentValue += mov.dx;
if(_currentValue < 0x54) {
_currentValue = 0x54;
} else if(_currentValue > 0xF4) {
_currentValue = 0xF4;
}
_stateBuffer = _currentValue;
}
public:
ArkanoidController(Emulator* emu, ControllerType type, uint8_t port) : BaseControlDevice(emu, type, port)
{
}
uint8_t ReadRam(uint16_t addr) override
{
uint8_t output = 0;
if(IsExpansionDevice()) {
if(addr == 0x4016) {
//Fire button is on port 1
if(IsPressed(ArkanoidController::Buttons::Fire)) {
output |= 0x02;
}
} else if(addr == 0x4017) {
//Serial data is on port 2
output |= ((~_stateBuffer) >> 6) & 0x02;
_stateBuffer <<= 1;
}
} else if(IsCurrentPort(addr)) {
output = ((~_stateBuffer) >> 3) & 0x10;
_stateBuffer <<= 1;
if(IsPressed(ArkanoidController::Buttons::Fire)) {
output |= 0x08;
}
}
return output;
}
void WriteRam(uint16_t addr, uint8_t value) override
{
StrobeProcessWrite(value);
}
};

View file

@ -0,0 +1,66 @@
#pragma once
#include "stdafx.h"
#include "Shared/BaseControlDevice.h"
#include "Shared/Emulator.h"
#include "Shared/EmuSettings.h"
#include "Shared/BatteryManager.h"
#include "Shared/Interfaces/IBattery.h"
#include "Utilities/Serializer.h"
class AsciiTurboFile : public BaseControlDevice, public IBattery
{
private:
static constexpr int FileSize = 0x2000;
static constexpr int BitCount = FileSize * 8;
uint8_t _lastWrite = 0;
uint16_t _position = 0;
uint8_t _data[AsciiTurboFile::FileSize];
protected:
void Serialize(Serializer& s) override
{
BaseControlDevice::Serialize(s);
ArrayInfo<uint8_t> data { _data, AsciiTurboFile::FileSize };
s.Stream(_position, _lastWrite, data);
}
public:
AsciiTurboFile(Emulator* emu) : BaseControlDevice(emu, ControllerType::AsciiTurboFile, BaseControlDevice::ExpDevicePort)
{
_emu->GetBatteryManager()->LoadBattery(".tf", _data, AsciiTurboFile::FileSize);
}
~AsciiTurboFile()
{
SaveBattery();
}
void SaveBattery() override
{
_emu->GetBatteryManager()->SaveBattery(".tf", _data, AsciiTurboFile::FileSize);
}
uint8_t ReadRam(uint16_t addr) override
{
if(addr == 0x4017) {
return ((_data[_position / 8] >> (_position % 8)) & 0x01) << 2;
}
return 0;
}
void WriteRam(uint16_t addr, uint8_t value) override
{
if(!(value & 0x02)) {
_position = 0;
}
if(!(value & 0x04) && (_lastWrite & 0x04)) {
//Clock, perform write, increase position
_data[_position / 8] &= ~(1 << (_position % 8));
_data[_position / 8] |= (value & 0x01) << (_position % 8);
_position = (_position + 1) & (AsciiTurboFile::BitCount - 1);
}
_lastWrite = value;
}
};

View file

@ -0,0 +1,77 @@
#pragma once
#include "stdafx.h"
#include "NES/Input/NesController.h"
#include "NES/Input/Zapper.h"
#include "NES/NesConsole.h"
#include "Shared/KeyManager.h"
class BandaiHyperShot : public NesController
{
private:
NesConsole* _console;
uint32_t _stateBuffer = 0;
protected:
enum ZapperButtons { Fire = 9 };
bool HasCoordinates() override { return true; }
string GetKeyNames() override
{
return NesController::GetKeyNames() + "F";
}
void InternalSetStateFromInput() override
{
NesController::InternalSetStateFromInput();
if(_emu->GetSettings()->IsInputEnabled()) {
SetPressedState(ZapperButtons::Fire, KeyManager::IsMouseButtonPressed(MouseButton::LeftButton));
MousePosition pos = KeyManager::GetMousePosition();
if(KeyManager::IsMouseButtonPressed(MouseButton::RightButton)) {
pos.X = -1;
pos.Y = -1;
}
SetCoordinates(pos);
}
}
bool IsLightFound()
{
return Zapper::StaticIsLightFound(GetCoordinates(), _console);
}
void Serialize(Serializer& s) override
{
BaseControlDevice::Serialize(s);
s.Stream(_stateBuffer);
}
public:
BandaiHyperShot(NesConsole* console, KeyMappingSet keyMappings) : NesController(console->GetEmulator(), ControllerType::BandaiHyperShot, BaseControlDevice::ExpDevicePort, keyMappings)
{
}
void RefreshStateBuffer() override
{
_stateBuffer = (uint32_t)ToByte();
}
uint8_t ReadRam(uint16_t addr) override
{
if(addr == 0x4016) {
StrobeProcessRead();
uint8_t output = (_stateBuffer & 0x01) << 1;
_stateBuffer >>= 1;
return output;
} else {
return (IsLightFound() ? 0 : 0x08) | (IsPressed(ZapperButtons::Fire) ? 0x10 : 0x00);
}
}
void WriteRam(uint16_t addr, uint8_t value) override
{
StrobeProcessWrite(value);
}
};

View file

@ -0,0 +1,106 @@
#pragma once
#include "stdafx.h"
#include "Shared/BaseControlDevice.h"
#include "Shared/Emulator.h"
#include "Utilities/Serializer.h"
#include "NES/Input/IBarcodeReader.h"
class BarcodeBattlerReader : public BaseControlDevice, public IBarcodeReader
{
private:
static constexpr int StreamSize = 200;
uint64_t _newBarcode = 0;
uint32_t _newBarcodeDigitCount = 0;
uint8_t _barcodeStream[BarcodeBattlerReader::StreamSize];
uint64_t _insertCycle = 0;
protected:
void Serialize(Serializer& s) override
{
BaseControlDevice::Serialize(s);
ArrayInfo<uint8_t> bitStream{ _barcodeStream, BarcodeBattlerReader::StreamSize };
s.Stream(_newBarcode, _newBarcodeDigitCount, _insertCycle, bitStream);
}
bool IsRawString() override
{
return true;
}
void InitBarcodeStream()
{
vector<uint8_t> state = GetRawState().State;
string barcodeText(state.begin(), state.end());
//Signature at the end, needed for code to be recognized
barcodeText += "EPOCH\xD\xA";
//Pad to 20 characters with spaces
barcodeText.insert(0, 20 - barcodeText.size(), ' ');
int pos = 0;
vector<uint8_t> bits;
for(int i = 0; i < 20; i++) {
_barcodeStream[pos++] = 1;
for(int j = 0; j < 8; j++) {
_barcodeStream[pos++] = ~((barcodeText[i] >> j) & 0x01);
}
_barcodeStream[pos++] = 0;
}
}
public:
BarcodeBattlerReader(Emulator* emu) : BaseControlDevice(emu, ControllerType::BarcodeBattler, BaseControlDevice::ExpDevicePort)
{
}
void InternalSetStateFromInput() override
{
ClearState();
if(_newBarcodeDigitCount > 0) {
string barcodeText = std::to_string(_newBarcode);
//Pad 8 or 13 character barcode with 0s at start
barcodeText.insert(0, _newBarcodeDigitCount - barcodeText.size(), '0');
SetTextState(barcodeText);
_newBarcode = 0;
_newBarcodeDigitCount = 0;
}
}
void OnAfterSetState() override
{
if(GetRawState().State.size() > 0) {
InitBarcodeStream();
if(_emu) {
_insertCycle = _emu->GetMasterClock();
}
}
}
void InputBarcode(uint64_t barcode, uint32_t digitCount) override
{
_newBarcode = barcode;
_newBarcodeDigitCount = digitCount;
}
uint8_t ReadRam(uint16_t addr) override
{
if(addr == 0x4017) {
uint64_t elapsedCycles = _emu->GetMasterClock() - _insertCycle;
uint32_t cyclesPerBit = _emu->GetMasterClockRate() / 1200;
uint32_t streamPosition = (uint32_t)(elapsedCycles / cyclesPerBit);
if(streamPosition < BarcodeBattlerReader::StreamSize) {
return _barcodeStream[streamPosition] << 2;
}
}
return 0;
}
void WriteRam(uint16_t addr, uint8_t value) override
{
}
};

118
Core/NES/Input/BattleBox.h Normal file
View file

@ -0,0 +1,118 @@
#pragma once
#include "stdafx.h"
#include "Shared/Emulator.h"
#include "Shared/BaseControlDevice.h"
#include "Shared/BatteryManager.h"
#include "Shared/Interfaces/IBattery.h"
#include "Utilities/Serializer.h"
class BattleBox : public BaseControlDevice, public IBattery
{
private:
static constexpr int FileSize = 0x200;
uint8_t _lastWrite = 0;
uint8_t _address = 0;
uint8_t _chipSelect = 0;
uint16_t _data[BattleBox::FileSize/2];
uint8_t _output = 0;
bool _writeEnabled = false;
uint8_t _inputBitPosition = 0;
uint16_t _inputData = 0;
bool _isWrite = false;
bool _isRead = false;
protected:
void Serialize(Serializer& s) override
{
BaseControlDevice::Serialize(s);
ArrayInfo<uint8_t> data{ (uint8_t*)_data, BattleBox::FileSize };
s.Stream(_lastWrite, _address, _chipSelect, _output, _writeEnabled, _inputBitPosition, _isWrite, _isRead, _inputData, data);
}
public:
BattleBox(Emulator* emu) : BaseControlDevice(emu, ControllerType::BattleBox, BaseControlDevice::ExpDevicePort)
{
_emu->GetBatteryManager()->LoadBattery(".bb", (uint8_t*)_data, BattleBox::FileSize);
}
~BattleBox()
{
SaveBattery();
}
void SaveBattery() override
{
_emu->GetBatteryManager()->SaveBattery(".bb", (uint8_t*)_data, BattleBox::FileSize);
}
uint8_t ReadRam(uint16_t addr) override
{
if(addr == 0x4017) {
if(_lastWrite & 0x01) {
_chipSelect ^= 0x01;
_inputData = 0;
_inputBitPosition = 0;
}
_output ^= 0x01;
uint8_t readBit = 0;
if(_isRead) {
readBit = ((_data[(_chipSelect ? 0x80 : 0) | _address] >> _inputBitPosition) & 0x01) << 3;
}
uint8_t writeBit = (_output << 4);
return readBit | writeBit;
}
return 0;
}
void WriteRam(uint16_t addr, uint8_t value) override
{
if(value & 0x01 && !(_lastWrite & 0x01)) {
//Clock
_inputData &= ~(1 << _inputBitPosition);
_inputData |= (_output << _inputBitPosition);
_inputBitPosition++;
if(_inputBitPosition > 15) {
if(_isWrite) {
_data[(_chipSelect ? 0x80 : 0) | _address] = _inputData;
_isWrite = false;
} else {
_isRead = false;
//done reading addr/command or write data
uint8_t address = (_inputData & 0x7F);
uint8_t cmd = ((_inputData & 0x7F00) >> 8) ^ 0x7F;
switch(cmd) {
case 0x01:
//read
_address = address;
_isRead = true;
break;
case 0x06:
//program
if(_writeEnabled) {
_address = address;
_isWrite = true;
}
break;
case 0x0C:
//chip erase
if(_writeEnabled) {
memset(_data, 0, BattleBox::FileSize);
}
break;
case 0x0D: break; //busy monitor
case 0x09: _writeEnabled = true; break; //erase/write enable
case 0x0B: _writeEnabled = false; break; //erase/write disable
}
}
_inputBitPosition = 0;
}
}
_lastWrite = value;
}
};

View file

@ -0,0 +1,64 @@
#pragma once
#include "stdafx.h"
#include "Shared/BaseControlDevice.h"
#include "Utilities/Serializer.h"
class Emulator;
class ExcitingBoxingController : public BaseControlDevice
{
private:
uint8_t _selectedSensors = 0;
enum Buttons { LeftHook = 0, MoveRight, MoveLeft, RightHook, LeftJab, HitBody, RightJab, Straight };
protected:
void Serialize(Serializer& s) override
{
BaseControlDevice::Serialize(s);
s.Stream(_selectedSensors);
}
string GetKeyNames() override
{
return "HRLhJBjS";
}
void InternalSetStateFromInput() override
{
for(KeyMapping keyMapping : _keyMappings) {
for(int i = 0; i < 8; i++) {
SetPressedState(i, keyMapping.CustomKeys[i]);
}
}
}
public:
ExcitingBoxingController(Emulator* emu, KeyMappingSet keyMappings) : BaseControlDevice(emu, ControllerType::ExcitingBoxing, BaseControlDevice::ExpDevicePort, keyMappings)
{
}
uint8_t ReadRam(uint16_t addr) override
{
if(addr == 0x4017) {
if(_selectedSensors == 0) {
return
(IsPressed(ExcitingBoxingController::Buttons::LeftHook) ? 0 : 0x02) |
(IsPressed(ExcitingBoxingController::Buttons::MoveRight) ? 0 : 0x04) |
(IsPressed(ExcitingBoxingController::Buttons::MoveLeft) ? 0 : 0x08) |
(IsPressed(ExcitingBoxingController::Buttons::RightHook) ? 0 : 0x10);
} else {
return
(IsPressed(ExcitingBoxingController::Buttons::LeftJab) ? 0 : 0x02) |
(IsPressed(ExcitingBoxingController::Buttons::HitBody) ? 0 : 0x04) |
(IsPressed(ExcitingBoxingController::Buttons::RightJab) ? 0 : 0x08) |
(IsPressed(ExcitingBoxingController::Buttons::Straight) ? 0 : 0x10);
}
}
return 0;
}
void WriteRam(uint16_t addr, uint8_t value) override
{
_selectedSensors = (value & 0x02) >> 1;
}
};

View file

@ -0,0 +1,141 @@
#pragma once
#include "stdafx.h"
#include "../Utilities/Base64.h"
#include "Shared/BaseControlDevice.h"
#include "Shared/Emulator.h"
#include "Utilities/Serializer.h"
class FamilyBasicDataRecorder : public BaseControlDevice
{
private:
static constexpr int32_t SamplingRate = 88;
vector<uint8_t> _data;
vector<uint8_t> _fileData;
bool _enabled = false;
bool _isPlaying = false;
uint64_t _cycle = 0;
bool _isRecording = false;
string _recordFilePath;
protected:
void Serialize(Serializer& s) override
{
BaseControlDevice::Serialize(s);
VectorInfo<uint8_t> data { &_data };
s.Stream(_enabled, _isPlaying, _cycle, data);
if(!s.IsSaving() && _isRecording) {
StopRecording();
}
}
bool IsRawString() override
{
return true;
}
void InternalSetStateFromInput() override
{
if(_fileData.size() > 0) {
SetTextState(Base64::Encode(_fileData));
_fileData.clear();
}
}
public:
FamilyBasicDataRecorder(Emulator* emu) : BaseControlDevice(emu, ControllerType::None, BaseControlDevice::ExpDevicePort2)
{
}
~FamilyBasicDataRecorder()
{
if(_isRecording) {
StopRecording();
}
}
void OnAfterSetState() override
{
if(GetRawState().State.size() > 0) {
_data = Base64::Decode(GetTextState());
_cycle = _emu->GetMasterClock();
_isPlaying = true;
_isRecording = false;
}
}
void LoadFromFile(VirtualFile file)
{
if(file.IsValid()) {
vector<uint8_t> fileData;
file.ReadFile(fileData);
_fileData = fileData;
}
}
bool IsRecording()
{
return _isRecording;
}
void StartRecording(string filePath)
{
_isPlaying = false;
_recordFilePath = filePath;
_data.clear();
_cycle = _emu->GetMasterClock();
_isRecording = true;
}
void StopRecording()
{
_isRecording = false;
vector<uint8_t> fileData;
int bitPos = 0;
uint8_t currentByte = 0;
for(uint8_t bitValue : _data) {
currentByte |= (bitValue & 0x01) << bitPos;
bitPos = (bitPos + 1) % 8;
if(bitPos == 0) {
fileData.push_back(currentByte);
currentByte = 0;
}
}
ofstream out(_recordFilePath, ios::binary);
if(out) {
out.write((char*)fileData.data(), fileData.size());
}
}
uint8_t ReadRam(uint16_t addr) override
{
if(addr == 0x4016 && _isPlaying) {
uint32_t readPos = (uint32_t)((_emu->GetMasterClock() - _cycle) / FamilyBasicDataRecorder::SamplingRate);
if((uint32_t)_data.size() > readPos / 8) {
uint8_t value = ((_data[readPos / 8] >> (readPos % 8)) & 0x01) << 1;
return _enabled ? value : 0;
} else {
_isPlaying = false;
}
}
return 0;
}
void WriteRam(uint16_t addr, uint8_t value) override
{
_enabled = (value & 0x04) != 0;
if(_isRecording) {
while(_emu->GetMasterClock() - _cycle > FamilyBasicDataRecorder::SamplingRate) {
_data.push_back(value & 0x01);
_cycle += 88;
}
}
}
};

View file

@ -0,0 +1,123 @@
#pragma once
#include "stdafx.h"
#include "Shared/BaseControlDevice.h"
#include "Utilities/Serializer.h"
class FamilyBasicKeyboard : public BaseControlDevice
{
private:
uint8_t _row = 0;
uint8_t _column = 0;
bool _enabled = false;
const uint32_t _keyMatrix[72] = {
F8, Return, LeftBracket, RightBracket,
Kana, RightShift, Yen, Stop,
F7, AtSign, Colon, SemiColon,
Underscore, Slash, Minus, Caret,
F6, O, L, K,
Dot, Comma, P, Num0,
F5, I, U, J,
M, N, Num9, Num8,
F4, Y, G, H,
B, V, Num7, Num6,
F3, T, R, D,
F, C, Num5, Num4,
F2, W, S, A,
X, Z, E, Num3,
F1, Esc, Q, Ctrl,
LeftShift, Grph, Num1, Num2,
ClrHome, Up, Right, Left,
Down, Space, Del, Ins
};
enum Buttons
{
A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z,
Num0, Num1, Num2, Num3, Num4, Num5, Num6, Num7, Num8, Num9,
Return, Space, Del, Ins, Esc,
Ctrl, RightShift, LeftShift,
RightBracket, LeftBracket,
Up, Down, Left, Right,
Dot, Comma, Colon, SemiColon, Underscore, Slash, Minus, Caret,
F1, F2, F3, F4, F5, F6, F7, F8,
Yen, Stop, AtSign, Grph, ClrHome, Kana
};
string GetKeyNames() override
{
return "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789rsdiecSs[]udlrd,:;_/-^12345678ysagck";
}
void InternalSetStateFromInput() override
{
//TODO
bool allowInput = false; // _emu->GetSettings()->IsKeyboardMode();
if(allowInput) {
for(KeyMapping keyMapping : _keyMappings) {
for(int i = 0; i < 72; i++) {
SetPressedState(i, keyMapping.CustomKeys[i]);
}
}
}
}
uint8_t GetActiveKeys(uint8_t row, uint8_t column)
{
if(row == 9) {
//10th row has no keys
return 0;
}
uint8_t result = 0;
uint32_t baseIndex = row * 8 + (column ? 4 : 0);
for(int i = 0; i < 4; i++) {
if(IsPressed(_keyMatrix[baseIndex + i])) {
result |= 0x10;
}
result >>= 1;
}
return result;
}
protected:
void Serialize(Serializer& s) override
{
BaseControlDevice::Serialize(s);
s.Stream(_row, _column, _enabled);
}
public:
FamilyBasicKeyboard(Emulator* emu, KeyMappingSet keyMappings) : BaseControlDevice(emu, ControllerType::FamilyBasicKeyboard, BaseControlDevice::ExpDevicePort, keyMappings)
{
}
uint8_t ReadRam(uint16_t addr) override
{
if(addr == 0x4017) {
if(_enabled) {
return ((~GetActiveKeys(_row, _column)) << 1) & 0x1E;
} else {
return 0;
}
}
return 0;
}
void WriteRam(uint16_t addr, uint8_t value) override
{
uint8_t prevColumn = _column;
_column = (value & 0x02) >> 1;
if(!_column && prevColumn) {
//"Incrementing the row from the (keyless) 10th row will cause it to wrap back to the first row."
_row = (_row + 1) % 10;
}
if(value & 0x01) {
_row = 0;
}
_enabled = (value & 0x04) != 0;
}
};

View file

@ -0,0 +1,46 @@
#pragma once
#include "stdafx.h"
#include "NES/Input/PowerPad.h"
#include "Utilities/Serializer.h"
class FamilyMatTrainer : public PowerPad
{
private:
uint8_t _ignoreRows = 0;
protected:
void Serialize(Serializer& s) override
{
BaseControlDevice::Serialize(s);
s.Stream(_ignoreRows);
}
public:
FamilyMatTrainer(Emulator* emu, KeyMappingSet keyMappings) : PowerPad(emu, ControllerType::FamilyTrainerMat, BaseControlDevice::ExpDevicePort, keyMappings)
{
}
uint8_t ReadRam(uint16_t addr) override
{
uint8_t output = 0;
if(addr == 0x4017) {
uint8_t pressedKeys[4] = {};
for(int j = 0; j < 3; j++) {
if((_ignoreRows >> (2 - j)) & 0x01) {
//Ignore this row
continue;
}
for(int i = 0; i < 4; i++) {
pressedKeys[i] |= IsPressed(j * 4 + i) ? 1 : 0;
}
}
output = ~((pressedKeys[0] << 4) | (pressedKeys[1] << 3) | (pressedKeys[2] << 2) | (pressedKeys[3] << 1)) & 0x1E;
}
return output;
}
void WriteRam(uint16_t addr, uint8_t value) override
{
_ignoreRows = value & 0x07;
}
};

View file

@ -0,0 +1,50 @@
#pragma once
#include "stdafx.h"
#include "Shared/BaseControlDevice.h"
#include "Utilities/Serializer.h"
class FourScore : public BaseControlDevice
{
private:
uint32_t _signature4016 = 0;
uint32_t _signature4017 = 0;
protected:
void Serialize(Serializer &s) override
{
BaseControlDevice::Serialize(s);
s.Stream(_signature4016, _signature4017);
}
void RefreshStateBuffer() override
{
//Signature for port 0 = 0x10, reversed bit order => 0x08
//Signature for port 1 = 0x20, reversed bit order => 0x04
_signature4016 = (0x08 << 16);
_signature4017 = (0x04 << 16);
}
public:
FourScore(Emulator* emu) : BaseControlDevice(emu, ControllerType::FourScore, BaseControlDevice::ExpDevicePort)
{
}
uint8_t ReadRam(uint16_t addr) override
{
StrobeProcessRead();
uint8_t output = 0;
if(addr == 0x4016) {
output = _signature4016 & 0x01;
_signature4016 >>= 1;
} else if(addr == 0x4017) {
output = _signature4017 & 0x01;
_signature4017 >>= 1;
}
return output;
}
void WriteRam(uint16_t addr, uint8_t value) override
{
StrobeProcessWrite(value);
}
};

View file

@ -0,0 +1,54 @@
#pragma once
#include "stdafx.h"
#include "NES/Input/NesController.h"
#include "Shared/KeyManager.h"
class HoriTrack : public NesController
{
protected:
bool HasCoordinates() override { return true; }
void InternalSetStateFromInput() override
{
NesController::InternalSetStateFromInput();
SetPressedState(NesController::Buttons::A, KeyManager::IsMouseButtonPressed(MouseButton::LeftButton));
SetPressedState(NesController::Buttons::B, KeyManager::IsMouseButtonPressed(MouseButton::RightButton));
SetMovement(KeyManager::GetMouseMovement(
_emu->GetSettings()->GetVideoConfig().VideoScale,
_emu->GetSettings()->GetInputConfig().MouseSensitivity + 1
));
}
public:
HoriTrack(Emulator* emu, KeyMappingSet keyMappings) : NesController(emu, ControllerType::HoriTrack, BaseControlDevice::ExpDevicePort, keyMappings)
{
}
uint8_t ReadRam(uint16_t addr) override
{
uint8_t output = 0;
if(addr == 0x4016) {
StrobeProcessRead();
output = (_stateBuffer & 0x01) << 1;
_stateBuffer >>= 1;
}
return output;
}
void RefreshStateBuffer() override
{
MouseMovement mov = GetMovement();
mov.dx = std::max(-8, std::min((int)mov.dx, 7));
mov.dy = std::max(-8, std::min((int)mov.dy, 7));
mov.dx = ((mov.dx & 0x08) >> 3) | ((mov.dx & 0x04) >> 1) | ((mov.dx & 0x02) << 1) | ((mov.dx & 0x01) << 3);
mov.dy = ((mov.dy & 0x08) >> 3) | ((mov.dy & 0x04) >> 1) | ((mov.dy & 0x02) << 1) | ((mov.dy & 0x01) << 3);
uint8_t byte1 = (~mov.dy & 0x0F) | ((~mov.dx & 0x0F) << 4);
uint8_t byte2 = 0x09;
NesController::RefreshStateBuffer();
_stateBuffer = (_stateBuffer & 0xFF) | (byte1 << 8) | (byte2 << 16);
}
};

View file

@ -0,0 +1,8 @@
#pragma once
#include "stdafx.h"
class IBarcodeReader
{
public:
virtual void InputBarcode(uint64_t barcode, uint32_t digitCount) = 0;
};

View file

@ -0,0 +1,99 @@
#pragma once
#include "stdafx.h"
#include "Shared/BaseControlDevice.h"
#include "Utilities/Serializer.h"
class JissenMahjongController : public BaseControlDevice
{
private:
uint8_t _row = 0;
uint32_t _stateBuffer = 0;
protected:
enum Buttons { A = 0, B, C, D, E, F, G, H, I, J, K, L, M, N, Select, Start, Kan, Pon, Chii, Riichi, Ron };
string GetKeyNames() override
{
return "ABCDEFGHIJKLMNSTkpcir";
}
void InternalSetStateFromInput() override
{
for(KeyMapping keyMapping : _keyMappings) {
for(int i = 0; i < 21; i++) {
SetPressedState(i, keyMapping.CustomKeys[i]);
}
}
}
void Serialize(Serializer& s) override
{
BaseControlDevice::Serialize(s);
s.Stream(_row, _stateBuffer);
}
public:
JissenMahjongController(Emulator* emu, KeyMappingSet keyMappings) : BaseControlDevice(emu, ControllerType::JissenMahjong, BaseControlDevice::ExpDevicePort, keyMappings)
{
}
uint8_t ReadRam(uint16_t addr) override
{
if(addr == 0x4017) {
StrobeProcessRead();
uint8_t value = (_stateBuffer & 0x01) << 1;
_stateBuffer >>= 1;
return value;
}
return 0;
}
void RefreshStateBuffer() override
{
switch(_row) {
default:
case 0:
_stateBuffer = 0;
break;
case 1:
_stateBuffer =
(IsPressed(JissenMahjongController::Buttons::N) ? 0x04 : 0) |
(IsPressed(JissenMahjongController::Buttons::M) ? 0x08 : 0) |
(IsPressed(JissenMahjongController::Buttons::L) ? 0x10 : 0) |
(IsPressed(JissenMahjongController::Buttons::K) ? 0x20 : 0) |
(IsPressed(JissenMahjongController::Buttons::J) ? 0x40 : 0) |
(IsPressed(JissenMahjongController::Buttons::I) ? 0x80 : 0);
break;
case 2:
_stateBuffer =
(IsPressed(JissenMahjongController::Buttons::H) ? 0x01 : 0) |
(IsPressed(JissenMahjongController::Buttons::G) ? 0x02 : 0) |
(IsPressed(JissenMahjongController::Buttons::F) ? 0x04 : 0) |
(IsPressed(JissenMahjongController::Buttons::E) ? 0x08 : 0) |
(IsPressed(JissenMahjongController::Buttons::D) ? 0x10 : 0) |
(IsPressed(JissenMahjongController::Buttons::C) ? 0x20 : 0) |
(IsPressed(JissenMahjongController::Buttons::B) ? 0x40 : 0) |
(IsPressed(JissenMahjongController::Buttons::A) ? 0x80 : 0);
break;
case 3:
_stateBuffer =
(IsPressed(JissenMahjongController::Buttons::Ron) ? 0x02 : 0) |
(IsPressed(JissenMahjongController::Buttons::Riichi) ? 0x04 : 0) |
(IsPressed(JissenMahjongController::Buttons::Chii) ? 0x08 : 0) |
(IsPressed(JissenMahjongController::Buttons::Pon) ? 0x10 : 0) |
(IsPressed(JissenMahjongController::Buttons::Kan) ? 0x20 : 0) |
(IsPressed(JissenMahjongController::Buttons::Start) ? 0x40 : 0) |
(IsPressed(JissenMahjongController::Buttons::Select) ? 0x80 : 0);
break;
}
}
void WriteRam(uint16_t addr, uint8_t value) override
{
_row = (value & 0x6) >> 1;
StrobeProcessWrite(value);
}
};

View file

@ -0,0 +1,86 @@
#pragma once
#include "stdafx.h"
#include "Shared/BaseControlDevice.h"
#include "Shared/Emulator.h"
#include "Utilities/Serializer.h"
class KonamiHyperShot : public BaseControlDevice
{
private:
bool _enableP1 = true;
bool _enableP2 = true;
uint32_t _p1TurboSpeed;
uint32_t _p2TurboSpeed;
vector<KeyMapping> _p2KeyMappings;
protected:
enum Buttons { Player1Run = 0, Player1Jump, Player2Run, Player2Jump };
string GetKeyNames() override
{
return "RJrj";
}
void InternalSetStateFromInput() override
{
for(KeyMapping keyMapping : _keyMappings) {
SetPressedState(Buttons::Player1Jump, keyMapping.A);
SetPressedState(Buttons::Player1Run, keyMapping.B);
uint8_t turboFreq = 1 << (4 - _p1TurboSpeed);
bool turboOn = (uint8_t)(_emu->GetFrameCount() % turboFreq) < turboFreq / 2;
if(turboOn) {
SetPressedState(Buttons::Player1Jump, keyMapping.TurboA);
SetPressedState(Buttons::Player1Run, keyMapping.TurboB);
}
}
for(KeyMapping keyMapping : _p2KeyMappings) {
SetPressedState(Buttons::Player2Jump, keyMapping.A);
SetPressedState(Buttons::Player2Run, keyMapping.B);
uint8_t turboFreq = 1 << (4 - _p2TurboSpeed);
bool turboOn = (uint8_t)(_emu->GetFrameCount() % turboFreq) < turboFreq / 2;
if(turboOn) {
SetPressedState(Buttons::Player2Jump, keyMapping.TurboA);
SetPressedState(Buttons::Player2Run, keyMapping.TurboB);
}
}
}
void Serialize(Serializer& s) override
{
BaseControlDevice::Serialize(s);
s.Stream(_enableP1, _enableP2);
}
public:
KonamiHyperShot(Emulator* emu, KeyMappingSet p1, KeyMappingSet p2) : BaseControlDevice(emu, ControllerType::KonamiHyperShot, BaseControlDevice::ExpDevicePort, p1)
{
_p1TurboSpeed = p1.TurboSpeed;
_p2TurboSpeed = p2.TurboSpeed;
_p2KeyMappings = p2.GetKeyMappingArray();
}
uint8_t ReadRam(uint16_t addr) override
{
uint8_t output = 0;
if(addr == 0x4017) {
if(_enableP1) {
output |= IsPressed(KonamiHyperShot::Buttons::Player1Jump) ? 0x02 : 0;
output |= IsPressed(KonamiHyperShot::Buttons::Player1Run) ? 0x04 : 0;
}
if(_enableP2) {
output |= IsPressed(KonamiHyperShot::Buttons::Player2Jump) ? 0x08 : 0;
output |= IsPressed(KonamiHyperShot::Buttons::Player2Run) ? 0x10 : 0;
}
}
return output;
}
void WriteRam(uint16_t addr, uint8_t value) override
{
_enableP2 = (value & 0x02) == 0;
_enableP1 = (value & 0x04) == 0;
}
};

View file

@ -89,11 +89,10 @@ protected:
public:
enum Buttons { Up = 0, Down, Left, Right, Start, Select, B, A, Microphone };
NesController(Emulator* emu, uint8_t port, KeyMappingSet keyMappings) : BaseControlDevice(emu, port, keyMappings)
NesController(Emulator* emu, ControllerType type, uint8_t port, KeyMappingSet keyMappings) : BaseControlDevice(emu, type, port, keyMappings)
{
_turboSpeed = keyMappings.TurboSpeed;
_microphoneEnabled = false;
//_microphoneEnabled = port == 1 && _console->GetSettings()->GetConsoleType() == ConsoleType::Famicom;
_microphoneEnabled = port == 1 && type == ControllerType::FamicomController;
}
uint8_t ToByte()

View file

@ -0,0 +1,82 @@
#pragma once
#include "stdafx.h"
#include "Shared/BaseControlDevice.h"
#include "Shared/Emulator.h"
#include "Shared/EmuSettings.h"
#include "Shared/KeyManager.h"
#include "Utilities/Serializer.h"
class OekaKidsTablet : public BaseControlDevice
{
private:
bool _strobe = false;
bool _shift = false;
uint32_t _stateBuffer = 0;
protected:
enum Buttons { Click, Touch };
bool HasCoordinates() override { return true; }
string GetKeyNames() override
{
return "CT";
}
void InternalSetStateFromInput() override
{
if(_emu->GetSettings()->IsInputEnabled()) {
MousePosition pos = KeyManager::GetMousePosition();
SetPressedState(Buttons::Click, KeyManager::IsMouseButtonPressed(MouseButton::LeftButton));
SetPressedState(Buttons::Touch, pos.Y >= 48 || KeyManager::IsMouseButtonPressed(MouseButton::LeftButton));
SetCoordinates(pos);
}
}
void Serialize(Serializer& s) override
{
BaseControlDevice::Serialize(s);
s.Stream(_strobe, _shift, _stateBuffer);
}
public:
OekaKidsTablet(Emulator* emu) : BaseControlDevice(emu, ControllerType::OekaKidsTablet, BaseControlDevice::ExpDevicePort)
{
}
uint8_t ReadRam(uint16_t addr) override
{
if(addr == 0x4017) {
if(_strobe) {
if(_shift) {
return (_stateBuffer & 0x40000) ? 0x00 : 0x08;
} else {
return 0x04;
}
} else {
return 0x00;
}
}
return 0;
}
void WriteRam(uint16_t addr, uint8_t value) override
{
_strobe = (value & 0x01) == 0x01;
bool shift = ((value >> 1) & 0x01) == 0x01;
if(_strobe) {
if(!_shift && shift) {
_stateBuffer <<= 1;
}
_shift = shift;
} else {
MousePosition pos = GetCoordinates();
uint8_t xPosition = (uint8_t)((double)std::max(0, pos.X + 8) / 256.0 * 240);
uint8_t yPosition = (uint8_t)((double)std::max(0, pos.Y - 14) / 240.0 * 256);
_stateBuffer = (xPosition << 10) | (yPosition << 2) | (IsPressed(OekaKidsTablet::Buttons::Touch) ? 0x02 : 0x00) | (IsPressed(OekaKidsTablet::Buttons::Click) ? 0x01 : 0x00);
}
}
};

View file

@ -0,0 +1,60 @@
#pragma once
#include "stdafx.h"
#include "NES/Input/NesController.h"
class PachinkoController : public NesController
{
private:
uint8_t _analogData = 0;
protected:
enum PachinkoButtons { Press = 8, Release = 9 };
void InternalSetStateFromInput() override
{
NesController::InternalSetStateFromInput();
for(KeyMapping keyMapping : _keyMappings) {
SetPressedState(PachinkoButtons::Press, keyMapping.CustomKeys[0]);
SetPressedState(PachinkoButtons::Release, keyMapping.CustomKeys[1]);
}
}
public:
PachinkoController(Emulator* emu, KeyMappingSet keyMappings) : NesController(emu, ControllerType::Pachinko, BaseControlDevice::ExpDevicePort, keyMappings)
{
}
uint8_t ReadRam(uint16_t addr) override
{
uint8_t output = 0;
if(addr == 0x4016) {
StrobeProcessRead();
output = (_stateBuffer & 0x01) << 1;
_stateBuffer >>= 1;
}
return output;
}
void RefreshStateBuffer() override
{
if(_analogData < 63 && IsPressed(PachinkoController::PachinkoButtons::Press)) {
_analogData++;
} else if(_analogData > 0 && IsPressed(PachinkoController::PachinkoButtons::Release)) {
_analogData--;
}
uint8_t analogData =
((_analogData & 0x01) << 7) |
((_analogData & 0x02) << 5) |
((_analogData & 0x04) << 3) |
((_analogData & 0x08) << 1) |
((_analogData & 0x10) >> 1) |
((_analogData & 0x20) >> 3) |
((_analogData & 0x40) >> 5) |
((_analogData & 0x80) >> 7);
NesController::RefreshStateBuffer();
_stateBuffer = (_stateBuffer & 0xFF) | (~analogData << 8);
}
};

76
Core/NES/Input/PartyTap.h Normal file
View file

@ -0,0 +1,76 @@
#pragma once
#include "stdafx.h"
#include "Shared/BaseControlDevice.h"
#include "Utilities/Serializer.h"
class Emulator;
class PartyTap : public BaseControlDevice
{
private:
uint8_t _stateBuffer = 0;
uint8_t _readCount = 0;
bool _enabled = false;
protected:
enum Buttons { B1 = 0, B2, B3, B4, B5, B6 };
string GetKeyNames() override
{
return "123456";
}
void InternalSetStateFromInput() override
{
for(KeyMapping keyMapping : _keyMappings) {
for(int i = 0; i < 6; i++) {
SetPressedState(i, keyMapping.CustomKeys[i]);
}
}
}
void Serialize(Serializer& s) override
{
BaseControlDevice::Serialize(s);
s.Stream(_stateBuffer, _readCount, _enabled);
}
public:
PartyTap(Emulator* emu, KeyMappingSet keyMappings) : BaseControlDevice(emu, ControllerType::PartyTap, BaseControlDevice::ExpDevicePort, keyMappings)
{
}
uint8_t ReadRam(uint16_t addr) override
{
if(addr == 0x4017) {
StrobeProcessRead();
if(_readCount < 2) {
uint8_t value = (_stateBuffer & 0x7) << 2;
_stateBuffer >>= 3;
_readCount++;
return value;
} else {
//"After 1st/2nd reads, a detection value can be read : $4017 & $1C == $14"
return 0x14;
}
}
return 0;
}
void RefreshStateBuffer() override
{
_readCount = 0;
_stateBuffer =
IsPressed(PartyTap::Buttons::B1) ? 1 : 0 |
IsPressed(PartyTap::Buttons::B2) ? 2 : 0 |
IsPressed(PartyTap::Buttons::B3) ? 4 : 0 |
IsPressed(PartyTap::Buttons::B4) ? 8 : 0 |
IsPressed(PartyTap::Buttons::B5) ? 16 : 0 |
IsPressed(PartyTap::Buttons::B6) ? 32 : 0;
}
void WriteRam(uint16_t addr, uint8_t value) override
{
StrobeProcessWrite(value);
}
};

81
Core/NES/Input/PowerPad.h Normal file
View file

@ -0,0 +1,81 @@
#pragma once
#include "stdafx.h"
#include "Shared/BaseControlDevice.h"
#include "Utilities/Serializer.h"
class Emulator;
class PowerPad : public BaseControlDevice
{
private:
uint8_t _stateBufferL = 0;
uint8_t _stateBufferH = 0;
protected:
string GetKeyNames() override
{
return "123456789ABC";
}
void InternalSetStateFromInput() override
{
for(KeyMapping keyMapping : _keyMappings) {
for(int i = 0; i < 3; i++) {
for(int j = 0; j < 4; j++) {
if(false) { //TODO
//Invert the order of each row
SetPressedState(i*4+j, keyMapping.CustomKeys[i*4+(3-j)]);
} else {
SetPressedState(i*4+j, keyMapping.CustomKeys[i*4+j]);
}
}
}
}
}
void RefreshStateBuffer() override
{
uint8_t pressedKeys[12] = {};
for(int i = 0; i < 12; i++) {
pressedKeys[i] |= IsPressed(i) ? 1 : 0;
}
//"Serial data from buttons 2, 1, 5, 9, 6, 10, 11, 7"
_stateBufferL = pressedKeys[1] | (pressedKeys[0] << 1) | (pressedKeys[4] << 2) | (pressedKeys[8] << 3) | (pressedKeys[5] << 4) | (pressedKeys[9] << 5) | (pressedKeys[10] << 6) | (pressedKeys[6] << 7);
//"Serial data from buttons 4, 3, 12, 8 (following 4 bits read as H=1)"
_stateBufferH = pressedKeys[3] | (pressedKeys[2] << 1) | (pressedKeys[11] << 2) | (pressedKeys[7] << 3) | 0xF0;
}
void Serialize(Serializer& s) override
{
BaseControlDevice::Serialize(s);
s.Stream(_stateBufferL, _stateBufferH);
}
public:
PowerPad(Emulator* emu, ControllerType type, uint8_t port, KeyMappingSet keyMappings) : BaseControlDevice(emu, type, port, keyMappings)
{
}
uint8_t ReadRam(uint16_t addr) override
{
uint8_t output = 0;
if(IsCurrentPort(addr)) {
StrobeProcessRead();
output = ((_stateBufferH & 0x01) << 4) | ((_stateBufferL & 0x01) << 3);
_stateBufferL >>= 1;
_stateBufferH >>= 1;
_stateBufferL |= 0x80;
_stateBufferH |= 0x80;
}
return output;
}
void WriteRam(uint16_t addr, uint8_t value) override
{
StrobeProcessWrite(value);
}
};

View file

@ -0,0 +1,126 @@
#pragma once
#include "stdafx.h"
#include "Shared/BaseControlDevice.h"
#include "Utilities/Serializer.h"
class SuborKeyboard : public BaseControlDevice
{
private:
uint8_t _row = 0;
uint8_t _column = 0;
bool _enabled = false;
protected:
string GetKeyNames() override
{
return "ABCDEFGHIJKLMNOPQRSTUVWXYZ01234567891234567890120123456789edpmdmncdsasbemglrcpcsasbteeehidududlr123";
}
enum Buttons
{
A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z,
Num0, Num1, Num2, Num3, Num4, Num5, Num6, Num7, Num8, Num9,
F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12,
Numpad0, Numpad1, Numpad2, Numpad3, Numpad4, Numpad5, Numpad6, Numpad7, Numpad8, Numpad9,
NumpadEnter, NumpadDot, NumpadPlus, NumpadMultiply, NumpadDivide, NumpadMinus, NumLock,
Comma, Dot, SemiColon, Apostrophe,
Slash, Backslash,
Equal, Minus, Grave,
LeftBracket, RightBracket,
CapsLock, Pause,
Ctrl, Shift, Alt,
Space, Backspace, Tab, Esc, Enter,
End, Home,
Ins, Delete,
PageUp, PageDown,
Up, Down, Left, Right,
Unknown1, Unknown2, Unknown3,
};
Buttons _keyboardMatrix[104] = {
Num4, G, F, C, F2, E, Num5, V,
Num2, D, S, End, F1, W, Num3, X,
Ins, Backspace, PageDown, Right, F8, PageUp, Delete, Home,
Num9, I, L, Comma, F5, O, Num0, Dot,
RightBracket, Enter, Up, Left, F7, LeftBracket, Backslash, Down,
Q, CapsLock, Z, Tab, Esc, A, Num1, Ctrl,
Num7, Y, K, M, F4, U, Num8, J,
Minus, SemiColon, Apostrophe, Slash, F6, P, Equal, Shift,
T, H, N, Space, F3, R, Num6, B,
Numpad6, NumpadEnter, Numpad4, Numpad8, Numpad2, Unknown1, Unknown2, Unknown3,
Alt, Numpad4, Numpad7, F11, F12, Numpad1, Numpad2, Numpad8,
NumpadMinus, NumpadPlus, NumpadMultiply, Numpad9, F10, Numpad5, NumpadDivide, NumLock,
Grave, Numpad6, Pause, Space, F9, Numpad3, NumpadDot, Numpad0
};
void InternalSetStateFromInput() override
{
//TODO
bool allowInput = false; // _emu->GetSettings()->IsKeyboardMode();
if(allowInput) {
for(KeyMapping keyMapping : _keyMappings) {
for(int i = 0; i < 99; i++) {
SetPressedState(i, keyMapping.CustomKeys[i]);
}
}
}
}
uint8_t GetActiveKeys(uint8_t row, uint8_t column)
{
uint8_t result = 0;
uint32_t baseIndex = row * 8 + (column ? 4 : 0);
for(int i = 0; i < 4; i++) {
if(IsPressed(_keyboardMatrix[baseIndex + i])) {
result |= 0x10;
}
result >>= 1;
}
return result;
}
void Serialize(Serializer& s) override
{
BaseControlDevice::Serialize(s);
s.Stream(_row, _column, _enabled);
}
void RefreshStateBuffer() override
{
_row = 0;
_column = 0;
}
public:
SuborKeyboard(Emulator* emu, KeyMappingSet keyMappings) : BaseControlDevice(emu, ControllerType::SuborKeyboard, BaseControlDevice::ExpDevicePort, keyMappings)
{
}
uint8_t ReadRam(uint16_t addr) override
{
if(addr == 0x4017) {
if(_enabled) {
uint8_t value = ((~GetActiveKeys(_row, _column)) << 1) & 0x1E;
return value;
} else {
return 0x1E;
}
}
return 0;
}
void WriteRam(uint16_t addr, uint8_t value) override
{
StrobeProcessWrite(value);
uint8_t prevColumn = _column;
_column = (value & 0x02) >> 1;
_enabled = (value & 0x04) != 0;
if(_enabled) {
if(!_column && prevColumn) {
_row = (_row + 1) % 13;
}
}
}
};

110
Core/NES/Input/SuborMouse.h Normal file
View file

@ -0,0 +1,110 @@
#pragma once
#include "stdafx.h"
#include "Shared/BaseControlDevice.h"
#include "Shared/KeyManager.h"
#include "Shared/EmuSettings.h"
#include "Shared/Emulator.h"
#include "Utilities/Serializer.h"
class SuborMouse : public BaseControlDevice
{
private:
uint32_t _stateBuffer = 0;
uint8_t _packetBytes[3] = {};
uint8_t _packetPos = 0;
uint8_t _packetSize = 1;
protected:
bool HasCoordinates() override { return true; }
enum Buttons { Left = 0, Right };
void Serialize(Serializer& s) override
{
BaseControlDevice::Serialize(s);
ArrayInfo<uint8_t> packetBytes { _packetBytes, 3 };
s.Stream(_stateBuffer, _packetPos, _packetSize, packetBytes);
}
void InternalSetStateFromInput() override
{
SetPressedState(Buttons::Left, KeyManager::IsMouseButtonPressed(MouseButton::LeftButton));
SetPressedState(Buttons::Right, KeyManager::IsMouseButtonPressed(MouseButton::RightButton));
SetMovement(KeyManager::GetMouseMovement(
_emu->GetSettings()->GetVideoConfig().VideoScale,
_emu->GetSettings()->GetInputConfig().MouseSensitivity + 1
));
}
public:
SuborMouse(Emulator* emu, uint8_t port) : BaseControlDevice(emu, ControllerType::SuborMouse, port)
{
}
void WriteRam(uint16_t addr, uint8_t value) override
{
StrobeProcessWrite(value);
}
uint8_t ReadRam(uint16_t addr) override
{
uint8_t output = 0;
if((addr == 0x4016 && (_port & 0x01) == 0) || (addr == 0x4017 && (_port & 0x01) == 1)) {
StrobeProcessRead();
output = (_stateBuffer & 0x80) >> 7;
if(_port >= 2) {
output <<= 1;
}
_stateBuffer <<= 1;
}
return output;
}
void RefreshStateBuffer() override
{
if(_packetPos < _packetSize - 1) {
//3-byte packet is not done yet, move to next byte
_packetPos++;
_stateBuffer = _packetBytes[_packetPos];
return;
}
MouseMovement mov = GetMovement();
uint32_t upFlag = mov.dy < 0 ? 0x80 : 0;
uint32_t leftFlag = mov.dx < 0 ? 0x80 : 0;
mov.dx = std::min<int16_t>(std::abs(mov.dx), 31);
mov.dy = std::min<int16_t>(std::abs(mov.dy), 31);
if(mov.dx <= 1 && mov.dy <= 1) {
//1-byte packet
_packetBytes[0] =
(IsPressed(SuborMouse::Buttons::Left) ? 0x80 : 0) |
(IsPressed(SuborMouse::Buttons::Right) ? 0x40 : 0) |
(leftFlag && mov.dx ? 0x30 : (mov.dx ? 0x10 : 0)) |
(upFlag && mov.dy ? 0x0C : (mov.dy ? 0x04 : 0));
_packetBytes[1] = 0;
_packetBytes[2] = 0;
_packetSize = 1;
} else {
//3-byte packet
_packetBytes[0] =
(IsPressed(SuborMouse::Buttons::Left) ? 0x80 : 0) |
(IsPressed(SuborMouse::Buttons::Right) ? 0x40 : 0) |
(leftFlag ? 0x20 : 0) |
(mov.dx & 0x10) |
(upFlag ? 0x08 : 0) |
((mov.dy & 0x10) >> 2) |
0x01;
_packetBytes[1] = ((mov.dx & 0x0F) << 2) | 0x02;
_packetBytes[2] = ((mov.dy & 0x0F) << 2) | 0x03;
_packetSize = 3;
}
_packetPos = 0;
_stateBuffer = _packetBytes[0];
}
};

View file

@ -0,0 +1,109 @@
#pragma once
#include "stdafx.h"
#include "Shared/BaseControlDevice.h"
#include "Shared/Emulator.h"
#include "Shared/EmuSettings.h"
#include "Utilities/Serializer.h"
class VirtualBoyController : public BaseControlDevice
{
private:
uint32_t _stateBuffer = 0;
protected:
enum Buttons { Down1 = 0, Left1, Select, Start, Up0, Down0, Left0, Right0, Right1, Up1, L, R, B, A };
string GetKeyNames() override
{
return "dlSTUDLRruLRBA";
}
void InternalSetStateFromInput() override
{
for(KeyMapping keyMapping : _keyMappings) {
for(int i = 0; i < 14; i++) {
SetPressedState(i, keyMapping.CustomKeys[i]);
}
if(!_emu->GetSettings()->GetNesConfig().AllowInvalidInput) {
//If both U+D or L+R are pressed at the same time, act as if neither is pressed
if(IsPressed(Buttons::Up0) && IsPressed(Buttons::Down0)) {
ClearBit(Buttons::Down0);
ClearBit(Buttons::Up0);
}
if(IsPressed(Buttons::Left0) && IsPressed(Buttons::Right0)) {
ClearBit(Buttons::Left0);
ClearBit(Buttons::Right0);
}
if (IsPressed(Buttons::Up1) && IsPressed(Buttons::Down1)) {
ClearBit(Buttons::Down1);
ClearBit(Buttons::Up1);
}
if (IsPressed(Buttons::Left1) && IsPressed(Buttons::Right1)) {
ClearBit(Buttons::Left1);
ClearBit(Buttons::Right1);
}
}
}
}
uint16_t ToByte()
{
//"A Virtual Boy controller returns a 16-bit report in a similar order as SNES, with two additional buttons."
return
(uint8_t)IsPressed(Buttons::Down1) |
((uint8_t)IsPressed(Buttons::Left1) << 1) |
((uint8_t)IsPressed(Buttons::Select) << 2) |
((uint8_t)IsPressed(Buttons::Start) << 3) |
((uint8_t)IsPressed(Buttons::Up0) << 4) |
((uint8_t)IsPressed(Buttons::Down0) << 5) |
((uint8_t)IsPressed(Buttons::Left0) << 6) |
((uint8_t)IsPressed(Buttons::Right0) << 7) |
((uint8_t)IsPressed(Buttons::Right1) << 8) |
((uint8_t)IsPressed(Buttons::Up1) << 9) |
((uint8_t)IsPressed(Buttons::L) << 10) |
((uint8_t)IsPressed(Buttons::R) << 11) |
((uint8_t)IsPressed(Buttons::B) << 12) |
((uint8_t)IsPressed(Buttons::A) << 13) |
(1 << 14);
}
void Serialize(Serializer& s) override
{
BaseControlDevice::Serialize(s);
s.Stream(_stateBuffer);
}
void RefreshStateBuffer() override
{
_stateBuffer = (uint32_t)ToByte();
}
public:
VirtualBoyController(Emulator* emu, uint8_t port, KeyMappingSet keyMappings) : BaseControlDevice(emu, ControllerType::VirtualBoyController, port, keyMappings)
{
}
uint8_t ReadRam(uint16_t addr) override
{
uint8_t output = 0;
if(IsCurrentPort(addr)) {
StrobeProcessRead();
output = _stateBuffer & 0x01;
_stateBuffer >>= 1;
//"All subsequent reads will return D=1 on an authentic controller but may return D=0 on third party controllers."
_stateBuffer |= 0x8000;
}
return output;
}
void WriteRam(uint16_t addr, uint8_t value) override
{
StrobeProcessWrite(value);
}
};

45
Core/NES/Input/VsZapper.h Normal file
View file

@ -0,0 +1,45 @@
#pragma once
#include "stdafx.h"
#include "NES/Input/Zapper.h"
class NesConsole;
class VsZapper : public Zapper
{
private:
uint32_t _stateBuffer = 0;
protected:
void Serialize(Serializer& s) override
{
BaseControlDevice::Serialize(s);
s.Stream(_stateBuffer);
}
void RefreshStateBuffer() override
{
_stateBuffer = 0x10 | (IsLightFound() ? 0x40 : 0x00) | (IsPressed(Zapper::Buttons::Fire) ? 0x80 : 0x00);
}
public:
VsZapper(NesConsole* console, uint8_t port) : Zapper(console, ControllerType::VsZapper, port)
{
}
uint8_t ReadRam(uint16_t addr) override
{
if(IsCurrentPort(addr)) {
StrobeProcessRead();
uint8_t returnValue = _stateBuffer & 0x01;
_stateBuffer >>= 1;
return returnValue;
}
return 0;
}
void WriteRam(uint16_t addr, uint8_t value) override
{
StrobeProcessWrite(value);
}
};

98
Core/NES/Input/Zapper.h Normal file
View file

@ -0,0 +1,98 @@
#pragma once
#include "stdafx.h"
#include "Shared/BaseControlDevice.h"
#include "NES/NesPpu.h"
#include "NES/NesConsole.h"
#include "Shared/Emulator.h"
#include "Shared/Emulator.h"
#include "Shared/EmuSettings.h"
#include "Shared/KeyManager.h"
#include "Utilities/Serializer.h"
class Zapper : public BaseControlDevice
{
private:
NesConsole* _console;
protected:
bool HasCoordinates() override { return true; }
string GetKeyNames() override
{
return "F";
}
ControllerType GetControllerType()
{
return ControllerType::NesController;
}
enum Buttons { Fire };
void InternalSetStateFromInput() override
{
SetPressedState(Buttons::Fire, KeyManager::IsMouseButtonPressed(MouseButton::LeftButton));
MousePosition pos = KeyManager::GetMousePosition();
if(KeyManager::IsMouseButtonPressed(MouseButton::RightButton)) {
pos.X = -1;
pos.Y = -1;
}
SetCoordinates(pos);
}
bool IsLightFound()
{
return StaticIsLightFound(GetCoordinates(), _console);
}
public:
Zapper(NesConsole* console, ControllerType type, uint8_t port) : BaseControlDevice(console->GetEmulator(), type, port)
{
_console = console;
}
uint8_t ReadRam(uint16_t addr) override
{
uint8_t output = 0;
if((IsExpansionDevice() && addr == 0x4017) || IsCurrentPort(addr)) {
output = (IsLightFound() ? 0 : 0x08) | (IsPressed(Zapper::Buttons::Fire) ? 0x10 : 0x00);
}
return output;
}
void WriteRam(uint16_t addr, uint8_t value) override
{
}
static bool StaticIsLightFound(MousePosition pos, NesConsole* console)
{
NesPpu* ppu = console ? console->GetPpu() : nullptr;
if(!ppu) {
return false;
}
int32_t scanline = ppu->GetCurrentScanline();
int32_t cycle = ppu->GetCurrentCycle();
int radius = (int)console->GetNesConfig().ZapperDetectionRadius;
if(pos.X >= 0 && pos.Y >= 0) {
for(int yOffset = -radius; yOffset <= radius; yOffset++) {
int yPos = pos.Y + yOffset;
if(yPos >= 0 && yPos < NesPpu::ScreenHeight) {
for(int xOffset = -radius; xOffset <= radius; xOffset++) {
int xPos = pos.X + xOffset;
if(xPos >= 0 && xPos < NesPpu::ScreenWidth) {
if(scanline >= yPos && (scanline - yPos <= 20) && (scanline != yPos || cycle > xPos) && ppu->GetPixelBrightness(xPos, yPos) >= 85) {
//Light cannot be detected if the Y/X position is further ahead than the PPU, or if the PPU drew a dark color
return true;
}
}
}
}
}
}
return false;
}
};

View file

@ -249,3 +249,8 @@ uint64_t NesConsole::GetMasterClock()
{
return _cpu->GetCycleCount();
}
uint32_t NesConsole::GetMasterClockRate()
{
return NesCpu::ClockRateNtsc;
}

View file

@ -77,5 +77,6 @@ public:
virtual AddressInfo GetAbsoluteAddress(AddressInfo relAddress) override;
virtual AddressInfo GetRelativeAddress(AddressInfo absAddress, CpuType cpuType) override;
virtual uint64_t GetMasterClock() override;
uint64_t GetMasterClock() override;
uint32_t GetMasterClockRate() override;
};

View file

@ -3,8 +3,6 @@
#include "NES/BaseMapper.h"
#include "NES/NesConsole.h"
#include "NES/NesMemoryManager.h"
#include "NES/Input/NesController.h"
#include "SNES/Input/SnesController.h"
#include "Shared/EmuSettings.h"
#include "Shared/Interfaces/IKeyManager.h"
#include "Shared/Interfaces/IInputProvider.h"
@ -13,30 +11,31 @@
#include "Shared/Emulator.h"
#include "Shared/KeyManager.h"
#include "Shared/SystemActionManager.h"
/*#include "Zapper.h"
#include "ArkanoidController.h"
#include "OekaKidsTablet.h"
#include "FourScore.h"
#include "SnesController.h"
#include "SnesMouse.h"
#include "PowerPad.h"
#include "FamilyMatTrainer.h"
#include "KonamiHyperShot.h"
#include "FamilyBasicKeyboard.h"
#include "FamilyBasicDataRecorder.h"
#include "PartyTap.h"
#include "PachinkoController.h"
#include "ExcitingBoxingController.h"
#include "SuborKeyboard.h"
#include "SuborMouse.h"
#include "JissenMahjongController.h"
#include "BarcodeBattlerReader.h"
#include "HoriTrack.h"
#include "BandaiHyperShot.h"
#include "VsZapper.h"
#include "AsciiTurboFile.h"
#include "BattleBox.h"
#include "VbController.h"*/
#include "NES/Input/NesController.h"
#include "SNES/Input/SnesController.h"
#include "SNES/Input/SnesMouse.h"
#include "NES/Input/Zapper.h"
#include "NES/Input/ArkanoidController.h"
#include "NES/Input/OekaKidsTablet.h"
#include "NES/Input/FourScore.h"
#include "NES/Input/PowerPad.h"
#include "NES/Input/FamilyMatTrainer.h"
#include "NES/Input/KonamiHyperShot.h"
#include "NES/Input/FamilyBasicKeyboard.h"
#include "NES/Input/FamilyBasicDataRecorder.h"
#include "NES/Input/PartyTap.h"
#include "NES/Input/PachinkoController.h"
#include "NES/Input/ExcitingBoxingController.h"
#include "NES/Input/SuborKeyboard.h"
#include "NES/Input/SuborMouse.h"
#include "NES/Input/JissenMahjongController.h"
#include "NES/Input/BarcodeBattlerReader.h"
#include "NES/Input/HoriTrack.h"
#include "NES/Input/BandaiHyperShot.h"
#include "NES/Input/VsZapper.h"
#include "NES/Input/AsciiTurboFile.h"
#include "NES/Input/BattleBox.h"
#include "NES/Input/VirtualBoyController.h"
NesControlManager::NesControlManager(shared_ptr<NesConsole> console, shared_ptr<BaseControlDevice> mapperControlDevice) : BaseControlManager(console->GetEmulator())
{
@ -58,48 +57,43 @@ shared_ptr<BaseControlDevice> NesControlManager::CreateControllerDevice(Controll
shared_ptr<BaseControlDevice> device;
NesConfig cfg = _emu->GetSettings()->GetNesConfig();
KeyMappingSet keys = cfg.Controllers[port].Keys;
switch(type) {
case ControllerType::None: break;
case ControllerType::NesController: device.reset(new NesController(_emu, port, cfg.Controllers[port].Keys)); break;
//case ControllerType::Zapper: device.reset(new Zapper(console, port)); break;
//case ControllerType::ArkanoidController: device.reset(new ArkanoidController(console, port)); break;
case ControllerType::SnesController: device.reset(new SnesController(_emu, port, cfg.Controllers[port].Keys)); break;
/*case ControllerType::PowerPad: device.reset(new PowerPad(console, port, console->GetSettings()->GetControllerKeys(port))); break;
case ControllerType::SnesMouse: device.reset(new SnesMouse(console, port)); break;
case ControllerType::SuborMouse: device.reset(new SuborMouse(console, port)); break;
case ControllerType::VsZapper: device.reset(new VsZapper(console, port)); break;
case ControllerType::VbController: device.reset(new VbController(console, port, console->GetSettings()->GetControllerKeys(port))); break;*/
}
return device;
}
case ControllerType::NesController: device.reset(new NesController(_emu, type, port, keys)); break;
case ControllerType::FamicomController: device.reset(new NesController(_emu, type, port, keys)); break;
case ControllerType::NesZapper: device.reset(new Zapper(_console.get(), type, port)); break;
case ControllerType::NesArkanoidController: device.reset(new ArkanoidController(_emu, type, port)); break;
case ControllerType::SnesController: device.reset(new SnesController(_emu, port, keys)); break;
case ControllerType::PowerPad: device.reset(new PowerPad(_emu, type, port, keys)); break;
case ControllerType::SnesMouse: device.reset(new SnesMouse(_emu, port)); break;
case ControllerType::SuborMouse: device.reset(new SuborMouse(_emu, port)); break;
case ControllerType::VsZapper: device.reset(new VsZapper(_console.get(), port)); break;
case ControllerType::VirtualBoyController: device.reset(new VirtualBoyController(_emu, port, keys)); break;
shared_ptr<BaseControlDevice> NesControlManager::CreateExpansionDevice(ExpansionPortDevice type)
{
shared_ptr<BaseControlDevice> device;
//Exp port devices
case ControllerType::FamicomZapper: device.reset(new Zapper(_console.get(), type, BaseControlDevice::ExpDevicePort)); break;
case ControllerType::FamicomArkanoidController: device.reset(new ArkanoidController(_emu, type, BaseControlDevice::ExpDevicePort)); break;
case ControllerType::OekaKidsTablet: device.reset(new OekaKidsTablet(_emu)); break;
case ControllerType::FamilyTrainerMat: device.reset(new FamilyMatTrainer(_emu, keys)); break;
case ControllerType::KonamiHyperShot: device.reset(new KonamiHyperShot(_emu, keys, cfg.Controllers[1].Keys)); break;
case ControllerType::FamilyBasicKeyboard: device.reset(new FamilyBasicKeyboard(_emu, keys)); break;
case ControllerType::PartyTap: device.reset(new PartyTap(_emu, keys)); break;
case ControllerType::Pachinko: device.reset(new PachinkoController(_emu, keys)); break;
case ControllerType::ExcitingBoxing: device.reset(new ExcitingBoxingController(_emu, keys)); break;
case ControllerType::JissenMahjong: device.reset(new JissenMahjongController(_emu, keys)); break;
case ControllerType::SuborKeyboard: device.reset(new SuborKeyboard(_emu, keys)); break;
case ControllerType::BarcodeBattler: device.reset(new BarcodeBattlerReader(_emu)); break;
case ControllerType::HoriTrack: device.reset(new HoriTrack(_emu, keys)); break;
case ControllerType::BandaiHyperShot: device.reset(new BandaiHyperShot(_console.get(), keys)); break;
case ControllerType::AsciiTurboFile: device.reset(new AsciiTurboFile(_emu)); break;
case ControllerType::BattleBox: device.reset(new BattleBox(_emu)); break;
/*switch(type) {
case ExpansionPortDevice::Zapper: device.reset(new Zapper(console, BaseControlDevice::ExpDevicePort)); break;
case ExpansionPortDevice::ArkanoidController: device.reset(new ArkanoidController(console, BaseControlDevice::ExpDevicePort)); break;
case ExpansionPortDevice::OekaKidsTablet: device.reset(new OekaKidsTablet(console)); break;
case ExpansionPortDevice::FamilyTrainerMat: device.reset(new FamilyMatTrainer(console, console->GetSettings()->GetControllerKeys(0))); break;
case ExpansionPortDevice::KonamiHyperShot: device.reset(new KonamiHyperShot(console, console->GetSettings()->GetControllerKeys(0), console->GetSettings()->GetControllerKeys(1))); break;
case ExpansionPortDevice::FamilyBasicKeyboard: device.reset(new FamilyBasicKeyboard(console, console->GetSettings()->GetControllerKeys(0))); break;
case ExpansionPortDevice::PartyTap: device.reset(new PartyTap(console, console->GetSettings()->GetControllerKeys(0))); break;
case ExpansionPortDevice::Pachinko: device.reset(new PachinkoController(console, console->GetSettings()->GetControllerKeys(0))); break;
case ExpansionPortDevice::ExcitingBoxing: device.reset(new ExcitingBoxingController(console, console->GetSettings()->GetControllerKeys(0))); break;
case ExpansionPortDevice::JissenMahjong: device.reset(new JissenMahjongController(console, console->GetSettings()->GetControllerKeys(0))); break;
case ExpansionPortDevice::SuborKeyboard: device.reset(new SuborKeyboard(console, console->GetSettings()->GetControllerKeys(0))); break;
case ExpansionPortDevice::BarcodeBattler: device.reset(new BarcodeBattlerReader(console)); break;
case ExpansionPortDevice::HoriTrack: device.reset(new HoriTrack(console, console->GetSettings()->GetControllerKeys(0))); break;
case ExpansionPortDevice::BandaiHyperShot: device.reset(new BandaiHyperShot(console, console->GetSettings()->GetControllerKeys(0))); break;
case ExpansionPortDevice::AsciiTurboFile: device.reset(new AsciiTurboFile(console)); break;
case ExpansionPortDevice::BattleBox: device.reset(new BattleBox(console)); break;
case ExpansionPortDevice::FourPlayerAdapter:
case ControllerType::FourScore: //TODO
case ControllerType::FourPlayerAdapter: //TODO
default: break;
}*/
}
return device;
}

View file

@ -41,7 +41,7 @@ shared_ptr<BaseControlDevice> ControlManager::CreateControllerDevice(ControllerT
switch(type) {
case ControllerType::None: break;
case ControllerType::SnesController: device.reset(new SnesController(_emu, port, cfg.Controllers[port].Keys)); break;
case ControllerType::SnesMouse: device.reset(new SnesMouse(_console, port)); break;
case ControllerType::SnesMouse: device.reset(new SnesMouse(_emu, port)); break;
case ControllerType::SuperScope: device.reset(new SuperScope(_console, port, cfg.Controllers[port].Keys)); break;
case ControllerType::Multitap: device.reset(new Multitap(_console, port, cfg.Controllers[port].Keys, cfg.Controllers[2].Keys, cfg.Controllers[3].Keys, cfg.Controllers[4].Keys)); break;
}

View file

@ -94,7 +94,7 @@ void Multitap::RefreshStateBuffer()
}
}
Multitap::Multitap(Console* console, uint8_t port, KeyMappingSet keyMappings1, KeyMappingSet keyMappings2, KeyMappingSet keyMappings3, KeyMappingSet keyMappings4) : BaseControlDevice(console->GetEmulator(), port, keyMappings1)
Multitap::Multitap(Console* console, uint8_t port, KeyMappingSet keyMappings1, KeyMappingSet keyMappings2, KeyMappingSet keyMappings3, KeyMappingSet keyMappings4) : BaseControlDevice(console->GetEmulator(), ControllerType::Multitap, port, keyMappings1)
{
_turboSpeed[0] = keyMappings1.TurboSpeed;
_turboSpeed[1] = keyMappings2.TurboSpeed;
@ -108,11 +108,6 @@ Multitap::Multitap(Console* console, uint8_t port, KeyMappingSet keyMappings1, K
_internalRegs = console->GetInternalRegisters().get();
}
ControllerType Multitap::GetControllerType()
{
return ControllerType::Multitap;
}
void Multitap::SetControllerState(uint8_t controllerNumber, ControlDeviceState state)
{
SnesController controller(_emu, 0, KeyMappingSet());

View file

@ -29,8 +29,6 @@ protected:
public:
Multitap(Console* console, uint8_t port, KeyMappingSet keyMappings1, KeyMappingSet keyMappings2, KeyMappingSet keyMappings3, KeyMappingSet keyMappings4);
ControllerType GetControllerType() override;
void SetControllerState(uint8_t controllerNumber, ControlDeviceState state);
uint8_t ReadRam(uint16_t addr) override;

View file

@ -2,7 +2,7 @@
#include "SNES/Input/SnesController.h"
#include "Shared/Emulator.h"
SnesController::SnesController(Emulator* emu, uint8_t port, KeyMappingSet keyMappings) : BaseControlDevice(emu, port, keyMappings)
SnesController::SnesController(Emulator* emu, uint8_t port, KeyMappingSet keyMappings) : BaseControlDevice(emu, ControllerType::SnesController, port, keyMappings)
{
_turboSpeed = keyMappings.TurboSpeed;
}
@ -71,11 +71,6 @@ void SnesController::RefreshStateBuffer()
_stateBuffer = (uint32_t)ToByte();
}
ControllerType SnesController::GetControllerType()
{
return ControllerType::SnesController;
}
uint8_t SnesController::ReadRam(uint16_t addr)
{
uint8_t output = 0;

View file

@ -21,7 +21,6 @@ public:
SnesController(Emulator* emu, uint8_t port, KeyMappingSet keyMappings);
ControllerType GetControllerType() override;
uint8_t ReadRam(uint16_t addr) override;
void WriteRam(uint16_t addr, uint8_t value) override;
};

View file

@ -1,6 +1,5 @@
#pragma once
#include "stdafx.h"
#include "SNES/Console.h"
#include "Shared/BaseControlDevice.h"
#include "Shared/Interfaces/IKeyManager.h"
#include "Shared/KeyManager.h"
@ -42,16 +41,11 @@ protected:
public:
enum Buttons { Left = 0, Right };
SnesMouse(Console* console, uint8_t port) : BaseControlDevice(console->GetEmulator(), port)
SnesMouse(Emulator* emu, uint8_t port) : BaseControlDevice(emu, ControllerType::SnesMouse, port)
{
_settings = _emu->GetSettings();
}
ControllerType GetControllerType() override
{
return ControllerType::SnesMouse;
}
void WriteRam(uint16_t addr, uint8_t value) override
{
StrobeProcessWrite(value);

View file

@ -93,16 +93,11 @@ protected:
}
public:
SuperScope(Console* console, uint8_t port, KeyMappingSet keyMappings) : BaseControlDevice(console->GetEmulator(), port, keyMappings)
SuperScope(Console* console, uint8_t port, KeyMappingSet keyMappings) : BaseControlDevice(console->GetEmulator(), ControllerType::SuperScope, port, keyMappings)
{
_ppu = console->GetPpu().get();
}
ControllerType GetControllerType() override
{
return ControllerType::SuperScope;
}
uint8_t ReadRam(uint16_t addr) override
{
uint8_t output = 0;

View file

@ -5,9 +5,10 @@
#include "Utilities/StringUtilities.h"
#include "Utilities/Serializer.h"
BaseControlDevice::BaseControlDevice(Emulator* emu, uint8_t port, KeyMappingSet keyMappingSet)
BaseControlDevice::BaseControlDevice(Emulator* emu, ControllerType type, uint8_t port, KeyMappingSet keyMappingSet)
{
_emu = emu;
_type = type;
_port = port;
_strobe = false;
_keyMappings = keyMappingSet.GetKeyMappingArray();
@ -22,6 +23,11 @@ uint8_t BaseControlDevice::GetPort()
return _port;
}
ControllerType BaseControlDevice::GetControllerType()
{
return _type;
}
void BaseControlDevice::SetStateFromInput()
{
ClearState();

View file

@ -17,6 +17,7 @@ protected:
Emulator* _emu;
vector<KeyMapping> _keyMappings;
bool _strobe;
ControllerType _type;
uint8_t _port;
SimpleLock _stateLock;
@ -51,10 +52,11 @@ public:
static constexpr uint8_t ExpDevicePort2 = 7;
static constexpr uint8_t PortCount = ExpDevicePort2 + 1;
BaseControlDevice(Emulator* emu, uint8_t port, KeyMappingSet keyMappingSet = KeyMappingSet());
BaseControlDevice(Emulator* emu, ControllerType type, uint8_t port, KeyMappingSet keyMappingSet = KeyMappingSet());
virtual ~BaseControlDevice();
uint8_t GetPort();
ControllerType GetControllerType();
bool IsPressed(uint8_t bit);
MousePosition GetCoordinates();
@ -74,7 +76,6 @@ public:
void SetRawState(ControlDeviceState state);
ControlDeviceState GetRawState();
virtual ControllerType GetControllerType() = 0;
virtual uint8_t ReadRam(uint16_t addr) = 0;
virtual void WriteRam(uint16_t addr, uint8_t value) = 0;

View file

@ -331,8 +331,7 @@ bool Emulator::LoadRom(VirtualFile romFile, VirtualFile patchFile, bool stopRom,
}
if(patchFile.IsValid()) {
//TODO
//_patchPath = patchFile;
_patchFile = patchFile;
if(romFile.ApplyPatch(patchFile)) {
MessageManager::DisplayMessage("Patch", "ApplyingPatch", patchFile.GetFileName());
}
@ -478,6 +477,11 @@ uint64_t Emulator::GetMasterClock()
return _console->GetMasterClock();
}
uint32_t Emulator::GetMasterClockRate()
{
return _console->GetMasterClockRate();
}
uint32_t Emulator::GetFrameCount()
{
return _console->GetPpuFrame().FrameCount;

View file

@ -129,6 +129,7 @@ public:
ConsoleType GetConsoleType();
vector<CpuType> GetCpuTypes();
uint64_t GetMasterClock();
uint32_t GetMasterClockRate();
EmulatorLock AcquireLock();
void Lock();

View file

@ -0,0 +1,7 @@
#pragma once
class IBattery
{
public:
virtual void SaveBattery() = 0;
};

View file

@ -37,6 +37,7 @@ public:
virtual vector<CpuType> GetCpuTypes() = 0;
virtual uint64_t GetMasterClock() = 0;
virtual uint32_t GetMasterClockRate() = 0;
virtual double GetFrameDelay() = 0;
virtual double GetFps() = 0;

View file

@ -144,12 +144,46 @@ struct AudioConfig
//Update ControllerTypeNames when changing this
enum class ControllerType
{
None = 0,
SnesController = 1,
SnesMouse = 2,
SuperScope = 3,
Multitap = 4,
NesController = 5
None,
//SNES controllers
SnesController,
SnesMouse,
SuperScope,
Multitap,
//NES controllers
NesController,
FamicomController,
NesZapper,
NesArkanoidController,
PowerPad,
SuborMouse,
VsZapper,
VirtualBoyController,
//NES/Famicon expansion devices
FourScore,
FamicomZapper,
FourPlayerAdapter,
FamicomArkanoidController,
OekaKidsTablet,
FamilyTrainerMat,
KonamiHyperShot,
FamilyBasicKeyboard,
PartyTap,
Pachinko,
ExcitingBoxing,
JissenMahjong,
SuborKeyboard,
BarcodeBattler,
HoriTrack,
BandaiHyperShot,
AsciiTurboFile,
BattleBox,
//Game Boy
GameboyController,
};
struct KeyMapping
@ -354,6 +388,7 @@ enum class VsDualOutputOption
struct NesConfig
{
ControllerConfig Controllers[5];
uint32_t ZapperDetectionRadius = 0;
bool EnableHdPacks = true;
bool DisableGameDatabase = false;

View file

@ -18,15 +18,10 @@ protected:
public:
enum Buttons { ResetButton = 0, PowerButton = 1 };
SystemActionManager(Emulator* emu) : BaseControlDevice(emu, BaseControlDevice::ConsoleInputPort)
SystemActionManager(Emulator* emu) : BaseControlDevice(emu, ControllerType::None, BaseControlDevice::ConsoleInputPort)
{
}
ControllerType GetControllerType() override
{
return ControllerType::None;
}
uint8_t ReadRam(uint16_t addr) override
{
return 0;

View file

@ -12,6 +12,7 @@ namespace Mesen.GUI.Config
{
//Input
[Reactive] public List<ControllerConfig> Controllers { get; set; } = new List<ControllerConfig> { new ControllerConfig(), new ControllerConfig(), new ControllerConfig(), new ControllerConfig(), new ControllerConfig() };
[Reactive] public UInt32 ZapperDetectionRadius { get; set; } = 0;
//Video
[Reactive] public bool EnableHdPacks { get; set; } = true;
@ -117,6 +118,7 @@ namespace Mesen.GUI.Config
this.Controllers[3].ToInterop(),
this.Controllers[4].ToInterop()
},
ZapperDetectionRadius = ZapperDetectionRadius,
EnableHdPacks = EnableHdPacks,
DisableGameDatabase = DisableGameDatabase,
@ -246,6 +248,7 @@ namespace Mesen.GUI.Config
{
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 5)]
public InteropControllerConfig[] Controllers;
public UInt32 ZapperDetectionRadius;
[MarshalAs(UnmanagedType.I1)] public bool EnableHdPacks;
[MarshalAs(UnmanagedType.I1)] public bool DisableGameDatabase;