Oeka Kids Tablet support

This commit is contained in:
Souryo 2016-07-30 17:27:14 -04:00
parent e08db1cd04
commit 5f59dc1a7f
20 changed files with 185 additions and 37 deletions

View file

@ -5,9 +5,9 @@
class ArkanoidController : public BaseControlDevice
{
private:
uint32_t _stateBuffer;
bool _buttonPressed;
int32_t _xPosition;
uint32_t _stateBuffer = 0;
bool _buttonPressed = false;
int32_t _xPosition = 0;
bool IsButtonPressed();

View file

@ -3,6 +3,7 @@
#include "StandardController.h"
#include "Zapper.h"
#include "ArkanoidController.h"
#include "OekaKidsTablet.h"
#include "EmulationSettings.h"
#include "Console.h"
#include "GameServerConnection.h"
@ -124,19 +125,15 @@ void ControlManager::UpdateControlDevices()
bool fourScore = EmulationSettings::CheckFlag(EmulationFlags::HasFourScore);
ExpansionPortDevice expansionDevice = EmulationSettings::GetExpansionDevice();
shared_ptr<BaseControlDevice> arkanoidController;
if(EmulationSettings::GetConsoleType() != ConsoleType::Famicom) {
expansionDevice = ExpansionPortDevice::None;
} else if(expansionDevice != ExpansionPortDevice::FourPlayerAdapter) {
fourScore = false;
if(expansionDevice == ExpansionPortDevice::ArkanoidController) {
arkanoidController.reset(new ArkanoidController(2));
}
}
for(int i = 0; i < 2; i++) {
shared_ptr<BaseControlDevice> device;
if(fourScore || expansionDevice == ExpansionPortDevice::ArkanoidController || i == 1 && expansionDevice == ExpansionPortDevice::Zapper) {
if(fourScore || EmulationSettings::GetConsoleType() == ConsoleType::Famicom) {
//Need to set standard controller in all slots if four score (to allow emulation to work correctly)
device.reset(new StandardController(i));
} else {
@ -152,10 +149,13 @@ void ControlManager::UpdateControlDevices()
if(fourScore) {
std::dynamic_pointer_cast<StandardController>(device)->AddAdditionalController(shared_ptr<StandardController>(new StandardController(i + 2)));
} else if(i == 1 && expansionDevice == ExpansionPortDevice::Zapper) {
std::dynamic_pointer_cast<StandardController>(device)->AddAdditionalController(shared_ptr<Zapper>(new Zapper(2)));
} else if(expansionDevice == ExpansionPortDevice::ArkanoidController) {
std::dynamic_pointer_cast<StandardController>(device)->AddAdditionalController(arkanoidController);
} else if(i == 1 || expansionDevice == ExpansionPortDevice::ArkanoidController) {
switch(expansionDevice) {
case ExpansionPortDevice::Zapper: std::dynamic_pointer_cast<StandardController>(device)->AddAdditionalController(shared_ptr<Zapper>(new Zapper(2))); break;
case ExpansionPortDevice::ArkanoidController: std::dynamic_pointer_cast<StandardController>(device)->AddAdditionalController(shared_ptr<ArkanoidController>(new ArkanoidController(2))); break;
case ExpansionPortDevice::OekaKidsTablet: std::dynamic_pointer_cast<StandardController>(device)->AddAdditionalController(shared_ptr<OekaKidsTablet>(new OekaKidsTablet(2))); break;
default: break;
}
}
} else {
@ -199,15 +199,33 @@ uint8_t ControlManager::ReadRAM(uint16_t addr)
return 0;
}
template<typename T>
shared_ptr<T> ControlManager::GetExpansionDevice()
{
shared_ptr<StandardController> controller;
controller = std::dynamic_pointer_cast<StandardController>(GetControlDevice(1));
if(controller) {
shared_ptr<T> expansionDevice;
expansionDevice = std::dynamic_pointer_cast<T>(controller->GetAdditionalController());
return expansionDevice;
}
return nullptr;
}
void ControlManager::WriteRAM(uint16_t addr, uint8_t value)
{
//$4016 writes
bool previousState = _refreshState;
_refreshState = (value & 0x01) == 0x01;
if(previousState && !_refreshState) {
//Refresh controller once strobe bit is disabled
RefreshAllPorts();
auto tablet = GetExpansionDevice<OekaKidsTablet>();
if(tablet) {
tablet->WriteRam(value);
} else {
if(previousState && !_refreshState) {
//Refresh controller once strobe bit is disabled
RefreshAllPorts();
}
}
}

View file

@ -29,6 +29,8 @@ class ControlManager : public Snapshotable, public IMemoryHandler
bool _isLagging = false;
bool _refreshState = false;
template<typename T> shared_ptr<T> GetExpansionDevice();
virtual shared_ptr<BaseControlDevice> GetZapper(uint8_t port);
static void RegisterControlDevice(shared_ptr<BaseControlDevice> controlDevice, uint8_t port);

View file

@ -505,6 +505,7 @@
<ClInclude Include="NsfMapper.h" />
<ClInclude Include="NsfPpu.h" />
<ClInclude Include="OekaKids.h" />
<ClInclude Include="OekaKidsTablet.h" />
<ClInclude Include="PlayerListMessage.h" />
<ClInclude Include="Racermate.h" />
<ClInclude Include="ReverbFilter.h" />
@ -681,6 +682,7 @@
<ClCompile Include="iNesLoader.cpp" />
<ClCompile Include="NsfMapper.cpp" />
<ClCompile Include="NtscFilter.cpp" />
<ClCompile Include="OekaKidsTablet.cpp" />
<ClCompile Include="ReverbFilter.cpp" />
<ClCompile Include="RomLoader.cpp" />
<ClCompile Include="Snapshotable.cpp" />

View file

@ -838,6 +838,9 @@
<ClInclude Include="Racermate.h">
<Filter>Nes\Mappers</Filter>
</ClInclude>
<ClInclude Include="OekaKidsTablet.h">
<Filter>Nes\Controllers</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="stdafx.cpp">
@ -1005,5 +1008,8 @@
<ClCompile Include="VideoHud.cpp">
<Filter>VideoDecoder</Filter>
</ClCompile>
<ClCompile Include="OekaKidsTablet.cpp">
<Filter>Nes\Controllers</Filter>
</ClCompile>
</ItemGroup>
</Project>

View file

@ -161,6 +161,7 @@ enum class ExpansionPortDevice
Zapper = 1,
FourPlayerAdapter = 2,
ArkanoidController = 3,
OekaKidsTablet = 4,
};
struct KeyMapping

View file

@ -113,6 +113,10 @@ void GameDatabase::InitializeInputDevices(string inputType, GameSystem system)
} else {
controllers[1] = ControllerType::ArkanoidController;
}
} else if(inputType.compare("OekaKidsTablet") == 0) {
MessageManager::Log("[DB] Input: Oeka Kids Tablet connected");
system = GameSystem::Famicom;
expDevice = ExpansionPortDevice::OekaKidsTablet;
} else {
MessageManager::Log("[DB] Input: 2 standard controllers connected");
}

84
Core/OekaKidsTablet.cpp Normal file
View file

@ -0,0 +1,84 @@
#include "stdafx.h"
#include "OekaKidsTablet.h"
#include "ControlManager.h"
#include "GameServerConnection.h"
void OekaKidsTablet::StreamState(bool saving)
{
BaseControlDevice::StreamState(saving);
Stream(_xPosition, _yPosition, _touch, _click);
}
uint32_t OekaKidsTablet::GetNetPlayState()
{
//Used by netplay
uint32_t state = _xPosition | (_yPosition << 8);
if(_touch) {
state |= 0x40000000;
}
if(_click) {
state |= 0x80000000;
}
return state;
}
uint8_t OekaKidsTablet::ProcessNetPlayState(uint32_t netplayState)
{
_xPosition = netplayState & 0xFF;
_yPosition = (netplayState >> 8) & 0xFF;
_touch = ((netplayState >> 30) & 0x01) == 0x01;
_click = ((netplayState >> 31) & 0x01) == 0x01;
return RefreshState();
}
uint8_t OekaKidsTablet::RefreshState()
{
if(_strobe) {
if(_shift) {
return (_stateBuffer & 0x40000) ? 0x00 : 0x08;
} else {
return 0x04;
}
} else {
return 0x00;
}
}
uint8_t OekaKidsTablet::GetPortOutput()
{
return GetControlState();
}
void OekaKidsTablet::WriteRam(uint8_t value)
{
_strobe = (value & 0x01) == 0x01;
bool shift = ((value >> 1) & 0x01) == 0x01;
if(_strobe) {
if(!_shift && shift) {
_stateBuffer <<= 1;
}
_shift = shift;
} else {
if(!GameServerConnection::GetNetPlayDevice(_port)) {
MousePosition position = ControlManager::GetMousePosition();
_xPosition = (int32_t)((double)std::max(0, position.X + 8) / 256.0 * 240);
_yPosition = (int32_t)((double)std::max(0, position.Y - 14) / 240.0 * 256);
if(!EmulationSettings::CheckFlag(EmulationFlags::InBackground) || EmulationSettings::CheckFlag(EmulationFlags::AllowBackgroundInput)) {
_touch = position.Y >= 48 || ControlManager::IsMouseButtonPressed(MouseButton::LeftButton);
_click = ControlManager::IsMouseButtonPressed(MouseButton::LeftButton);
} else {
_touch = false;
_click = false;
}
}
_stateBuffer = ((_xPosition & 0xFF) << 10) | ((_yPosition & 0xFF) << 2) | (_touch ? 0x02 : 0x00) | (_click ? 0x01 : 0x00);
}
}

29
Core/OekaKidsTablet.h Normal file
View file

@ -0,0 +1,29 @@
#pragma once
#include "stdafx.h"
#include "BaseControlDevice.h"
class OekaKidsTablet : public BaseControlDevice
{
private:
bool _strobe = false;
bool _shift = false;
uint32_t _stateBuffer = 0;
bool _click = false;
bool _touch = false;
int32_t _xPosition = 0;
int32_t _yPosition = 0;
protected:
virtual uint8_t RefreshState();
uint8_t ProcessNetPlayState(uint32_t netplayState);
void StreamState(bool saving);
public:
using BaseControlDevice::BaseControlDevice;
virtual uint8_t GetPortOutput();
virtual uint32_t GetNetPlayState();
void WriteRam(uint8_t value);
};

View file

@ -4,6 +4,7 @@
#include "PPU.h"
#include "EmulationSettings.h"
#include "ArkanoidController.h"
#include "OekaKidsTablet.h"
void StandardController::StreamState(bool saving)
{
@ -65,9 +66,9 @@ uint8_t StandardController::GetPortOutput()
_stateBuffer >>= 1;
if(_famiconDevice && _additionalController) {
if(_hasZapper) {
if(std::dynamic_pointer_cast<Zapper>(_additionalController) || std::dynamic_pointer_cast<OekaKidsTablet>(_additionalController)) {
returnValue |= _additionalController->GetPortOutput();
} else if(_hasArkanoidController) {
} else if(std::dynamic_pointer_cast<ArkanoidController>(_additionalController)) {
returnValue |= std::dynamic_pointer_cast<ArkanoidController>(_additionalController)->GetExpansionPortOutput(_port);
} else {
returnValue |= (_stateBufferFamicom & 0x01) << 1;
@ -86,11 +87,11 @@ void StandardController::RefreshStateBuffer()
{
_stateBuffer = GetControlState();
_lastButtonState = _stateBuffer;
if(_additionalController && !_hasZapper) {
if(_additionalController && !std::dynamic_pointer_cast<Zapper>(_additionalController)) {
//Next 8 bits = Gamepad 3/4
if(_famiconDevice) {
//Four player adapter (Famicom)
if(_hasArkanoidController) {
if(std::dynamic_pointer_cast<ArkanoidController>(_additionalController) || std::dynamic_pointer_cast<OekaKidsTablet>(_additionalController)) {
_additionalController->RefreshStateBuffer();
} else {
_stateBufferFamicom = _additionalController->GetControlState();
@ -118,14 +119,6 @@ uint8_t StandardController::RefreshState()
void StandardController::AddAdditionalController(shared_ptr<BaseControlDevice> controller)
{
_hasZapper = false;
_hasArkanoidController = false;
if(std::dynamic_pointer_cast<Zapper>(controller)) {
_hasZapper = true;
} else if(std::dynamic_pointer_cast<ArkanoidController>(controller)) {
_hasArkanoidController = true;
}
_additionalController = controller;
}

View file

@ -10,8 +10,6 @@ private:
uint32_t _stateBufferFamicom = 0;
uint8_t _lastButtonState = 0;
bool _hasZapper = false;
bool _hasArkanoidController = false;
shared_ptr<BaseControlDevice> _additionalController;
uint8_t GetButtonState();

View file

@ -5,7 +5,7 @@
class VsZapper : public Zapper
{
private:
uint32_t _stateBuffer;
uint32_t _stateBuffer = 0;
protected:
uint8_t RefreshState();

View file

@ -16,9 +16,9 @@ struct ZapperButtonState
class Zapper : public BaseControlDevice
{
private:
bool _pulled;
int32_t _xPosition;
int32_t _yPosition;
bool _pulled = false;
int32_t _xPosition = -1;
int32_t _yPosition = -1;
protected:
virtual uint8_t RefreshState();

View file

@ -20,6 +20,11 @@ namespace Mesen.GUI.Controls
InitializeComponent();
}
private bool NeedMouseIcon
{
get { return InteropEmu.GetExpansionDevice() == InteropEmu.ExpansionPortDevice.OekaKidsTablet || InteropEmu.HasZapper(); }
}
private void ShowMouse()
{
if(_cursorHidden) {
@ -38,7 +43,7 @@ namespace Mesen.GUI.Controls
protected override void OnDoubleClick(EventArgs e)
{
if(!InteropEmu.HasZapper() && !InteropEmu.HasArkanoidPaddle()) {
if(!this.NeedMouseIcon && !InteropEmu.HasArkanoidPaddle()) {
//Disable double clicking (used to switch to fullscreen mode) when using zapper/arkanoid controller
base.OnDoubleClick(e);
}
@ -48,13 +53,13 @@ namespace Mesen.GUI.Controls
{
if(!InteropEmu.IsRunning() || InteropEmu.IsPaused() || !InteropEmu.HasArkanoidPaddle()) {
ShowMouse();
} else if(InteropEmu.HasArkanoidPaddle() && !InteropEmu.HasZapper()) {
} else if(InteropEmu.HasArkanoidPaddle() && !this.NeedMouseIcon) {
HideMouse();
}
tmrMouse.Stop();
if(InteropEmu.HasZapper()) {
if(this.NeedMouseIcon) {
this.Cursor = Cursors.Cross;
} else {
this.Cursor = Cursors.Default;

View file

@ -89,6 +89,7 @@
<Value ID="Zapper">Zapper</Value>
<Value ID="FourPlayerAdapter">Four Player Adapter</Value>
<Value ID="ArkanoidController">Arkanoid Controller</Value>
<Value ID="OekaKidsTablet">Oeka Kids Tablet</Value>
</Enum>
<Enum ID="PpuModel">
<Value ID="Ppu2C03">RP2C03</Value>

View file

@ -460,6 +460,7 @@
<Value ID="Zapper">Zapper</Value>
<Value ID="FourPlayerAdapter">Adaptador para 4 jugadores</Value>
<Value ID="ArkanoidController">Control Arkanoid</Value>
<Value ID="OekaKidsTablet">Oeka Kids Tablet</Value>
</Enum>
<Enum ID="PpuModel">
<Value ID="Ppu2C03">RP2C03</Value>

View file

@ -460,6 +460,7 @@
<Value ID="Zapper">Zapper</Value>
<Value ID="FourPlayerAdapter">Adapteur pour 4 joueurs</Value>
<Value ID="ArkanoidController">Manette Arkanoid</Value>
<Value ID="OekaKidsTablet">Tablette Oeka Kids</Value>
</Enum>
<Enum ID="PpuModel">
<Value ID="Ppu2C03">RP2C03</Value>

View file

@ -452,6 +452,7 @@
<Value ID="Zapper">ガン</Value>
<Value ID="FourPlayerAdapter">4-Player Adapter</Value>
<Value ID="ArkanoidController">Arkanoidコントローラ</Value>
<Value ID="OekaKidsTablet">おえかきっずタブレット</Value>
</Enum>
<Enum ID="PpuModel">
<Value ID="Ppu2C03">RP2C03</Value>

View file

@ -460,6 +460,7 @@
<Value ID="Zapper">Zapper</Value>
<Value ID="FourPlayerAdapter">Адаптер на 4 игрока</Value>
<Value ID="ArkanoidController">Arkanoid</Value>
<Value ID="OekaKidsTablet">Oeka Kids Tablet</Value>
</Enum>
<Enum ID="PpuModel">
<Value ID="Ppu2C03">RP2C03</Value>

View file

@ -390,6 +390,7 @@ namespace Mesen.GUI
Zapper = 1,
FourPlayerAdapter = 2,
ArkanoidController = 3,
OekaKidsTablet = 4,
}
public enum VsInputType