mirror of https://github.com/bsnes-emu/bsnes.git
273 lines
7.9 KiB
C++
Executable File
273 lines
7.9 KiB
C++
Executable File
#include "../ui-base.hpp"
|
|
|
|
#include "controller.cpp"
|
|
#include "userinterface-general.cpp"
|
|
#include "userinterface-system.cpp"
|
|
#include "userinterface-emulationspeed.cpp"
|
|
#include "userinterface-states.cpp"
|
|
#include "userinterface-videosettings.cpp"
|
|
|
|
void MappedInput::bind() {
|
|
lstring part;
|
|
part.split("+", name);
|
|
|
|
modifier = InputModifier::None;
|
|
for(unsigned i = 0; i < part.size(); i++) {
|
|
if(part[i] == "Shift") modifier |= InputModifier::Shift;
|
|
if(part[i] == "Control") modifier |= InputModifier::Control;
|
|
if(part[i] == "Alt") modifier |= InputModifier::Alt;
|
|
if(part[i] == "Super") modifier |= InputModifier::Super;
|
|
}
|
|
|
|
string temp = part[part.size() - 1];
|
|
part.split(".", temp);
|
|
scancode = Scancode::decode(part[0]);
|
|
specifier = InputSpecifier::None;
|
|
if(part[1] == "Up") specifier = InputSpecifier::Up;
|
|
if(part[1] == "Down") specifier = InputSpecifier::Down;
|
|
if(part[1] == "Left") specifier = InputSpecifier::Left;
|
|
if(part[1] == "Right") specifier = InputSpecifier::Right;
|
|
if(part[1] == "Lo") specifier = InputSpecifier::Lo;
|
|
if(part[1] == "Hi") specifier = InputSpecifier::Hi;
|
|
if(part[1] == "Trigger") specifier = InputSpecifier::Trigger;
|
|
|
|
//re-encode name, in case previous name was invalid
|
|
name = "";
|
|
if(modifier & InputModifier::Shift) name << "Shift+";
|
|
if(modifier & InputModifier::Control) name << "Control+";
|
|
if(modifier & InputModifier::Alt) name << "Alt+";
|
|
if(modifier & InputModifier::Super) name << "Super+";
|
|
name << Scancode::encode(scancode);
|
|
if(specifier == InputSpecifier::Up) name << ".Up";
|
|
if(specifier == InputSpecifier::Down) name << ".Down";
|
|
if(specifier == InputSpecifier::Left) name << ".Left";
|
|
if(specifier == InputSpecifier::Right) name << ".Right";
|
|
if(specifier == InputSpecifier::Lo) name << ".Lo";
|
|
if(specifier == InputSpecifier::Hi) name << ".Hi";
|
|
if(specifier == InputSpecifier::Trigger) name << ".Trigger";
|
|
}
|
|
|
|
void MappedInput::cache() {
|
|
cachedState = state;
|
|
}
|
|
|
|
MappedInput::MappedInput(const char *label_, const char *configName) : parent(0), label(label_) {
|
|
specifier = InputSpecifier::None;
|
|
state = 0;
|
|
previousState = 0;
|
|
cachedState = 0;
|
|
config().attach(name = "None", configName);
|
|
}
|
|
|
|
//
|
|
|
|
void DigitalInput::poll() {
|
|
previousState = state;
|
|
if(modifier == mapper().modifier || !config().input.modifierEnable) {
|
|
if(specifier == InputSpecifier::None) {
|
|
state = mapper().state(scancode);
|
|
} else if(specifier == InputSpecifier::Up) {
|
|
state = (bool)(mapper().state(scancode) & Joypad::HatUp);
|
|
} else if(specifier == InputSpecifier::Down) {
|
|
state = (bool)(mapper().state(scancode) & Joypad::HatDown);
|
|
} else if(specifier == InputSpecifier::Left) {
|
|
state = (bool)(mapper().state(scancode) & Joypad::HatLeft);
|
|
} else if(specifier == InputSpecifier::Right) {
|
|
state = (bool)(mapper().state(scancode) & Joypad::HatRight);
|
|
} else if(specifier == InputSpecifier::Lo) {
|
|
state = mapper().state(scancode) < -16384;
|
|
} else if(specifier == InputSpecifier::Hi) {
|
|
state = mapper().state(scancode) > +16384;
|
|
} else if(specifier == InputSpecifier::Trigger) {
|
|
state = mapper().state(scancode) < 0;
|
|
}
|
|
} else {
|
|
state = 0;
|
|
}
|
|
}
|
|
|
|
bool DigitalInput::isPressed() const { return state; }
|
|
bool DigitalInput::wasPressed() const { return previousState; }
|
|
|
|
DigitalInput::DigitalInput(const char *label, const char *configName) : MappedInput(label, configName) {
|
|
}
|
|
|
|
//
|
|
|
|
void AnalogInput::poll() {
|
|
previousState = state;
|
|
if(Mouse::isAnyAxis(scancode)) {
|
|
if(input.acquired()) {
|
|
state = mapper().state(scancode);
|
|
} else {
|
|
state = 0;
|
|
}
|
|
} else if(Joypad::isAnyAxis(scancode)) {
|
|
state = mapper().state(scancode) / 8192;
|
|
}
|
|
}
|
|
|
|
AnalogInput::AnalogInput(const char *label, const char *configName) : MappedInput(label, configName) {
|
|
}
|
|
|
|
//
|
|
|
|
void HotkeyInput::poll() {
|
|
DigitalInput::poll();
|
|
if(mainWindow->isActive() && state != previousState) {
|
|
state ? pressed() : released();
|
|
}
|
|
}
|
|
|
|
HotkeyInput::HotkeyInput(const char *label, const char *configName) : DigitalInput(label, configName) {
|
|
}
|
|
|
|
//
|
|
|
|
void InputGroup::attach(MappedInput *input) {
|
|
input->parent = this;
|
|
append(input);
|
|
}
|
|
|
|
void InputGroup::bind() {
|
|
for(unsigned i = 0; i < size(); i++) {
|
|
(*this)[i]->bind();
|
|
}
|
|
}
|
|
|
|
void InputGroup::poll() {
|
|
for(unsigned i = 0; i < size(); i++) {
|
|
(*this)[i]->poll();
|
|
}
|
|
}
|
|
|
|
void InputGroup::cache() {
|
|
for(unsigned i = 0; i < size(); i++) {
|
|
(*this)[i]->cache();
|
|
}
|
|
}
|
|
|
|
void InputGroup::flushCache() {
|
|
for(unsigned i = 0; i < size(); i++) {
|
|
MappedInput &input = *((*this)[i]);
|
|
input.cachedState = 0;
|
|
}
|
|
}
|
|
|
|
InputGroup::InputGroup(unsigned category_, const char *label_) : category(category_), label(label_) {
|
|
mapper().append(this);
|
|
}
|
|
|
|
//
|
|
|
|
InputMapper& mapper() {
|
|
static InputMapper mapper;
|
|
return mapper;
|
|
}
|
|
|
|
void InputMapper::calibrate() {
|
|
calibrated = true;
|
|
audio.clear();
|
|
QMessageBox::information(settingsWindow, "Joypad Calibration",
|
|
"Joypads must be calibrated prior to mapping. Please ensure that "
|
|
"all axes and analog buttons are not pressed or moved in any specific "
|
|
"direction, and then press ok."
|
|
);
|
|
|
|
poll();
|
|
for(unsigned i = 0; i < Joypad::Count; i++) {
|
|
for(unsigned axis = 0; axis < Joypad::Axes; axis++) {
|
|
int16_t n = state(joypad(i).axis(axis));
|
|
isTrigger[i][axis] = n < -16384 || n > +16384;
|
|
}
|
|
}
|
|
}
|
|
|
|
void InputMapper::bind() {
|
|
for(unsigned i = 0; i < size(); i++) {
|
|
(*this)[i]->bind();
|
|
}
|
|
}
|
|
|
|
void InputMapper::poll() {
|
|
activeState = !activeState;
|
|
input.poll(stateTable[activeState]);
|
|
|
|
modifier = 0;
|
|
for(unsigned i = 0; i < Keyboard::Count; i++) {
|
|
if(state(keyboard(i)[Keyboard::Shift])) modifier |= InputModifier::Shift;
|
|
if(state(keyboard(i)[Keyboard::Control])) modifier |= InputModifier::Control;
|
|
if(state(keyboard(i)[Keyboard::Alt])) modifier |= InputModifier::Alt;
|
|
if(state(keyboard(i)[Keyboard::Super])) modifier |= InputModifier::Super;
|
|
}
|
|
|
|
for(unsigned i = 0; i < size(); i++) {
|
|
(*this)[i]->poll();
|
|
}
|
|
|
|
for(unsigned i = 0; i < Scancode::Limit; i++) {
|
|
if(state(i) != previousState(i)) {
|
|
utility.inputEvent(i);
|
|
inputSettingsWindow->inputEvent(i);
|
|
}
|
|
}
|
|
}
|
|
|
|
void InputMapper::cache() {
|
|
if(config().input.focusPolicy == Configuration::Input::FocusPolicyIgnoreInput && !mainWindow->isActive()) {
|
|
for(unsigned i = 0; i < size(); i++) {
|
|
InputGroup &group = *((*this)[i]);
|
|
group.flushCache();
|
|
}
|
|
} else {
|
|
for(unsigned i = 0; i < size(); i++) {
|
|
InputGroup &group = *((*this)[i]);
|
|
if(group.category == InputCategory::Port1 || group.category == InputCategory::Port2) {
|
|
group.cache();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
int16_t InputMapper::status(bool port, SNES::Input::Device device, unsigned index, unsigned id) {
|
|
int16_t result = 0;
|
|
|
|
if(port == InputCategory::Port1 && port1) result = port1->status(index, id);
|
|
if(port == InputCategory::Port2 && port2) result = port2->status(index, id);
|
|
|
|
if(movie.state == Movie::Playback) {
|
|
result = movie.read();
|
|
} else if(movie.state == Movie::Record) {
|
|
movie.write(result);
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
string InputMapper::modifierString() const {
|
|
string name;
|
|
if(modifier & InputModifier::Shift) name << "Shift+";
|
|
if(modifier & InputModifier::Control) name << "Control+";
|
|
if(modifier & InputModifier::Alt) name << "Alt+";
|
|
if(modifier & InputModifier::Super) name << "Super+";
|
|
return name;
|
|
}
|
|
|
|
int16_t InputMapper::state(uint16_t scancode) const { return stateTable[activeState][scancode]; }
|
|
int16_t InputMapper::previousState(uint16_t scancode) const { return stateTable[!activeState][scancode]; }
|
|
unsigned InputMapper::distance(uint16_t scancode) const { return abs(state(scancode) - previousState(scancode)); }
|
|
|
|
InputMapper::InputMapper() : port1(0), port2(0) {
|
|
calibrated = false;
|
|
for(unsigned i = 0; i < Joypad::Count; i++) {
|
|
for(unsigned axis = 0; axis < Joypad::Axes; axis++) {
|
|
isTrigger[i][axis] = false;
|
|
}
|
|
}
|
|
|
|
activeState = 0;
|
|
for(unsigned i = 0; i < Scancode::Limit; i++) {
|
|
stateTable[0][i] = stateTable[1][i] = 0;
|
|
}
|
|
}
|