Skip to content
Permalink
Browse files

Added second controller and configurable keybindings.

  • Loading branch information...
amhndu committed Dec 7, 2016
1 parent 654faaf commit 6ece071e6217f0f8eae6fa926b45372af57612d1
Showing with 227 additions and 32 deletions.
  1. +4 −3 include/Controller.h
  2. +2 −1 include/Emulator.h
  3. +1 −1 include/MainBus.h
  4. +14 −15 main.cpp
  5. +15 −9 src/Controller.cpp
  6. +8 −2 src/Emulator.cpp
  7. +182 −0 src/KeybindingsParser.cpp
  8. +1 −1 src/MainBus.cpp
@@ -1,9 +1,8 @@
#ifndef CONTROLLER_H
#define CONTROLLER_H
#include <SFML/Window.hpp>
#include <list>
#include <map>
#include <cstdint>
#include <vector>

namespace sn
{
@@ -27,11 +26,13 @@ namespace sn

void strobe(Byte b);
Byte read();
void setKeyBindings(const std::vector<sf::Keyboard::Key>& keys);
private:
bool m_strobe;
unsigned int m_keyStates;

sf::Keyboard::Key m_keyBindings[TotalButtons];
std::vector<sf::Keyboard::Key> m_keyBindings;
// sf::Keyboard::Key m_keyBindings[TotalButtons];
};
}

@@ -24,6 +24,7 @@ namespace sn
void setVideoWidth(int width);
void setVideoHeight(int height);
void setVideoScale(float scale);
void setKeys(std::vector<sf::Keyboard::Key>& p1, std::vector<sf::Keyboard::Key>& p2);
private:
void DMA(Byte page);

@@ -34,7 +35,7 @@ namespace sn
Cartridge m_cartridge;
std::unique_ptr<Mapper> m_mapper;

Controller m_controller1;
Controller m_controller1, m_controller2;

sf::RenderWindow m_window;
VirtualScreen m_emulatorScreen;
@@ -21,7 +21,7 @@ namespace sn
PPUDATA,
OAMDMA = 0x4014,
JOY1 = 0x4016,
JOY2,
JOY2 = 0x4017,
};

class MainBus
@@ -3,21 +3,12 @@
#include <string>
#include <sstream>

// #include <ctime>
// #include <sstream>
// #include <iomanip>
// #include <cstring>
// #include <chrono>

/*std::string return_current_time_and_date() //courtesy of SO
namespace sn
{
auto now = std::chrono::system_clock::now();
auto in_time_t = std::chrono::system_clock::to_time_t(now);
std::stringstream ss;
ss << std::put_time(std::localtime(&in_time_t), "%Y-%m-%d.%X");
return ss.str();
}*/
void parseControllerConf(std::string filepath,
std::vector<sf::Keyboard::Key>& p1,
std::vector<sf::Keyboard::Key>& p2);
}

int main(int argc, char** argv)
{
@@ -33,6 +24,11 @@ int main(int argc, char** argv)

std::string path;

//Default keybindings
std::vector<sf::Keyboard::Key> p1 {sf::Keyboard::J, sf::Keyboard::K, sf::Keyboard::RShift, sf::Keyboard::Return,
sf::Keyboard::W, sf::Keyboard::S, sf::Keyboard::A, sf::Keyboard::D},
p2 {sf::Keyboard::Numpad5, sf::Keyboard::Numpad6, sf::Keyboard::Numpad8, sf::Keyboard::Numpad9,
sf::Keyboard::Up, sf::Keyboard::Down, sf::Keyboard::Left, sf::Keyboard::Right};
sn::Emulator emulator;

for (int i = 1; i < argc; ++i)
@@ -41,7 +37,8 @@ int main(int argc, char** argv)
if (arg == "-h" || arg == "--help")
{
std::cout << "SimpleNES is a simple NES emulator.\n"
<< "It can run off .nes images.\n\n"
<< "It can run off .nes images.\n"
<< "Set keybindings with keybindings.conf\n\n"
<< "Usage: SimpleNES [options] rom-path\n\n"
<< "Options:\n"
<< "-h, --help Print this help text and exit\n"
@@ -104,6 +101,8 @@ int main(int argc, char** argv)
return 1;
}

sn::parseControllerConf("keybindings.conf", p1, p2);
emulator.setKeys(p1, p2);
emulator.run(path);
return 0;
}
@@ -3,16 +3,22 @@
namespace sn
{
Controller::Controller() :
m_keyStates(0)
m_keyStates(0),
m_keyBindings(TotalButtons)
{
m_keyBindings[A] = sf::Keyboard::J;
m_keyBindings[B] = sf::Keyboard::K;
m_keyBindings[Select] = sf::Keyboard::RShift;
m_keyBindings[Start] = sf::Keyboard::Return;
m_keyBindings[Up] = sf::Keyboard::W;
m_keyBindings[Down] = sf::Keyboard::S;
m_keyBindings[Left] = sf::Keyboard::A;
m_keyBindings[Right] = sf::Keyboard::D;
// m_keyBindings[A] = sf::Keyboard::J;
// m_keyBindings[B] = sf::Keyboard::K;
// m_keyBindings[Select] = sf::Keyboard::RShift;
// m_keyBindings[Start] = sf::Keyboard::Return;
// m_keyBindings[Up] = sf::Keyboard::W;
// m_keyBindings[Down] = sf::Keyboard::S;
// m_keyBindings[Left] = sf::Keyboard::A;
// m_keyBindings[Right] = sf::Keyboard::D;
}

void Controller::setKeyBindings(const std::vector<sf::Keyboard::Key>& keys)
{
m_keyBindings = keys;
}

void Controller::strobe(Byte b)
@@ -16,7 +16,7 @@ namespace sn
if(!m_bus.setReadCallback(PPUSTATUS, [&](void) {return m_ppu.getStatus();}) ||
!m_bus.setReadCallback(PPUDATA, [&](void) {return m_ppu.getData();}) ||
!m_bus.setReadCallback(JOY1, [&](void) {return m_controller1.read();}) ||
!m_bus.setReadCallback(JOY2, [&](void) {return 0x2;}) ||
!m_bus.setReadCallback(JOY2, [&](void) {return m_controller2.read();}) ||
!m_bus.setReadCallback(OAMDATA, [&](void) {return m_ppu.getOAMData();}))
{
LOG(Error) << "Critical error: Failed to set I/O callbacks" << std::endl;
@@ -30,7 +30,7 @@ namespace sn
!m_bus.setWriteCallback(PPUSCROL, [&](Byte b) {m_ppu.setScroll(b);}) ||
!m_bus.setWriteCallback(PPUDATA, [&](Byte b) {m_ppu.setData(b);}) ||
!m_bus.setWriteCallback(OAMDMA, [&](Byte b) {DMA(b);}) ||
!m_bus.setWriteCallback(JOY1, [&](Byte b) {m_controller1.strobe(b);}) ||
!m_bus.setWriteCallback(JOY1, [&](Byte b) {m_controller1.strobe(b); m_controller2.strobe(b);}) ||
!m_bus.setWriteCallback(OAMDATA, [&](Byte b) {m_ppu.setOAMData(b);}))
{
LOG(Error) << "Critical error: Failed to set I/O callbacks" << std::endl;
@@ -174,4 +174,10 @@ namespace sn
<< int(NESVideoWidth * m_screenScale) << "x" << int(NESVideoHeight * m_screenScale) << std::endl;
}

void Emulator::setKeys(std::vector<sf::Keyboard::Key>& p1, std::vector<sf::Keyboard::Key>& p2)
{
m_controller1.setKeyBindings(p1);
m_controller2.setKeyBindings(p2);
}

}
@@ -0,0 +1,182 @@
#include <string>
#include <vector>
#include <fstream>
#include <algorithm>

#include "Controller.h"
#include "Log.h"

namespace sn
{
// trim from start (construct new string)
inline std::string ltrim(const std::string &str)
{
std::string s(str);
s.erase(s.begin(), std::find_if(s.begin(), s.end(),
std::not1(std::ptr_fun<int, int>(std::isspace))));
return s;
}

// trim from end (construct new string)
inline std::string rtrim(const std::string &str)
{
std::string s(str);
s.erase(std::find_if(s.rbegin(), s.rend(),
std::not1(std::ptr_fun<int, int>(std::isspace))).base(), s.end());
return s;
}

void parseControllerConf(std::string filepath,
std::vector<sf::Keyboard::Key>& p1,
std::vector<sf::Keyboard::Key>& p2)
{
const std::string buttonStrings[] = { "A",
"B",
"Select",
"Start",
"Up",
"Down",
"Left",
"Right" };
const std::string keys[] = {"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",
"Escape",
"LControl",
"LShift",
"LAlt",
"LSystem",
"RControl",
"RShift",
"RAlt",
"RSystem",
"Menu",
"LBracket",
"RBracket",
"SemiColon",
"Comma",
"Period",
"Quote",
"Slash",
"BackSlash",
"Tilde",
"Equal",
"Dash",
"Space",
"Return",
"BackSpace",
"Tab",
"PageUp",
"PageDown",
"End",
"Home",
"Insert",
"Delete",
"Add",
"Subtract",
"Multiply",
"Divide",
"Left",
"Right",
"Up",
"Down",
"Numpad0",
"Numpad1",
"Numpad2",
"Numpad3",
"Numpad4",
"Numpad5",
"Numpad6",
"Numpad7",
"Numpad8",
"Numpad9",
"F1",
"F2",
"F3",
"F4",
"F5",
"F6",
"F7",
"F8",
"F9",
"F10",
"F11",
"F12",
"F13",
"F14",
"F15",
"Pause"
};

std::ifstream file(filepath);
std::string line;
enum { Player1, Player2, None } state;
unsigned int line_no = 0;
while (std::getline(file, line))
{
line = rtrim(ltrim(line));
if (line[0] == '#' || line.empty())
continue;
else if (line == "[Player1]")
{
state = Player1;
}
else if (line == "[Player2]")
{
state = Player2;
}
else if (state == Player1 || state == Player2)
{
auto divider = line.find("=");
auto it = std::find(std::begin(buttonStrings), std::end(buttonStrings), ltrim(rtrim(line.substr(0, divider)))),
it2 = std::find(std::begin(keys), std::end(keys), ltrim(rtrim(line.substr(divider + 1))));
if (it == std::end(buttonStrings) || it2 == std::end(keys))
{
LOG(Error) << "Invalid key in configuration file at Line " << line_no << std::endl;
continue;
}
auto i = std::distance(std::begin(buttonStrings), it);
auto key = std::distance(std::begin(keys), it2);
(state == Player1 ? p1 : p2)[i] = static_cast<sf::Keyboard::Key>(key);
}
else
LOG(Error) << "Invalid line in key configuration at Line " << line_no << std::endl;

++line_no;
}

}
}
@@ -26,7 +26,7 @@ namespace sn
else
LOG(InfoVerbose) << "No read callback registered for I/O register at: " << std::hex << +addr << std::endl;
}
else if (addr < 0x4017 && addr >= 0x4014) //Only *some* IO registers
else if (addr < 0x4018 && addr >= 0x4014) //Only *some* IO registers
{
auto it = m_readCallbacks.find(static_cast<IORegisters>(addr));
if (it != m_readCallbacks.end())

0 comments on commit 6ece071

Please sign in to comment.
You can’t perform that action at this time.