Oeka Kids Tablet support
This commit is contained in:
parent
e08db1cd04
commit
5f59dc1a7f
20 changed files with 185 additions and 37 deletions
|
@ -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();
|
||||
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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" />
|
||||
|
|
|
@ -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>
|
|
@ -161,6 +161,7 @@ enum class ExpansionPortDevice
|
|||
Zapper = 1,
|
||||
FourPlayerAdapter = 2,
|
||||
ArkanoidController = 3,
|
||||
OekaKidsTablet = 4,
|
||||
};
|
||||
|
||||
struct KeyMapping
|
||||
|
|
|
@ -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
84
Core/OekaKidsTablet.cpp
Normal 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
29
Core/OekaKidsTablet.h
Normal 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);
|
||||
};
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
class VsZapper : public Zapper
|
||||
{
|
||||
private:
|
||||
uint32_t _stateBuffer;
|
||||
uint32_t _stateBuffer = 0;
|
||||
|
||||
protected:
|
||||
uint8_t RefreshState();
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -390,6 +390,7 @@ namespace Mesen.GUI
|
|||
Zapper = 1,
|
||||
FourPlayerAdapter = 2,
|
||||
ArkanoidController = 3,
|
||||
OekaKidsTablet = 4,
|
||||
}
|
||||
|
||||
public enum VsInputType
|
||||
|
|
Loading…
Add table
Reference in a new issue