Update to v082r15 release.

byuu says:

7.5 hours of power coding. Das Keyboard definitely helped (but didn't
eliminate) RSI, neato.

Okay, the NES resampler was using 315 / 88.8 by mistake, so the output
rate was wrong, causing way more video/audio stuttering than necessary.
STILL forgot the NES APU frame IRQ clear thing on $4015 reads, blah. Why
do I always remember things right after uploading the WIPs?
Recreated the input manager with a new design, works much nicer than the
old one, a whole lot less duplicated code.
Recreated the input settings window to work with the new multi-system
emulation.
All input settings are saved to their own configuration file, input.cfg.
Going to batch folder for now.

Okay, so the new input settings window ... basically there are now three
drop-downs, and I'm not even trying to label them anymore.
They are primary, secondary, tertiary selectors for the listed group
below. Examples:
"NES -> Controller Port 1 -> Gamepad"
"SNES -> Controller Port 2 -> Super Scope"
"User Interface -> Hotkeys -> Save States"

I am aware that "Clear" gets disabled when assigning. I will work on
that later, being lazy for now and disabling the entire window. Have to
add the mouse binders back, too.
Escape and modifiers are both mappable as individual keys now. If you
want to clear, click the damn clear button :P

Oh, and all input goes to all windows for now. That'll be fixed too when
input focus stuff is re-added.
This commit is contained in:
Tim Allen 2011-09-17 16:42:17 +10:00
parent 7619805266
commit 382ae1e61e
43 changed files with 878 additions and 119 deletions

View File

@ -4,27 +4,56 @@ namespace GameBoy {
Cheat cheat;
bool Cheat::decode(const string &code, unsigned &addr, unsigned &data, unsigned &comp) {
bool Cheat::decode(const string &code_, unsigned &addr, unsigned &data, unsigned &comp) {
static bool initialize = false;
static uint8 asciiMap[256];
static uint8 mapProActionReplay[256], mapGameGenie[256];
if(initialize == false) {
initialize = true;
foreach(n, asciiMap) n = ~0;
asciiMap['0'] = 0; asciiMap['1'] = 1; asciiMap['2'] = 2; asciiMap['3'] = 3;
asciiMap['4'] = 4; asciiMap['5'] = 5; asciiMap['6'] = 6; asciiMap['7'] = 7;
asciiMap['8'] = 8; asciiMap['9'] = 9; asciiMap['A'] = 10; asciiMap['B'] = 11;
asciiMap['C'] = 12; asciiMap['D'] = 13; asciiMap['E'] = 14; asciiMap['F'] = 15;
foreach(n, mapProActionReplay) n = ~0;
mapProActionReplay['0'] = 0; mapProActionReplay['1'] = 1; mapProActionReplay['2'] = 2; mapProActionReplay['3'] = 3;
mapProActionReplay['4'] = 4; mapProActionReplay['5'] = 5; mapProActionReplay['6'] = 6; mapProActionReplay['7'] = 7;
mapProActionReplay['8'] = 8; mapProActionReplay['9'] = 9; mapProActionReplay['A'] = 10; mapProActionReplay['B'] = 11;
mapProActionReplay['C'] = 12; mapProActionReplay['D'] = 13; mapProActionReplay['E'] = 14; mapProActionReplay['F'] = 15;
foreach(n, mapGameGenie) n = ~0;
mapGameGenie['0'] = 0; mapGameGenie['1'] = 1; mapGameGenie['2'] = 2; mapGameGenie['3'] = 3;
mapGameGenie['4'] = 4; mapGameGenie['5'] = 5; mapGameGenie['6'] = 6; mapGameGenie['7'] = 7;
mapGameGenie['8'] = 8; mapGameGenie['9'] = 9; mapGameGenie['A'] = 10; mapGameGenie['B'] = 11;
mapGameGenie['C'] = 12; mapGameGenie['D'] = 13; mapGameGenie['E'] = 14; mapGameGenie['F'] = 15;
}
string code = code_;
code.upper();
unsigned length = code.length(), bits = 0;
for(unsigned n = 0; n < length; n++) if(asciiMap[code[n]] > 15 && code[n] != '-') return false;
if(code.wildcard("????:??")) {
code = { substr(code, 0, 4), substr(code, 5, 2) };
for(unsigned n = 0; n < 6; n++) if(mapProActionReplay[code[n]] > 15) return false;
bits = hex(code);
addr = (bits >> 8) & 0xffff;
data = (bits >> 0) & 0xff;
comp = ~0;
return true;
}
if(code.wildcard("????:??:??")) {
code = { substr(code, 0, 4), substr(code, 5, 2), substr(code, 8, 2) };
for(unsigned n = 0; n < 8; n++) if(mapProActionReplay[code[n]] > 15) return false;
bits = hex(code);
addr = (bits >> 16) & 0xffff;
data = (bits >> 8) & 0xff;
comp = (bits >> 0) & 0xff;
return true;
}
if(code.wildcard("???" "-" "???")) {
string text = string(code).replace("-", "");
for(unsigned n = 0; n < 6; n++) bits |= asciiMap[text[n]] << (20 - n * 4);
code = { substr(code, 0, 3), substr(code, 4, 3) };
for(unsigned n = 0; n < 6; n++) if(mapGameGenie[code[n]] > 15) return false;
for(unsigned n = 0; n < 6; n++) bits |= mapGameGenie[code[n]] << (20 - n * 4);
addr = (bits >> 0) & 0xffff;
addr = (bits >> 0) & 0xffff;
data = (bits >> 16) & 0xff;
comp = ~0;
@ -34,12 +63,13 @@ bool Cheat::decode(const string &code, unsigned &addr, unsigned &data, unsigned
}
if(code.wildcard("???" "-" "???" "-" "???")) {
string text = string(code).replace("-", "");
for(unsigned n = 0; n < 8; n++) bits |= asciiMap[text[n == 7 ? 8 : n]] << (28 - n * 4);
code = { substr(code, 0, 3), substr(code, 4, 3), substr(code, 8, 1), substr(code, 10, 1) };
for(unsigned n = 0; n < 8; n++) if(mapGameGenie[code[n]] > 15) return false;
for(unsigned n = 0; n < 8; n++) bits |= mapGameGenie[code[n]] << (28 - n * 4);
addr = (bits >> 8) & 0xffff;
addr = (bits >> 8) & 0xffff;
data = (bits >> 24) & 0xff;
comp = (bits >> 0) & 0xff;
comp = (bits >> 0) & 0xff;
addr = (((addr >> 4) | (addr << 12)) & 0xffff) ^ 0xf000;
comp = (((comp >> 2) | (comp << 6)) & 0xff) ^ 0xba;

View File

@ -48,7 +48,8 @@ uint8 Bus::read(uint16 addr) {
for(unsigned n = 0; n < cheat.size(); n++) {
if(cheat[n].addr == addr) {
if(cheat[n].comp > 255 || cheat[n].comp == data) {
return cheat[n].data;
data = cheat[n].data;
break;
}
}
}

View File

@ -121,6 +121,8 @@
*path = 0;
struct passwd *userinfo = getpwuid(getuid());
if(userinfo) strcpy(path, userinfo->pw_dir);
unsigned length = strlen(path);
if(path[length] != '/') strcpy(path + length, "/");
return path;
}

View File

@ -4,24 +4,53 @@ namespace NES {
Cheat cheat;
bool Cheat::decode(const string &code, unsigned &addr, unsigned &data, unsigned &comp) {
bool Cheat::decode(const string &code_, unsigned &addr, unsigned &data, unsigned &comp) {
static bool initialize = false;
static uint8 asciiMap[256];
static uint8 mapProActionReplay[256], mapGameGenie[256];
if(initialize == false) {
initialize = true;
foreach(n, asciiMap) n = ~0;
asciiMap['A'] = 0; asciiMap['P'] = 1; asciiMap['Z'] = 2; asciiMap['L'] = 3;
asciiMap['G'] = 4; asciiMap['I'] = 5; asciiMap['T'] = 6; asciiMap['Y'] = 7;
asciiMap['E'] = 8; asciiMap['O'] = 9; asciiMap['X'] = 10; asciiMap['U'] = 11;
asciiMap['K'] = 12; asciiMap['S'] = 13; asciiMap['V'] = 14; asciiMap['N'] = 15;
foreach(n, mapProActionReplay) n = ~0;
mapProActionReplay['0'] = 0; mapProActionReplay['1'] = 1; mapProActionReplay['2'] = 2; mapProActionReplay['3'] = 3;
mapProActionReplay['4'] = 4; mapProActionReplay['5'] = 5; mapProActionReplay['6'] = 6; mapProActionReplay['7'] = 7;
mapProActionReplay['8'] = 8; mapProActionReplay['9'] = 9; mapProActionReplay['A'] = 10; mapProActionReplay['B'] = 11;
mapProActionReplay['C'] = 12; mapProActionReplay['D'] = 13; mapProActionReplay['E'] = 14; mapProActionReplay['F'] = 15;
foreach(n, mapGameGenie) n = ~0;
mapGameGenie['A'] = 0; mapGameGenie['P'] = 1; mapGameGenie['Z'] = 2; mapGameGenie['L'] = 3;
mapGameGenie['G'] = 4; mapGameGenie['I'] = 5; mapGameGenie['T'] = 6; mapGameGenie['Y'] = 7;
mapGameGenie['E'] = 8; mapGameGenie['O'] = 9; mapGameGenie['X'] = 10; mapGameGenie['U'] = 11;
mapGameGenie['K'] = 12; mapGameGenie['S'] = 13; mapGameGenie['V'] = 14; mapGameGenie['N'] = 15;
}
string code = code_;
code.upper();
unsigned length = code.length(), bits = 0;
for(unsigned n = 0; n < length; n++) if(asciiMap[code[n]] > 15) return false;
if(code.length() == 6) {
for(unsigned n = 0; n < 6; n++) bits |= asciiMap[code[n]] << (20 - n * 4);
if(code.wildcard("????:??")) {
code = { substr(code, 0, 4), substr(code, 5, 2) };
for(unsigned n = 0; n < 6; n++) if(mapProActionReplay[code[n]] > 15) return false;
bits = hex(code);
addr = (bits >> 8) & 0xffff;
data = (bits >> 0) & 0xff;
comp = ~0;
return true;
}
if(code.wildcard("????:??:??")) {
code = { substr(code, 0, 4), substr(code, 5, 2), substr(code, 8, 2) };
for(unsigned n = 0; n < 8; n++) if(mapProActionReplay[code[n]] > 15) return false;
bits = hex(code);
addr = (bits >> 16) & 0xffff;
data = (bits >> 8) & 0xff;
comp = (bits >> 0) & 0xff;
return true;
}
if(length == 6) {
for(unsigned n = 0; n < 6; n++) if(mapGameGenie[code[n]] > 15) return false;
for(unsigned n = 0; n < 6; n++) bits |= mapGameGenie[code[n]] << (20 - n * 4);
unsigned addrTable[] = { 10, 9, 8, 7, 2, 1, 0, 19, 14, 13, 12, 11, 6, 5, 4 };
unsigned dataTable[] = { 23, 18, 17, 16, 3, 22, 21, 20 };
@ -31,8 +60,9 @@ bool Cheat::decode(const string &code, unsigned &addr, unsigned &data, unsigned
return true;
}
if(code.length() == 8) {
for(unsigned n = 0; n < 8; n++) bits |= asciiMap[code[n]] << (28 - n * 4);
if(length == 8) {
for(unsigned n = 0; n < 8; n++) if(mapGameGenie[code[n]] > 15) return false;
for(unsigned n = 0; n < 8; n++) bits |= mapGameGenie[code[n]] << (28 - n * 4);
unsigned addrTable[] = { 18, 17, 16, 15, 10, 9, 8, 27, 22, 21, 20, 19, 14, 13, 12 };
unsigned dataTable[] = { 31, 26, 25, 24, 3, 30, 29, 28 };
unsigned compTable[] = { 7, 2, 1, 0, 11, 6, 5,4 };

View File

@ -13,15 +13,16 @@ Bus bus;
uint8 Bus::read(uint16 addr) {
uint8 data = cartridge.prg_read(addr);
if(addr <= 0x1fff) return cpu.ram_read(addr);
if(addr <= 0x3fff) return ppu.read(addr);
if(addr <= 0x4017) return cpu.read(addr);
if(addr <= 0x1fff) data = cpu.ram_read(addr);
else if(addr <= 0x3fff) data = ppu.read(addr);
else if(addr <= 0x4017) data = cpu.read(addr);
if(cheat.override[addr]) {
for(unsigned n = 0; n < cheat.size(); n++) {
if(cheat[n].addr == addr) {
if(cheat[n].comp > 255 || cheat[n].comp == data) {
return cheat[n].data;
data = cheat[n].data;
break;
}
}
}

View File

@ -4,7 +4,7 @@
namespace NES {
namespace Info {
static const char Name[] = "bnes";
static const char Version[] = "000.10";
static const char Version[] = "000.11";
}
}

View File

@ -144,7 +144,7 @@ void Window::append(Layout &layout) {
((Sizable&)layout).state.window = this;
((Sizable&)layout).state.layout = 0;
p.append(layout);
layout.synchronize();
layout.synchronizeLayout();
}
}
@ -159,7 +159,7 @@ void Window::append(Widget &widget) {
if(state.widget.append(widget)) {
((Sizable&)widget).state.window = this;
p.append(widget);
synchronize();
synchronizeLayout();
}
}
@ -286,7 +286,7 @@ void Window::setWidgetFont(const string &font) {
return p.setWidgetFont(font);
}
void Window::synchronize() {
void Window::synchronizeLayout() {
setGeometry(geometry());
}
@ -509,7 +509,7 @@ void Layout::append(Sizable &sizable) {
if(dynamic_cast<Layout*>(&sizable)) {
Layout &layout = (Layout&)sizable;
layout.synchronize();
layout.synchronizeLayout();
}
if(dynamic_cast<Widget*>(&sizable)) {
@ -517,7 +517,7 @@ void Layout::append(Sizable &sizable) {
if(sizable.window()) sizable.window()->append(widget);
}
if(window()) window()->synchronize();
if(window()) window()->synchronizeLayout();
}
void Layout::remove(Sizable &sizable) {
@ -529,7 +529,7 @@ void Layout::remove(Sizable &sizable) {
sizable.state.layout = 0;
sizable.state.window = 0;
if(window()) window()->synchronize();
if(window()) window()->synchronizeLayout();
}
Layout::Layout():

View File

@ -152,7 +152,7 @@ struct Window : private nall::base_from_member<pWindow&>, Object {
void setTitle(const nall::string &text);
void setVisible(bool visible = true);
void setWidgetFont(const nall::string &font);
void synchronize();
void synchronizeLayout();
Window();
~Window();
@ -256,7 +256,7 @@ struct Layout : private nall::base_from_member<pLayout&>, Sizable {
virtual void append(Sizable &sizable);
virtual void remove(Sizable &sizable);
virtual void reset() {}
virtual void synchronize() = 0;
virtual void synchronizeLayout() = 0;
Layout();
Layout(pLayout &p);

View File

@ -1,6 +1,6 @@
void FixedLayout::append(Sizable &sizable, const Geometry &geometry) {
children.append({ &sizable, geometry });
synchronize();
synchronizeLayout();
}
void FixedLayout::append(Sizable &sizable) {
@ -55,7 +55,7 @@ void FixedLayout::setVisible(bool visible) {
}
}
void FixedLayout::synchronize() {
void FixedLayout::synchronizeLayout() {
foreach(child, children) {
Layout::append(*child.sizable);
child.sizable->setGeometry(child.geometry);

View File

@ -8,7 +8,7 @@ struct FixedLayout : Layout {
void setEnabled(bool enabled = true);
void setGeometry(const Geometry &geometry);
void setVisible(bool visible = true);
void synchronize();
void synchronizeLayout();
bool visible();
FixedLayout();
~FixedLayout();

View File

@ -1,13 +1,13 @@
void HorizontalLayout::append(Sizable &sizable, unsigned width, unsigned height, unsigned spacing) {
foreach(child, children) if(child.sizable == &sizable) return;
children.append({ &sizable, width, height, spacing });
synchronize();
synchronizeLayout();
}
void HorizontalLayout::append(Sizable &sizable) {
foreach(child, children) if(child.sizable == &sizable) return;
Layout::append(sizable);
if(window()) window()->synchronize();
if(window()) window()->synchronizeLayout();
}
bool HorizontalLayout::enabled() {
@ -114,7 +114,7 @@ void HorizontalLayout::setVisible(bool visible) {
}
}
void HorizontalLayout::synchronize() {
void HorizontalLayout::synchronizeLayout() {
foreach(child, children) Layout::append(*child.sizable);
}

View File

@ -10,7 +10,7 @@ struct HorizontalLayout : public Layout {
void setGeometry(const Geometry &geometry);
void setMargin(unsigned margin);
void setVisible(bool visible = true);
void synchronize();
void synchronizeLayout();
bool visible();
HorizontalLayout();
~HorizontalLayout();

View File

@ -1,13 +1,13 @@
void VerticalLayout::append(Sizable &sizable, unsigned width, unsigned height, unsigned spacing) {
foreach(child, children) if(child.sizable == &sizable) return;
children.append({ &sizable, width, height, spacing });
synchronize();
synchronizeLayout();
}
void VerticalLayout::append(Sizable &sizable) {
foreach(child, children) if(child.sizable == &sizable) return;
Layout::append(sizable);
if(window()) window()->synchronize();
if(window()) window()->synchronizeLayout();
}
bool VerticalLayout::enabled() {
@ -118,7 +118,7 @@ void VerticalLayout::setVisible(bool visible) {
}
}
void VerticalLayout::synchronize() {
void VerticalLayout::synchronizeLayout() {
foreach(child, children) Layout::append(*child.sizable);
}

View File

@ -10,7 +10,7 @@ struct VerticalLayout : public Layout {
void setGeometry(const Geometry &geometry);
void setMargin(unsigned margin);
void setVisible(bool visible = true);
void synchronize();
void synchronizeLayout();
bool visible();
VerticalLayout();
~VerticalLayout();

View File

@ -1,7 +1,7 @@
/****************************************************************************
** Meta object code from reading C++ file 'platform.moc.hpp'
**
** Created: Thu Sep 8 17:34:23 2011
** Created: Fri Sep 16 21:12:56 2011
** by: The Qt Meta Object Compiler version 62 (Qt 4.7.0)
**
** WARNING! All changes made in this file will be lost!

View File

@ -1,5 +1,7 @@
void pComboBox::append(const string &text) {
locked = true;
qtComboBox->addItem(QString::fromUtf8(text));
locked = false;
}
Geometry pComboBox::minimumGeometry() {
@ -10,7 +12,9 @@ Geometry pComboBox::minimumGeometry() {
}
void pComboBox::reset() {
locked = true;
while(qtComboBox->count()) qtComboBox->removeItem(0);
locked = false;
}
unsigned pComboBox::selection() {
@ -45,7 +49,6 @@ void pComboBox::orphan() {
}
void pComboBox::onChange() {
if(locked == true) return;
comboBox.state.selection = selection();
if(comboBox.onChange) comboBox.onChange();
if(locked == false && comboBox.onChange) comboBox.onChange();
}

View File

@ -71,19 +71,21 @@ bool Cheat::decode(const string &code, unsigned &addr, unsigned &data) {
#define ischr(n) ((n >= '0' && n <= '9') || (n >= 'a' && n <= 'f'))
if(strlen(t) == 8 || (strlen(t) == 9 && t[6] == ':')) {
if(t.wildcard("??????:??")) {
//Pro Action Replay
if(strlen(t) == 9 && t[6] == ':') t = { substr(t, 0, 6), substr(t, 7) }; //strip ':'
for(unsigned i = 0; i < 8; i++) if(!ischr(t[i])) return false; //validate input
t = { substr(t, 0, 6), substr(t, 7, 2) };
for(unsigned n = 0; n < 8; n++) if(!ischr(t[n])) return false; //validate input
unsigned r = hex(t);
addr = r >> 8;
data = r & 0xff;
return true;
} else if(strlen(t) == 9 && t[4] == '-') {
}
if(t.wildcard("????" "-" "????")) {
//Game Genie
t = { substr(t, 0, 4), substr(t, 5) }; //strip '-'
for(unsigned i = 0; i < 8; i++) if(!ischr(t[i])) return false; //validate input
t = { substr(t, 0, 4), substr(t, 5, 4) };
for(unsigned n = 0; n < 8; n++) if(!ischr(t[n])) return false; //validate input
t.transform("df4709156bc8a23e", "0123456789abcdef");
unsigned r = hex(t);
static unsigned bits[] = { 13, 12, 11, 10, 5, 4, 3, 2, 23, 22, 21, 20, 1, 0, 15, 14, 19, 18, 17, 16, 9, 8, 7, 6 };

View File

@ -4,7 +4,7 @@
namespace SNES {
namespace Info {
static const char Name[] = "bsnes";
static const char Version[] = "082.14";
static const char Version[] = "082.15";
static const unsigned SerializerVersion = 22;
}
}

View File

@ -3,7 +3,7 @@ include $(snes)/Makefile
include $(gameboy)/Makefile
name := batch
ui_objects := ui-main ui-config ui-interface ui-utility
ui_objects := ui-main ui-config ui-interface ui-input ui-utility
ui_objects += ui-general ui-settings ui-tools
ui_objects += phoenix ruby
ui_objects += $(if $(call streq,$(platform),win),resource)
@ -70,6 +70,7 @@ objects := $(patsubst %,obj/%.o,$(objects))
obj/ui-main.o: $(ui)/main.cpp $(call rwildcard,$(ui)/)
obj/ui-config.o: $(ui)/config/config.cpp $(call rwildcard,$(ui)/)
obj/ui-interface.o: $(ui)/interface/interface.cpp $(call rwildcard,$(ui)/)
obj/ui-input.o: $(ui)/input/input.cpp $(call rwildcard,$(ui)/)
obj/ui-utility.o: $(ui)/utility/utility.cpp $(call rwildcard,$(ui)/)
obj/ui-general.o: $(ui)/general/general.cpp $(call rwildcard,$(ui)/)
obj/ui-settings.o: $(ui)/settings/settings.cpp $(call rwildcard,$(ui)/)

View File

@ -21,6 +21,7 @@ using namespace ruby;
#include "config/config.hpp"
#include "interface/interface.hpp"
#include "input/input.hpp"
#include "utility/utility.hpp"
#include "general/general.hpp"
#include "settings/settings.hpp"
@ -35,6 +36,7 @@ struct Application {
string title;
string normalFont;
string boldFont;
string titleFont;
void run();
Application(int argc, char **argv);

View File

@ -19,6 +19,8 @@ MainWindow::MainWindow() {
snesPower.setText("Power Cycle");
snesReset.setText("Reset");
snesCartridgeUnload.setText("Unload Cartridge");
snesPort1.setText("Controller Port 1");
snesPort2.setText("Controller Port 2");
gameBoyMenu.setText("Game Boy");
gameBoyPower.setText("Power Cycle");
@ -26,7 +28,7 @@ MainWindow::MainWindow() {
settingsMenu.setText("Settings");
settingsSynchronizeVideo.setText("Synchronize Video");
settingsSynchronizeVideo.setChecked(false);
settingsSynchronizeVideo.setChecked();
settingsSynchronizeAudio.setText("Synchronize Audio");
settingsSynchronizeAudio.setChecked();
settingsMuteAudio.setText("Mute Audio");
@ -67,8 +69,11 @@ MainWindow::MainWindow() {
append(snesMenu);
snesMenu.append(snesPower);
snesMenu.append(snesReset);
snesMenu.append(snesSeparator);
snesMenu.append(snesSeparator1);
snesMenu.append(snesCartridgeUnload);
snesMenu.append(snesSeparator2);
snesMenu.append(snesPort1);
snesMenu.append(snesPort2);
append(gameBoyMenu);
gameBoyMenu.append(gameBoyPower);

View File

@ -16,8 +16,11 @@ struct MainWindow : Window {
Menu snesMenu;
Item snesPower;
Item snesReset;
Separator snesSeparator;
Separator snesSeparator1;
Item snesCartridgeUnload;
Separator snesSeparator2;
Menu snesPort1;
Menu snesPort2;
Menu gameBoyMenu;
Item gameBoyPower;

52
bsnes/ui/input/gameboy.cpp Executable file
View File

@ -0,0 +1,52 @@
int16_t GameBoyController::poll(unsigned n) {
switch(n) {
case 0: return up.poll() & !down.poll();
case 1: return down.poll() & !up.poll();
case 2: return left.poll() & !right.poll();
case 3: return right.poll() & !left.poll();
case 4: return b.poll();
case 5: return a.poll();
case 6: return select.poll();
case 7: return start.poll();
}
return 0;
}
GameBoyController::GameBoyController() {
name = "Controller";
up.name = "Up";
down.name = "Down";
left.name = "Left";
right.name = "Right";
b.name = "B";
a.name = "A";
select.name = "Select";
start.name = "Start";
up.mapping = "KB0::Up";
down.mapping = "KB0::Down";
left.mapping = "KB0::Left";
right.mapping = "KB0::Right";
b.mapping = "KB0::Z";
a.mapping = "KB0::X";
select.mapping = "KB0::Apostrophe";
start.mapping = "KB0::Return";
append(up); append(down); append(left); append(right);
append(b); append(a); append(select); append(start);
}
//
GameBoyDevice::GameBoyDevice() {
name = "Device";
append(controller);
}
//
GameBoyInput::GameBoyInput() {
name = "Game Boy";
append(device);
}

19
bsnes/ui/input/gameboy.hpp Executable file
View File

@ -0,0 +1,19 @@
struct GameBoyController : TertiaryInput {
DigitalInput up, down, left, right;
DigitalInput b, a, select, start;
int16_t poll(unsigned n);
GameBoyController();
};
struct GameBoyDevice : SecondaryInput {
GameBoyController controller;
GameBoyDevice();
};
struct GameBoyInput : PrimaryInput {
GameBoyDevice device;
GameBoyInput();
};

184
bsnes/ui/input/input.cpp Executable file
View File

@ -0,0 +1,184 @@
#include "../base.hpp"
#include "nes.cpp"
#include "snes.cpp"
#include "gameboy.cpp"
#include "user-interface.cpp"
InputManager *inputManager = 0;
void AbstractInput::attach(const string &primaryName, const string &secondaryName, const string &tertiaryName) {
string name = { primaryName, "::", secondaryName, "::", tertiaryName, "::", this->name };
name.replace(" ", "");
inputManager->config.attach(mapping, name);
}
void AbstractInput::bind() {
if(mapping.endswith(".Up")) type = Type::HatUp;
else if(mapping.endswith(".Down")) type = Type::HatDown;
else if(mapping.endswith(".Left")) type = Type::HatLeft;
else if(mapping.endswith(".Right")) type = Type::HatRight;
else if(mapping.endswith(".Lo")) type = Type::AxisLo;
else if(mapping.endswith(".Hi")) type = Type::AxisHi;
else if(mapping.beginswith("JP") && mapping.position("Axis")) type = Type::Axis;
else if(mapping.beginswith("MS") && mapping.endswith("axis")) type = Type::Axis;
else type = Type::Button;
string decode = mapping;
if(auto position = decode.position(".")) decode[position()] = 0;
scancode = Scancode::decode(decode);
}
int16_t AbstractInput::poll() {
return inputManager->scancode[inputManager->activeScancode][scancode];
}
//
bool AnalogInput::bind(int16_t scancode, int16_t value) {
string encode = Scancode::encode(scancode);
if(Mouse::isAnyAxis(scancode)) {
for(unsigned n = 0; n < Mouse::Count; n++) {
if(scancode == mouse(n)[Mouse::Xaxis]) { encode.append(".Xaxis"); goto bind; }
if(scancode == mouse(n)[Mouse::Yaxis]) { encode.append(".Yaxis"); goto bind; }
if(scancode == mouse(n)[Mouse::Zaxis]) { encode.append(".Zaxis"); goto bind; }
}
}
if(Joypad::isAnyAxis(scancode)) {
goto bind;
}
return false;
bind:
mapping = encode;
this->scancode = scancode;
this->type = Type::Axis;
}
//
bool DigitalInput::bind(int16_t scancode, int16_t value) {
string encode = Scancode::encode(scancode);
Type type;
if(Keyboard::isAnyKey(scancode) || Keyboard::isAnyModifier(scancode) || Joypad::isAnyButton(scancode)) {
if(value == 0) return false;
type = Type::Button;
goto bind;
}
if(Joypad::isAnyHat(scancode)) {
if(value & Joypad::HatUp ) { type = Type::HatUp; encode.append(".Up" ); goto bind; }
if(value & Joypad::HatDown ) { type = Type::HatDown; encode.append(".Down" ); goto bind; }
if(value & Joypad::HatLeft ) { type = Type::HatLeft; encode.append(".Left" ); goto bind; }
if(value & Joypad::HatRight) { type = Type::HatRight; encode.append(".Right"); goto bind; }
}
if(Joypad::isAnyAxis(scancode)) {
if(value < -12288) { type = Type::AxisLo; encode.append(".Lo"); goto bind; }
if(value > +24576) { type = Type::AxisHi; encode.append(".Hi"); goto bind; }
}
return false;
bind:
mapping = encode;
this->scancode = scancode;
this->type = type;
return true;
}
int16_t DigitalInput::poll() {
int16_t value = AbstractInput::poll();
switch(type) {
case Type::Button: return (bool)(value);
case Type::HatUp: return (bool)(value & Joypad::HatUp);
case Type::HatDown: return (bool)(value & Joypad::HatDown);
case Type::HatLeft: return (bool)(value & Joypad::HatLeft);
case Type::HatRight: return (bool)(value & Joypad::HatRight);
case Type::AxisLo: return (bool)(value < -16384);
case Type::AxisHi: return (bool)(value > +16384);
}
return 0;
}
//
void TertiaryInput::attach(const string &primaryName, const string &secondaryName) {
for(unsigned n = 0; n < size(); n++) {
operator[](n).attach(primaryName, secondaryName, name);
}
}
void TertiaryInput::bind() {
for(unsigned n = 0; n < size(); n++) {
operator[](n).bind();
}
}
int16_t TertiaryInput::poll(unsigned n) {
return operator[](n).poll();
}
//
void SecondaryInput::attach(const string &primaryName) {
for(unsigned n = 0; n < size(); n++) {
operator[](n).attach(primaryName, name);
}
}
void SecondaryInput::bind() {
for(unsigned n = 0; n < size(); n++) {
operator[](n).bind();
}
}
//
void PrimaryInput::attach() {
for(unsigned n = 0; n < size(); n++) {
operator[](n).attach(name);
}
}
void PrimaryInput::bind() {
for(unsigned n = 0; n < size(); n++) {
operator[](n).bind();
}
}
//
void InputManager::scan() {
activeScancode = !activeScancode;
input.poll(scancode[activeScancode]);
for(unsigned n = 0; n < Scancode::Limit; n++) {
if(scancode[!activeScancode][n] != scancode[activeScancode][n]) {
inputSettings->inputEvent(n, scancode[activeScancode][n]);
userInterface.inputEvent(n, scancode[activeScancode][n]);
}
}
}
InputManager::InputManager() {
inputManager = this;
inputList.append(nes);
inputList.append(snes);
inputList.append(gameBoy);
inputList.append(userInterface);
for(unsigned n = 0; n < inputList.size(); n++) inputList[n].attach();
config.load(string{ application->userpath, "input.cfg" });
config.save(string{ application->userpath, "input.cfg" });
for(unsigned n = 0; n < inputList.size(); n++) inputList[n].bind();
activeScancode = 0;
}
InputManager::~InputManager() {
config.save(string{ application->userpath, "input.cfg" });
}

65
bsnes/ui/input/input.hpp Executable file
View File

@ -0,0 +1,65 @@
struct AbstractInput {
enum class Type : unsigned { Button, Axis, HatUp, HatDown, HatLeft, HatRight, AxisLo, AxisHi } type;
string name;
string mapping;
unsigned scancode;
virtual void attach(const string &primaryName, const string &secondaryName, const string &tertiaryName);
virtual void bind();
virtual bool bind(int16_t scancode, int16_t value) = 0;
virtual int16_t poll();
};
struct AnalogInput : AbstractInput {
bool bind(int16_t scancode, int16_t value);
};
struct DigitalInput : AbstractInput {
bool bind(int16_t scancode, int16_t value);
int16_t poll();
};
struct TertiaryInput : reference_array<AbstractInput&> {
string name;
virtual void attach(const string &primaryName, const string &secondaryName);
virtual void bind();
virtual int16_t poll(unsigned n);
};
struct SecondaryInput : reference_array<TertiaryInput&> {
string name;
virtual void attach(const string &primaryName);
virtual void bind();
};
struct PrimaryInput : reference_array<SecondaryInput&> {
string name;
virtual void attach();
virtual void bind();
};
#include "nes.hpp"
#include "snes.hpp"
#include "gameboy.hpp"
#include "user-interface.hpp"
struct InputManager {
configuration config;
int16_t scancode[2][Scancode::Limit];
bool activeScancode;
reference_array<PrimaryInput&> inputList;
NesInput nes;
SnesInput snes;
GameBoyInput gameBoy;
UserInterfaceInput userInterface;
void scan();
InputManager();
~InputManager();
};
extern InputManager *inputManager;

60
bsnes/ui/input/nes.cpp Executable file
View File

@ -0,0 +1,60 @@
int16_t NesGamepad::poll(unsigned n) {
switch(n) {
case 0: return b.poll();
case 1: return a.poll();
case 2: return select.poll();
case 3: return start.poll();
case 4: return up.poll() & !down.poll();
case 5: return down.poll() & !up.poll();
case 6: return left.poll() & !right.poll();
case 7: return right.poll() & !left.poll();
}
return 0;
}
NesGamepad::NesGamepad() {
name = "Gamepad";
up.name = "Up";
down.name = "Down";
left.name = "Left";
right.name = "Right";
b.name = "B";
a.name = "A";
select.name = "Select";
start.name = "Start";
up.mapping = "KB0::Up";
down.mapping = "KB0::Down";
left.mapping = "KB0::Left";
right.mapping = "KB0::Right";
b.mapping = "KB0::Z";
a.mapping = "KB0::X";
select.mapping = "KB0::Apostrophe";
start.mapping = "KB0::Return";
append(up); append(down); append(left); append(right);
append(b); append(a); append(select); append(start);
}
//
NesPort1Input::NesPort1Input() {
name = "Controller Port 1";
append(gamepad);
}
//
NesPort2Input::NesPort2Input() {
name = "Controller Port 2";
append(gamepad);
}
//
NesInput::NesInput() {
name = "NES";
append(port1);
append(port2);
}

26
bsnes/ui/input/nes.hpp Executable file
View File

@ -0,0 +1,26 @@
struct NesGamepad : TertiaryInput {
DigitalInput up, down, left, right;
DigitalInput b, a, select, start;
int16_t poll(unsigned n);
NesGamepad();
};
struct NesPort1Input : SecondaryInput {
NesGamepad gamepad;
NesPort1Input();
};
struct NesPort2Input : SecondaryInput {
NesGamepad gamepad;
NesPort2Input();
};
struct NesInput : PrimaryInput {
NesPort1Input port1;
NesPort2Input port2;
NesInput();
};

73
bsnes/ui/input/snes.cpp Executable file
View File

@ -0,0 +1,73 @@
int16_t SnesGamepad::poll(unsigned n) {
switch((SNES::Input::JoypadID)n) {
case SNES::Input::JoypadID::Up: return up.poll() & !down.poll();
case SNES::Input::JoypadID::Down: return down.poll() & !up.poll();
case SNES::Input::JoypadID::Left: return left.poll() & !right.poll();
case SNES::Input::JoypadID::Right: return right.poll() & !left.poll();
case SNES::Input::JoypadID::B: return b.poll();
case SNES::Input::JoypadID::A: return a.poll();
case SNES::Input::JoypadID::Y: return y.poll();
case SNES::Input::JoypadID::X: return x.poll();
case SNES::Input::JoypadID::L: return l.poll();
case SNES::Input::JoypadID::R: return r.poll();
case SNES::Input::JoypadID::Select: return select.poll();
case SNES::Input::JoypadID::Start: return start.poll();
}
return 0;
}
SnesGamepad::SnesGamepad() {
name = "Gamepad";
up.name = "Up";
down.name = "Down";
left.name = "Left";
right.name = "Right";
b.name = "B";
a.name = "A";
y.name = "Y";
x.name = "X";
l.name = "L";
r.name = "R";
select.name = "Select";
start.name = "Start";
up.mapping = "KB0::Up";
down.mapping = "KB0::Down";
left.mapping = "KB0::Left";
right.mapping = "KB0::Right";
b.mapping = "KB0::Z";
a.mapping = "KB0::X";
y.mapping = "KB0::A";
x.mapping = "KB0::S";
l.mapping = "KB0::D";
r.mapping = "KB0::C";
select.mapping = "KB0::Apostrophe";
start.mapping = "KB0::Return";
append(up); append(down); append(left); append(right);
append(b); append(a); append(y); append(x);
append(l); append(r); append(select); append(start);
}
//
SnesPort1Input::SnesPort1Input() {
name = "Controller Port 1";
append(gamepad);
}
//
SnesPort2Input::SnesPort2Input() {
name = "Controller Port 2";
append(gamepad);
}
//
SnesInput::SnesInput() {
name = "SNES";
append(port1);
append(port2);
}

27
bsnes/ui/input/snes.hpp Executable file
View File

@ -0,0 +1,27 @@
struct SnesGamepad : TertiaryInput {
DigitalInput up, down, left, right;
DigitalInput b, a, y, x;
DigitalInput l, r, select, start;
int16_t poll(unsigned n);
SnesGamepad();
};
struct SnesPort1Input : SecondaryInput {
SnesGamepad gamepad;
SnesPort1Input();
};
struct SnesPort2Input : SecondaryInput {
SnesGamepad gamepad;
SnesPort2Input();
};
struct SnesInput : PrimaryInput {
SnesPort1Input port1;
SnesPort2Input port2;
SnesInput();
};

View File

@ -0,0 +1,53 @@
void HotkeyGeneral::inputEvent(int16_t scancode, int16_t value) {
if(scancode == toggleFullScreen.scancode && value) {
utility->toggleFullScreen();
}
if(scancode == turboMode.scancode) {
static bool Vsync, Async;
if(value) {
Vsync = any_cast<bool>(video.get(Video::Synchronize));
Async = any_cast<bool>(audio.get(Audio::Synchronize));
video.set(Video::Synchronize, false);
audio.set(Audio::Synchronize, false);
} else {
video.set(Video::Synchronize, Vsync);
audio.set(Audio::Synchronize, Async);
}
}
}
HotkeyGeneral::HotkeyGeneral() {
name = "General";
toggleFullScreen.name = "Toggle Fullscreen";
turboMode.name = "Turbo Mode";
toggleFullScreen.mapping = "KB0::F11";
turboMode.mapping = "KB0::Tilde";
append(toggleFullScreen);
append(turboMode);
}
//
void HotkeyInput::inputEvent(int16_t scancode, int16_t value) {
general.inputEvent(scancode, value);
}
HotkeyInput::HotkeyInput() {
name = "Hotkeys";
append(general);
}
//
void UserInterfaceInput::inputEvent(int16_t scancode, int16_t value) {
hotkey.inputEvent(scancode, value);
}
UserInterfaceInput::UserInterfaceInput() {
name = "User Interface";
append(hotkey);
}

View File

@ -0,0 +1,21 @@
struct HotkeyGeneral : TertiaryInput {
DigitalInput toggleFullScreen;
DigitalInput turboMode;
void inputEvent(int16_t scancode, int16_t value);
HotkeyGeneral();
};
struct HotkeyInput : SecondaryInput {
HotkeyGeneral general;
void inputEvent(int16_t scancode, int16_t value);
HotkeyInput();
};
struct UserInterfaceInput : PrimaryInput {
HotkeyInput hotkey;
void inputEvent(int16_t scancode, int16_t value);
UserInterfaceInput();
};

View File

@ -62,16 +62,5 @@ void InterfaceGameBoy::audioSample(int16_t csample, int16_t lsample, int16_t rsa
}
bool InterfaceGameBoy::inputPoll(unsigned id) {
switch((GameBoy::Input)id) {
case GameBoy::Input::Up: return interface->inputState[keyboard(0)[Keyboard::Up]];
case GameBoy::Input::Down: return interface->inputState[keyboard(0)[Keyboard::Down]];
case GameBoy::Input::Left: return interface->inputState[keyboard(0)[Keyboard::Left]];
case GameBoy::Input::Right: return interface->inputState[keyboard(0)[Keyboard::Right]];
case GameBoy::Input::B: return interface->inputState[keyboard(0)[Keyboard::Z]];
case GameBoy::Input::A: return interface->inputState[keyboard(0)[Keyboard::X]];
case GameBoy::Input::Select: return interface->inputState[keyboard(0)[Keyboard::Apostrophe]];
case GameBoy::Input::Start: return interface->inputState[keyboard(0)[Keyboard::Return]];
}
return false;
return inputManager->gameBoy.device.controller.poll(id);
}

View File

@ -149,13 +149,6 @@ Interface::Interface() {
//internal
void Interface::input_poll() {
bool fullScreen = inputState[keyboard(0)[Keyboard::F11]];
input.poll(inputState);
if(!fullScreen && inputState[keyboard(0)[Keyboard::F11]]) {
utility->toggleFullScreen();
}
}
void Interface::video_refresh() {

View File

@ -31,7 +31,6 @@ struct Interface : property<Interface> {
Interface();
int16_t inputState[Scancode::Limit];
void input_poll();
void video_refresh();

View File

@ -45,19 +45,7 @@ void InterfaceNES::audioSample(int16_t sample) {
}
int16_t InterfaceNES::inputPoll(bool port, unsigned device, unsigned id) {
if(port == 0 && device == 0) {
switch(id) {
case 0: return interface->inputState[keyboard(0)[Keyboard::X]];
case 1: return interface->inputState[keyboard(0)[Keyboard::Z]];
case 2: return interface->inputState[keyboard(0)[Keyboard::Apostrophe]];
case 3: return interface->inputState[keyboard(0)[Keyboard::Return]];
case 4: return interface->inputState[keyboard(0)[Keyboard::Up]];
case 5: return interface->inputState[keyboard(0)[Keyboard::Down]];
case 6: return interface->inputState[keyboard(0)[Keyboard::Left]];
case 7: return interface->inputState[keyboard(0)[Keyboard::Right]];
}
}
if(port == 0 && device == 0) return inputManager->nes.port1.gamepad.poll(id);
return 0;
}

View File

@ -78,23 +78,7 @@ void InterfaceSNES::audioSample(int16_t lsample, int16_t rsample) {
}
int16_t InterfaceSNES::inputPoll(bool port, SNES::Input::Device device, unsigned index, unsigned id) {
if(port == 0 && device == SNES::Input::Device::Joypad) {
switch((SNES::Input::JoypadID)id) {
case SNES::Input::JoypadID::Up: return interface->inputState[keyboard(0)[Keyboard::Up]];
case SNES::Input::JoypadID::Down: return interface->inputState[keyboard(0)[Keyboard::Down]];
case SNES::Input::JoypadID::Left: return interface->inputState[keyboard(0)[Keyboard::Left]];
case SNES::Input::JoypadID::Right: return interface->inputState[keyboard(0)[Keyboard::Right]];
case SNES::Input::JoypadID::B: return interface->inputState[keyboard(0)[Keyboard::Z]];
case SNES::Input::JoypadID::A: return interface->inputState[keyboard(0)[Keyboard::X]];
case SNES::Input::JoypadID::Y: return interface->inputState[keyboard(0)[Keyboard::A]];
case SNES::Input::JoypadID::X: return interface->inputState[keyboard(0)[Keyboard::S]];
case SNES::Input::JoypadID::L: return interface->inputState[keyboard(0)[Keyboard::D]];
case SNES::Input::JoypadID::R: return interface->inputState[keyboard(0)[Keyboard::C]];
case SNES::Input::JoypadID::Select: return interface->inputState[keyboard(0)[Keyboard::Apostrophe]];
case SNES::Input::JoypadID::Start: return interface->inputState[keyboard(0)[Keyboard::Return]];
}
}
if(port == 0 && device == SNES::Input::Device::Joypad) return inputManager->snes.port1.gamepad.poll(id);
return 0;
}

View File

@ -4,7 +4,7 @@ Application *application = 0;
nall::DSP dspaudio;
void Application::run() {
interface->input_poll();
inputManager->scan();
if(interface->loaded() == false) {
usleep(20 * 1000);
@ -22,9 +22,16 @@ Application::Application(int argc, char **argv) : quit(false) {
realpath = path;
unused = ::userpath(path);
userpath = path;
#if defined(PLATFORM_WIN)
userpath.append("batch/");
#else
userpath.append(".config/batch/");
#endif
mkdir(userpath, 0755);
}
config = new Config;
interface = new Interface;
inputManager = new InputManager;
utility = new Utility;
title = "batch";
@ -33,10 +40,12 @@ Application::Application(int argc, char **argv) : quit(false) {
string videoDriver = "Direct3D", audioDriver = "XAudio2", inputDriver = "RawInput";
normalFont = "Tahoma, 8";
boldFont = "Tahoma, 8, Bold";
titleFont = "Tahoma, 16, Bold";
#else
string videoDriver = "OpenGL", audioDriver = "PulseAudio", inputDriver = "SDL";
normalFont = "Sans, 8";
boldFont = "Sans, 8, Bold";
titleFont = "Sans, 16, Bold";
#endif
mainWindow = new MainWindow;
@ -49,7 +58,7 @@ Application::Application(int argc, char **argv) : quit(false) {
video.driver(videoDriver);
video.set(Video::Handle, mainWindow->viewport.handle());
video.set(Video::Synchronize, false);
video.set(Video::Synchronize, true);
video.set(Video::Filter, 0u);
video.init();
@ -87,6 +96,7 @@ Application::~Application() {
delete fileBrowser;
delete mainWindow;
delete utility;
delete inputManager;
delete interface;
delete config;
}

88
bsnes/ui/settings/input.cpp Executable file
View File

@ -0,0 +1,88 @@
InputSettings *inputSettings = 0;
InputSettings::InputSettings() : activeInput(0) {
title.setFont(application->titleFont);
title.setText("Input Settings");
inputList.setHeaderText("Name", "Mapping");
inputList.setHeaderVisible();
clearButton.setText("Clear");
for(unsigned n = 0; n < inputManager->inputList.size(); n++) {
primary.append(inputManager->inputList[n].name);
}
primaryChange();
append(title, ~0, 0, 5);
append(selectionLayout, ~0, 0, 5);
selectionLayout.append(primary, ~0, 0, 5);
selectionLayout.append(secondary, ~0, 0, 5);
selectionLayout.append(tertiary, ~0, 0);
append(inputList, ~0, ~0, 5);
append(controlLayout, ~0, 0);
controlLayout.append(spacer, ~0, 0);
controlLayout.append(clearButton, 80, 0);
primary.onChange = { &InputSettings::primaryChange, this };
secondary.onChange = { &InputSettings::secondaryChange, this };
tertiary.onChange = { &InputSettings::tertiaryChange, this };
inputList.onChange = { &InputSettings::synchronize, this };
inputList.onActivate = { &InputSettings::assignInputBegin, this };
synchronize();
}
void InputSettings::synchronize() {
clearButton.setEnabled(inputList.selected());
}
void InputSettings::primaryChange() {
secondary.reset();
tertiary.reset();
PrimaryInput &input = inputManager->inputList[primary.selection()];
for(unsigned n = 0; n < input.size(); n++) {
secondary.append(input[n].name);
}
secondaryChange();
}
void InputSettings::secondaryChange() {
tertiary.reset();
PrimaryInput &pinput = inputManager->inputList[primary.selection()];
SecondaryInput &input = pinput[secondary.selection()];
for(unsigned n = 0; n < input.size(); n++) {
tertiary.append(input[n].name);
}
tertiaryChange();
}
void InputSettings::tertiaryChange() {
inputList.reset();
PrimaryInput &pinput = inputManager->inputList[primary.selection()];
SecondaryInput &sinput = pinput[secondary.selection()];
TertiaryInput &input = sinput[tertiary.selection()];
for(unsigned n = 0; n < input.size(); n++) {
inputList.append(input[n].name, input[n].mapping);
}
synchronize();
inputList.autoSizeColumns();
}
void InputSettings::assignInputBegin() {
PrimaryInput &pinput = inputManager->inputList[primary.selection()];
SecondaryInput &sinput = pinput[secondary.selection()];
TertiaryInput &tinput = sinput[tertiary.selection()];
activeInput = &tinput[inputList.selection()];
settingsWindow->layout.setEnabled(false);
settingsWindow->setStatusText({ "Set asssignment for [", tinput.name, "::", activeInput->name, "] ..." });
}
void InputSettings::inputEvent(int16_t scancode, int16_t value) {
if(activeInput == 0) return;
if(activeInput->bind(scancode, value) == false) return;
activeInput = 0;
tertiaryChange();
settingsWindow->setStatusText("");
settingsWindow->layout.setEnabled(true);
}

25
bsnes/ui/settings/input.hpp Executable file
View File

@ -0,0 +1,25 @@
struct InputSettings : VerticalLayout {
Label title;
HorizontalLayout selectionLayout;
ComboBox primary;
ComboBox secondary;
ComboBox tertiary;
ListView inputList;
HorizontalLayout controlLayout;
Widget spacer;
Button clearButton;
InputSettings();
void synchronize();
void primaryChange();
void secondaryChange();
void tertiaryChange();
void assignInputBegin();
void inputEvent(int16_t scancode, int16_t value);
private:
AbstractInput *activeInput;
};
extern InputSettings *inputSettings;

View File

@ -1,7 +1,24 @@
#include "../base.hpp"
#include "input.cpp"
SettingsWindow *settingsWindow = 0;
SettingsWindow::SettingsWindow() {
setTitle("Configuration Settings");
setGeometry({ 128, 128, 640, 360 });
setStatusFont(application->boldFont);
setStatusVisible();
panelList.append("Input");
inputSettings = new InputSettings;
append(layout);
layout.setMargin(5);
layout.append(panelList, 120, ~0, 5);
layout.append(*inputSettings, ~0, ~0);
}
SettingsWindow::~SettingsWindow() {
delete inputSettings;
}

View File

@ -1,5 +1,11 @@
#include "input.hpp"
struct SettingsWindow : Window {
HorizontalLayout layout;
ListView panelList;
SettingsWindow();
~SettingsWindow();
};
extern SettingsWindow *settingsWindow;

View File

@ -19,7 +19,7 @@ void Utility::setMode(Interface::Mode mode) {
mainWindow->setTitle({ notdir(interface->baseName), " - ", NES::Info::Name, " v", NES::Info::Version });
mainWindow->nesMenu.setVisible(true);
dspaudio.setChannels(1);
dspaudio.setFrequency(315.0 / 88.8 * 6000000.0 / 12.0);
dspaudio.setFrequency(315.0 / 88.0 * 6000000.0 / 12.0);
}
else if(mode == Interface::Mode::SNES) {