mirror of https://github.com/bsnes-emu/bsnes.git
386 lines
14 KiB
C++
Executable File
386 lines
14 KiB
C++
Executable File
namespace Controllers {
|
|
|
|
void TurboInput::cache() {
|
|
if(state) {
|
|
cachedState = (counter < holdHi ? state : 0);
|
|
if(++counter >= holdHi + holdLo) counter = 0;
|
|
} else {
|
|
cachedState = 0;
|
|
counter = 0;
|
|
}
|
|
}
|
|
|
|
TurboInput::TurboInput(const char *label, const char *configName) :
|
|
DigitalInput(label, configName) {
|
|
holdHi = 2;
|
|
holdLo = 2;
|
|
counter = 0;
|
|
}
|
|
|
|
int16_t Gamepad::status(unsigned index, unsigned id) const {
|
|
if(config().input.allowInvalidInput == false) {
|
|
//block up+down and left+right combinations:
|
|
//a real gamepad has a pivot in the D-pad that makes this impossible;
|
|
//some software titles will crash if up+down or left+right are detected
|
|
if(id == (unsigned)SNES::Input::JoypadID::Down && up.cachedState) return 0;
|
|
if(id == (unsigned)SNES::Input::JoypadID::Right && left.cachedState) return 0;
|
|
}
|
|
|
|
switch(id) {
|
|
case SNES::Input::JoypadID::Up: return up.cachedState;
|
|
case SNES::Input::JoypadID::Down: return down.cachedState;
|
|
case SNES::Input::JoypadID::Left: return left.cachedState;
|
|
case SNES::Input::JoypadID::Right: return right.cachedState;
|
|
case SNES::Input::JoypadID::A: return a.cachedState | turboA.cachedState;
|
|
case SNES::Input::JoypadID::B: return b.cachedState | turboB.cachedState;
|
|
case SNES::Input::JoypadID::X: return x.cachedState | turboX.cachedState;
|
|
case SNES::Input::JoypadID::Y: return y.cachedState | turboY.cachedState;
|
|
case SNES::Input::JoypadID::L: return l.cachedState | turboL.cachedState;
|
|
case SNES::Input::JoypadID::R: return r.cachedState | turboR.cachedState;
|
|
case SNES::Input::JoypadID::Select: return select.cachedState;
|
|
case SNES::Input::JoypadID::Start: return start.cachedState;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
Gamepad::Gamepad(unsigned category, const char *label, const char *configName) :
|
|
InputGroup(category, label),
|
|
up("Up", string() << "input." << configName << ".up"),
|
|
down("Down", string() << "input." << configName << ".down"),
|
|
left("Left", string() << "input." << configName << ".left"),
|
|
right("Right", string() << "input." << configName << ".right"),
|
|
b("B", string() << "input." << configName << ".b"),
|
|
a("A", string() << "input." << configName << ".a"),
|
|
y("Y", string() << "input." << configName << ".y"),
|
|
x("X", string() << "input." << configName << ".x"),
|
|
l("L", string() << "input." << configName << ".l"),
|
|
r("R", string() << "input." << configName << ".r"),
|
|
select("Select", string() << "input." << configName << ".select"),
|
|
start("Start", string() << "input." << configName << ".start"),
|
|
turboB("Turbo B", string() << "input." << configName << ".turboB"),
|
|
turboA("Turbo A", string() << "input." << configName << ".turboA"),
|
|
turboY("Turbo Y", string() << "input." << configName << ".turboY"),
|
|
turboX("Turbo X", string() << "input." << configName << ".turboX"),
|
|
turboL("Turbo L", string() << "input." << configName << ".turboL"),
|
|
turboR("Turbo R", string() << "input." << configName << ".turboR") {
|
|
attach(&up); attach(&down); attach(&left); attach(&right);
|
|
attach(&b); attach(&a); attach(&y); attach(&x);
|
|
attach(&l); attach(&r); attach(&select); attach(&start);
|
|
attach(&turboB); attach(&turboA); attach(&turboY); attach(&turboX);
|
|
attach(&turboL); attach(&turboR);
|
|
|
|
if(this == &gamepad1) {
|
|
up.name = "KB0::Up";
|
|
down.name = "KB0::Down";
|
|
left.name = "KB0::Left";
|
|
right.name = "KB0::Right";
|
|
b.name = "KB0::Z";
|
|
a.name = "KB0::X";
|
|
y.name = "KB0::A";
|
|
x.name = "KB0::S";
|
|
l.name = "KB0::D";
|
|
r.name = "KB0::C";
|
|
select.name = "KB0::Apostrophe";
|
|
start.name = "KB0::Return";
|
|
}
|
|
}
|
|
|
|
//
|
|
|
|
int16_t Multitap::status(unsigned index, unsigned id) const {
|
|
switch(index & 3) { default:
|
|
case 0: return port1.status(index, id);
|
|
case 1: return port2.status(index, id);
|
|
case 2: return port3.status(index, id);
|
|
case 3: return port4.status(index, id);
|
|
}
|
|
}
|
|
|
|
Multitap::Multitap(Gamepad &port1_, Gamepad &port2_, Gamepad &port3_, Gamepad &port4_) :
|
|
InputGroup(InputCategory::Hidden, "Multitap"),
|
|
port1(port1_), port2(port2_), port3(port3_), port4(port4_) {
|
|
}
|
|
|
|
//
|
|
|
|
void AsciiSwitch::poll() {
|
|
DigitalInput::poll();
|
|
|
|
//only change state when controller is active
|
|
if(!parent) return;
|
|
if(parent->category == InputCategory::Port1 && mapper().port1 != parent) return;
|
|
if(parent->category == InputCategory::Port2 && mapper().port2 != parent) return;
|
|
|
|
if(previousState != state && state) {
|
|
switch(mode) {
|
|
case Off: mode = Turbo; utility.showMessage(string() << label << " set to turbo."); break;
|
|
case Turbo: mode = Auto; utility.showMessage(string() << label << " set to auto."); break;
|
|
case Auto: mode = Off; utility.showMessage(string() << label << " set to off."); break;
|
|
}
|
|
}
|
|
}
|
|
|
|
AsciiSwitch::AsciiSwitch(const char *label, const char *configName) :
|
|
DigitalInput(label, configName) {
|
|
mode = Off;
|
|
}
|
|
|
|
void AsciiInput::cache() {
|
|
if(asciiSwitch->mode == AsciiSwitch::Off) {
|
|
cachedState = state;
|
|
} else if(asciiSwitch->mode == AsciiSwitch::Turbo) {
|
|
if(state) {
|
|
cachedState = (counter < holdHi ? state : 0);
|
|
if(++counter >= holdHi + holdLo) counter = 0;
|
|
} else {
|
|
cachedState = 0;
|
|
counter = 0;
|
|
}
|
|
} else if(asciiSwitch->mode == AsciiSwitch::Auto) {
|
|
cachedState = (counter < holdHi);
|
|
if(++counter >= holdHi + holdLo) counter = 0;
|
|
}
|
|
}
|
|
|
|
AsciiInput::AsciiInput(const char *label, const char *configName) :
|
|
DigitalInput(label, configName) {
|
|
holdHi = 2;
|
|
holdLo = 2;
|
|
counter = 0;
|
|
}
|
|
|
|
void AsciiSlowMotion::poll() {
|
|
DigitalInput::poll();
|
|
|
|
//only change state when controller is active
|
|
if(!parent) return;
|
|
if(parent->category == InputCategory::Port1 && mapper().port1 != parent) return;
|
|
if(parent->category == InputCategory::Port2 && mapper().port2 != parent) return;
|
|
|
|
if(previousState != state && state) {
|
|
if(enabled == false) {
|
|
enabled = true;
|
|
utility.showMessage(string() << label << " enabled.");
|
|
} else {
|
|
enabled = false;
|
|
utility.showMessage(string() << label << " disabled.");
|
|
}
|
|
}
|
|
}
|
|
|
|
void AsciiSlowMotion::cache() {
|
|
if(enabled == false) {
|
|
cachedState = 0;
|
|
} else {
|
|
cachedState = counter < holdHi;
|
|
if(++counter >= holdHi + holdLo) counter = 0;
|
|
}
|
|
}
|
|
|
|
AsciiSlowMotion::AsciiSlowMotion(const char *label, const char *configName) :
|
|
DigitalInput(label, configName) {
|
|
enabled = false;
|
|
holdHi = 2;
|
|
holdLo = 2;
|
|
}
|
|
|
|
int16_t Asciipad::status(unsigned index, unsigned id) const {
|
|
if(config().input.allowInvalidInput == false) {
|
|
if(id == (unsigned)SNES::Input::JoypadID::Down && up.cachedState) return 0;
|
|
if(id == (unsigned)SNES::Input::JoypadID::Right && left.cachedState) return 0;
|
|
}
|
|
|
|
switch(id) {
|
|
case SNES::Input::JoypadID::Up: return up.cachedState;
|
|
case SNES::Input::JoypadID::Down: return down.cachedState;
|
|
case SNES::Input::JoypadID::Left: return left.cachedState;
|
|
case SNES::Input::JoypadID::Right: return right.cachedState;
|
|
case SNES::Input::JoypadID::A: return a.cachedState;
|
|
case SNES::Input::JoypadID::B: return b.cachedState;
|
|
case SNES::Input::JoypadID::X: return x.cachedState;
|
|
case SNES::Input::JoypadID::Y: return y.cachedState;
|
|
case SNES::Input::JoypadID::L: return l.cachedState;
|
|
case SNES::Input::JoypadID::R: return r.cachedState;
|
|
case SNES::Input::JoypadID::Select: return select.cachedState;
|
|
case SNES::Input::JoypadID::Start: return start.cachedState | slowMotion.cachedState;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
Asciipad::Asciipad(unsigned category, const char *label, const char *configName) :
|
|
InputGroup(category, label),
|
|
up("Up", string() << "input." << configName << ".up"),
|
|
down("Down", string() << "input." << configName << ".down"),
|
|
left("Left", string() << "input." << configName << ".left"),
|
|
right("Right", string() << "input." << configName << ".right"),
|
|
b("B", string() << "input." << configName << ".b"),
|
|
a("A", string() << "input." << configName << ".a"),
|
|
y("Y", string() << "input." << configName << ".y"),
|
|
x("X", string() << "input." << configName << ".x"),
|
|
l("L", string() << "input." << configName << ".l"),
|
|
r("R", string() << "input." << configName << ".r"),
|
|
select("Select", string() << "input." << configName << ".select"),
|
|
start("Start", string() << "input." << configName << ".start"),
|
|
switchB("B Switch", string() << "input." << configName << ".bSwitch"),
|
|
switchA("A Switch", string() << "input." << configName << ".aSwitch"),
|
|
switchY("Y Switch", string() << "input." << configName << ".ySwitch"),
|
|
switchX("X Switch", string() << "input." << configName << ".xSwitch"),
|
|
switchL("L Switch", string() << "input." << configName << ".lSwitch"),
|
|
switchR("R Switch", string() << "input." << configName << ".rSwitch"),
|
|
slowMotion("Slow Motion", string() << "input." << configName << ".slowMotion") {
|
|
b.asciiSwitch = &switchB;
|
|
a.asciiSwitch = &switchA;
|
|
y.asciiSwitch = &switchY;
|
|
x.asciiSwitch = &switchX;
|
|
l.asciiSwitch = &switchL;
|
|
r.asciiSwitch = &switchR;
|
|
|
|
attach(&up); attach(&down); attach(&left); attach(&right);
|
|
attach(&b); attach(&a); attach(&y); attach(&x);
|
|
attach(&l); attach(&r); attach(&select); attach(&start);
|
|
attach(&switchB); attach(&switchA); attach(&switchY); attach(&switchX);
|
|
attach(&switchL); attach(&switchR); attach(&slowMotion);
|
|
|
|
if(this == &asciipad1) {
|
|
up.name = "KB0::Up";
|
|
down.name = "KB0::Down";
|
|
left.name = "KB0::Left";
|
|
right.name = "KB0::Right";
|
|
b.name = "KB0::Z";
|
|
a.name = "KB0::X";
|
|
y.name = "KB0::A";
|
|
x.name = "KB0::S";
|
|
l.name = "KB0::D";
|
|
r.name = "KB0::C";
|
|
select.name = "KB0::Apostrophe";
|
|
start.name = "KB0::Return";
|
|
}
|
|
}
|
|
|
|
//
|
|
|
|
int16_t Mouse::status(unsigned index, unsigned id) const {
|
|
switch(id) {
|
|
case SNES::Input::MouseID::X: return x.cachedState;
|
|
case SNES::Input::MouseID::Y: return y.cachedState;
|
|
case SNES::Input::MouseID::Left: return left.cachedState;
|
|
case SNES::Input::MouseID::Right: return right.cachedState;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
Mouse::Mouse(unsigned category, const char *label, const char *configName) :
|
|
InputGroup(category, label),
|
|
x("X-axis", string() << "input." << configName << ".x"),
|
|
y("Y-axis", string() << "input." << configName << ".y"),
|
|
left("Left Button", string() << "input." << configName << ".left"),
|
|
right("Right Button", string() << "input." << configName << ".right") {
|
|
attach(&x); attach(&y); attach(&left); attach(&right);
|
|
|
|
x.name = "MS0::Xaxis";
|
|
y.name = "MS0::Yaxis";
|
|
left.name = "MS0::Button0";
|
|
right.name = "MS0::Button2";
|
|
}
|
|
|
|
//
|
|
|
|
int16_t SuperScope::status(unsigned index, unsigned id) const {
|
|
switch(id) {
|
|
case SNES::Input::SuperScopeID::X: return x.cachedState;
|
|
case SNES::Input::SuperScopeID::Y: return y.cachedState;
|
|
case SNES::Input::SuperScopeID::Trigger: return trigger.cachedState;
|
|
case SNES::Input::SuperScopeID::Cursor: return cursor.cachedState;
|
|
case SNES::Input::SuperScopeID::Turbo: return turbo.cachedState;
|
|
case SNES::Input::SuperScopeID::Pause: return pause.cachedState;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
SuperScope::SuperScope(unsigned category, const char *label, const char *configName) :
|
|
InputGroup(category, label),
|
|
x("X-axis", string() << "input." << configName << ".x"),
|
|
y("Y-axis", string() << "input." << configName << ".y"),
|
|
trigger("Trigger", string() << "input." << configName << ".trigger"),
|
|
cursor("Cursor", string() << "input." << configName << ".cursor"),
|
|
turbo("Turbo", string() << "input." << configName << ".turbo"),
|
|
pause("Pause", string() << "input." << configName << ".pause") {
|
|
attach(&x); attach(&y); attach(&trigger); attach(&cursor);
|
|
attach(&turbo); attach(&pause);
|
|
|
|
x.name = "MS0::Xaxis";
|
|
y.name = "MS0::Yaxis";
|
|
trigger.name = "MS0::Button0";
|
|
cursor.name = "MS0::Button2";
|
|
turbo.name = "KB0::T";
|
|
pause.name = "KB0::P";
|
|
}
|
|
|
|
//
|
|
|
|
int16_t Justifier::status(unsigned index, unsigned id) const {
|
|
switch(id) {
|
|
case SNES::Input::JustifierID::X: return x.cachedState;
|
|
case SNES::Input::JustifierID::Y: return y.cachedState;
|
|
case SNES::Input::JustifierID::Trigger: return trigger.cachedState;
|
|
case SNES::Input::JustifierID::Start: return start.cachedState;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
Justifier::Justifier(unsigned category, const char *label, const char *configName) :
|
|
InputGroup(category, label),
|
|
x("X-axis", string() << "input." << configName << ".x"),
|
|
y("Y-axis", string() << "input." << configName << ".y"),
|
|
trigger("Trigger", string() << "input." << configName << ".trigger"),
|
|
start("Start", string() << "input." << configName << ".start") {
|
|
attach(&x); attach(&y); attach(&trigger); attach(&start);
|
|
|
|
if(this == &justifier1) {
|
|
x.name = "MS0::Xaxis";
|
|
y.name = "MS0::Yaxis";
|
|
trigger.name = "MS0::Button0";
|
|
start.name = "MS0::Button2";
|
|
}
|
|
}
|
|
|
|
//
|
|
|
|
int16_t Justifiers::status(unsigned index, unsigned id) const {
|
|
switch(index & 1) { default:
|
|
case 0: return port1.status(index, id);
|
|
case 1: return port2.status(index, id);
|
|
}
|
|
}
|
|
|
|
Justifiers::Justifiers(Justifier &port1_, Justifier &port2_) :
|
|
InputGroup(InputCategory::Hidden, "Justifiers"),
|
|
port1(port1_), port2(port2_) {
|
|
}
|
|
|
|
//
|
|
|
|
Gamepad gamepad1(InputCategory::Port1, "Gamepad", "gamepad1");
|
|
Asciipad asciipad1(InputCategory::Port1, "asciiPad", "asciipad1");
|
|
Gamepad multitap1a(InputCategory::Port1, "Multitap - Port 1", "multitap1a");
|
|
Gamepad multitap1b(InputCategory::Port1, "Multitap - Port 2", "multitap1b");
|
|
Gamepad multitap1c(InputCategory::Port1, "Multitap - Port 3", "multitap1c");
|
|
Gamepad multitap1d(InputCategory::Port1, "Multitap - Port 4", "multitap1d");
|
|
Multitap multitap1(multitap1a, multitap1b, multitap1c, multitap1d);
|
|
Mouse mouse1(InputCategory::Port1, "Mouse", "mouse1");
|
|
|
|
Gamepad gamepad2(InputCategory::Port2, "Gamepad", "gamepad2");
|
|
Asciipad asciipad2(InputCategory::Port2, "asciiPad", "asciipad2");
|
|
Gamepad multitap2a(InputCategory::Port2, "Multitap - Port 1", "multitap2a");
|
|
Gamepad multitap2b(InputCategory::Port2, "Multitap - Port 2", "multitap2b");
|
|
Gamepad multitap2c(InputCategory::Port2, "Multitap - Port 3", "multitap2c");
|
|
Gamepad multitap2d(InputCategory::Port2, "Multitap - Port 4", "multitap2d");
|
|
Multitap multitap2(multitap2a, multitap2b, multitap2c, multitap2d);
|
|
Mouse mouse2(InputCategory::Port2, "Mouse", "mouse2");
|
|
SuperScope superscope(InputCategory::Port2, "Super Scope", "superscope");
|
|
Justifier justifier1(InputCategory::Port2, "Justifier 1", "justifier1");
|
|
Justifier justifier2(InputCategory::Port2, "Justifier 2", "justifier2");
|
|
Justifiers justifiers(justifier1, justifier2);
|
|
|
|
}
|