[config] Move VbamOption and wxGameControl to config namespace
This commit is contained in:
parent
297d7c06c4
commit
8c1bd84f40
1154
po/wxvbam/wxvbam.pot
1154
po/wxvbam/wxvbam.pot
File diff suppressed because it is too large
Load Diff
|
@ -736,14 +736,14 @@ set(
|
|||
opts.cpp
|
||||
sys.cpp
|
||||
panel.cpp
|
||||
vbam-options.cpp
|
||||
vbam-options-static.cpp
|
||||
viewsupt.cpp
|
||||
wayland.cpp
|
||||
strutils.cpp
|
||||
wxutil.cpp
|
||||
config/game-control.cpp
|
||||
config/internal/option-internal.cpp
|
||||
config/option.cpp
|
||||
config/user-input.cpp
|
||||
widgets/gamecontrol.cpp
|
||||
widgets/keyedit.cpp
|
||||
widgets/joyedit.cpp
|
||||
widgets/sdljoy.cpp
|
||||
|
@ -777,15 +777,15 @@ set(
|
|||
filters.h
|
||||
ioregs.h
|
||||
opts.h
|
||||
vbam-options.h
|
||||
vbam-options-internal.h
|
||||
viewsupt.h
|
||||
wxhead.h
|
||||
wayland.h
|
||||
wxutil.h
|
||||
config/game-control.h
|
||||
config/internal/option-internal.h
|
||||
config/option.h
|
||||
config/user-input.h
|
||||
widgets/dpi-support.h
|
||||
widgets/wx/gamecontrol.h
|
||||
widgets/wx/keyedit.h
|
||||
widgets/wx/joyedit.h
|
||||
widgets/wx/sdljoy.h
|
||||
|
|
|
@ -0,0 +1,298 @@
|
|||
#include "config/game-control.h"
|
||||
|
||||
#include "../strutils.h"
|
||||
#include "opts.h"
|
||||
#include "wx/log.h"
|
||||
#include "wxlogdebug.h"
|
||||
|
||||
namespace config {
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr uint32_t kBitKeyA = (1 << 0);
|
||||
constexpr uint32_t kBitKeyB = (1 << 1);
|
||||
constexpr uint32_t kBitKeySelect = (1 << 2);
|
||||
constexpr uint32_t kBitKeyStart = (1 << 3);
|
||||
constexpr uint32_t kBitKeyRight = (1 << 4);
|
||||
constexpr uint32_t kBitKeyLeft = (1 << 5);
|
||||
constexpr uint32_t kBitKeyUp = (1 << 6);
|
||||
constexpr uint32_t kBitKeyDown = (1 << 7);
|
||||
constexpr uint32_t kBitKeyR = (1 << 8);
|
||||
constexpr uint32_t kBitKeyL = (1 << 9);
|
||||
constexpr uint32_t kBitKeySpeed = (1 << 10);
|
||||
constexpr uint32_t kBitKeyCapture = (1 << 11);
|
||||
constexpr uint32_t kBitKeyGameShark = (1 << 12);
|
||||
constexpr uint32_t kBitKeyAutoA = (1 << 13);
|
||||
constexpr uint32_t kBitKeyAutoB = (1 << 14);
|
||||
constexpr uint32_t kBitKeyMotionUp = (1 << 15);
|
||||
constexpr uint32_t kBitKeyMotionDown = (1 << 16);
|
||||
constexpr uint32_t kBitKeyMotionLeft = (1 << 17);
|
||||
constexpr uint32_t kBitKeyMotionRight = (1 << 18);
|
||||
constexpr uint32_t kBitKeyMotionIn = (1 << 19);
|
||||
constexpr uint32_t kBitKeyMotionOut = (1 << 20);
|
||||
|
||||
// clang-format off
|
||||
constexpr std::array<uint32_t, kNbGameKeys> kBitMask = {
|
||||
kBitKeyUp,
|
||||
kBitKeyDown,
|
||||
kBitKeyLeft,
|
||||
kBitKeyRight,
|
||||
kBitKeyA,
|
||||
kBitKeyB,
|
||||
kBitKeyL,
|
||||
kBitKeyR,
|
||||
kBitKeySelect,
|
||||
kBitKeyStart,
|
||||
kBitKeyMotionUp,
|
||||
kBitKeyMotionDown,
|
||||
kBitKeyMotionLeft,
|
||||
kBitKeyMotionRight,
|
||||
kBitKeyMotionIn,
|
||||
kBitKeyMotionOut,
|
||||
kBitKeyAutoA,
|
||||
kBitKeyAutoB,
|
||||
kBitKeySpeed,
|
||||
kBitKeyCapture,
|
||||
kBitKeyGameShark,
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
inline int GameKeyToInt(const GameKey& game_key) {
|
||||
return static_cast<int>(game_key);
|
||||
}
|
||||
|
||||
// Returns true if `joypad` is in a valid joypad range.
|
||||
inline bool JoypadInRange(const int& joypad) {
|
||||
constexpr int kMinJoypadIndex = 0;
|
||||
return joypad >= kMinJoypadIndex && joypad < kNbJoypads;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
// clang-format off
|
||||
wxString GameKeyToString(const GameKey& game_key) {
|
||||
// Note: this must match GUI widget names or GUI won't work
|
||||
// This array's order determines tab order as well
|
||||
static const std::array<wxString, kNbGameKeys> kGameKeyStrings = {
|
||||
"Up",
|
||||
"Down",
|
||||
"Left",
|
||||
"Right",
|
||||
"A",
|
||||
"B",
|
||||
"L",
|
||||
"R",
|
||||
"Select",
|
||||
"Start",
|
||||
"MotionUp",
|
||||
"MotionDown",
|
||||
"MotionLeft",
|
||||
"MotionRight",
|
||||
"MotionIn",
|
||||
"MotionOut",
|
||||
"AutoA",
|
||||
"AutoB",
|
||||
"Speed",
|
||||
"Capture",
|
||||
"GS",
|
||||
};
|
||||
return kGameKeyStrings[GameKeyToInt(game_key)];
|
||||
}
|
||||
|
||||
nonstd::optional<GameKey> StringToGameKey(const wxString& input) {
|
||||
static const std::map<wxString, GameKey> kStringToGameKey = {
|
||||
{ "Up", GameKey::Up },
|
||||
{ "Down", GameKey::Down },
|
||||
{ "Left", GameKey::Left },
|
||||
{ "Right", GameKey::Right },
|
||||
{ "A", GameKey::A },
|
||||
{ "B", GameKey::B },
|
||||
{ "L", GameKey::L },
|
||||
{ "R", GameKey::R },
|
||||
{ "Select", GameKey::Select },
|
||||
{ "Start", GameKey::Start },
|
||||
{ "MotionUp", GameKey::MotionUp },
|
||||
{ "MotionDown", GameKey::MotionDown },
|
||||
{ "MotionLeft", GameKey::MotionLeft },
|
||||
{ "MotionRight", GameKey::MotionRight },
|
||||
{ "MotionIn", GameKey::MotionIn },
|
||||
{ "MotionOut", GameKey::MotionOut },
|
||||
{ "AutoA", GameKey::AutoA },
|
||||
{ "AutoB", GameKey::AutoB },
|
||||
{ "Speed", GameKey::Speed },
|
||||
{ "Capture", GameKey::Capture },
|
||||
{ "GS", GameKey::Gameshark },
|
||||
};
|
||||
|
||||
const auto iter = kStringToGameKey.find(input);
|
||||
if (iter == kStringToGameKey.end()) {
|
||||
return nonstd::nullopt;
|
||||
}
|
||||
return iter->second;
|
||||
}
|
||||
// clang-format on
|
||||
|
||||
// static
|
||||
nonstd::optional<GameControl> GameControl::FromString(const wxString& name) {
|
||||
static const wxString kJoypad("Joypad");
|
||||
if (!wxStrncmp(name, kJoypad, kJoypad.size())) {
|
||||
wxLogDebug("Doesn't start with joypad");
|
||||
return nonstd::nullopt;
|
||||
}
|
||||
|
||||
auto parts = strutils::split(name, "/");
|
||||
if (parts.size() != 3) {
|
||||
wxLogDebug("Wrong split size: %d", parts.size());
|
||||
return nonstd::nullopt;
|
||||
}
|
||||
|
||||
const int joypad = parts[1][0] - wxT('1');
|
||||
if (!JoypadInRange(joypad)) {
|
||||
wxLogDebug("Wrong joypad index: %d", joypad);
|
||||
return nonstd::nullopt;
|
||||
}
|
||||
|
||||
nonstd::optional<GameKey> game_key = StringToGameKey(parts[2]);
|
||||
if (!game_key) {
|
||||
wxLogDebug("Failed to parse game_key: %s", parts[2]);
|
||||
return nonstd::nullopt;
|
||||
}
|
||||
|
||||
return GameControl(joypad, game_key.value());
|
||||
}
|
||||
|
||||
GameControl::GameControl(int joypad, GameKey game_key)
|
||||
: joypad_(joypad),
|
||||
game_key_(game_key),
|
||||
config_string_(wxString::Format("Joypad/%d/%s",
|
||||
joypad_ + 1,
|
||||
GameKeyToString(game_key_))) {
|
||||
assert(JoypadInRange(joypad_));
|
||||
}
|
||||
GameControl::~GameControl() = default;
|
||||
|
||||
bool GameControl::operator==(const GameControl& other) const {
|
||||
return joypad_ == other.joypad_ && game_key_ == other.game_key_;
|
||||
}
|
||||
bool GameControl::operator!=(const GameControl& other) const {
|
||||
return !(*this == other);
|
||||
}
|
||||
bool GameControl::operator<(const GameControl& other) const {
|
||||
if (joypad_ != other.joypad_) {
|
||||
return joypad_ < other.joypad_;
|
||||
}
|
||||
if (game_key_ != other.game_key_) {
|
||||
return game_key_ < other.game_key_;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
bool GameControl::operator<=(const GameControl& other) const {
|
||||
return !(*this > other);
|
||||
}
|
||||
bool GameControl::operator>(const GameControl& other) const {
|
||||
return other < *this;
|
||||
}
|
||||
bool GameControl::operator>=(const GameControl& other) const {
|
||||
return !(*this < other);
|
||||
}
|
||||
|
||||
GameControlState& GameControlState::Instance() {
|
||||
static GameControlState g_game_control_state;
|
||||
return g_game_control_state;
|
||||
}
|
||||
|
||||
GameControlState::GameControlState() : joypads_({0, 0, 0, 0}) {}
|
||||
GameControlState::~GameControlState() = default;
|
||||
|
||||
bool GameControlState::OnInputPressed(const config::UserInput& user_input) {
|
||||
assert(user_input);
|
||||
|
||||
const auto& game_keys = input_bindings_.find(user_input);
|
||||
if (game_keys == input_bindings_.end()) {
|
||||
// No associated game control for `user_input`.
|
||||
return false;
|
||||
}
|
||||
|
||||
auto iter = keys_pressed_.find(user_input);
|
||||
if (iter != keys_pressed_.end()) {
|
||||
// Double press is noop.
|
||||
return true;
|
||||
}
|
||||
|
||||
// Remember the key pressed.
|
||||
keys_pressed_.emplace(user_input);
|
||||
|
||||
// Update all corresponding controls.
|
||||
for (const GameControl& game_control : game_keys->second) {
|
||||
active_controls_[game_control].emplace(user_input);
|
||||
joypads_[game_control.joypad_] |=
|
||||
kBitMask[GameKeyToInt(game_control.game_key_)];
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool GameControlState::OnInputReleased(const config::UserInput& user_input) {
|
||||
assert(user_input);
|
||||
|
||||
const auto& game_keys = input_bindings_.find(user_input);
|
||||
if (game_keys == input_bindings_.end()) {
|
||||
// No associated game control for `user_input`.
|
||||
return false;
|
||||
}
|
||||
|
||||
auto iter = keys_pressed_.find(user_input);
|
||||
if (iter == keys_pressed_.end()) {
|
||||
// Double release is noop.
|
||||
return true;
|
||||
}
|
||||
|
||||
// Release the key pressed.
|
||||
keys_pressed_.erase(iter);
|
||||
|
||||
// Update all corresponding controls.
|
||||
for (const GameControl& game_control : game_keys->second) {
|
||||
auto active_controls = active_controls_.find(game_control);
|
||||
if (active_controls == active_controls_.end()) {
|
||||
// This should never happen.
|
||||
assert(false);
|
||||
return true;
|
||||
}
|
||||
|
||||
active_controls->second.erase(user_input);
|
||||
if (active_controls->second.empty()) {
|
||||
// Actually release control.
|
||||
active_controls_.erase(active_controls);
|
||||
joypads_[game_control.joypad_] &=
|
||||
~kBitMask[GameKeyToInt(game_control.game_key_)];
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void GameControlState::Reset() {
|
||||
active_controls_.clear();
|
||||
keys_pressed_.clear();
|
||||
joypads_.fill(0);
|
||||
}
|
||||
|
||||
void GameControlState::OnGameBindingsChanged() {
|
||||
// We should reset to ensure no key remains accidentally pressed following a
|
||||
// configuration change.
|
||||
Reset();
|
||||
|
||||
input_bindings_.clear();
|
||||
for (const auto& iter : gopts.game_control_bindings) {
|
||||
for (const auto& user_input : iter.second) {
|
||||
input_bindings_[user_input].emplace(iter.first);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t GameControlState::GetJoypad(int joypad) const {
|
||||
assert(JoypadInRange(joypad));
|
||||
return joypads_[joypad];
|
||||
}
|
||||
|
||||
} // namespace config
|
|
@ -0,0 +1,144 @@
|
|||
#ifndef VBAM_WX_CONFIG_GAME_CONTROL_H_
|
||||
#define VBAM_WX_CONFIG_GAME_CONTROL_H_
|
||||
|
||||
#include <array>
|
||||
#include <map>
|
||||
#include "nonstd/optional.hpp"
|
||||
#include <set>
|
||||
#include <wx/string.h>
|
||||
|
||||
#include "config/user-input.h"
|
||||
|
||||
namespace config {
|
||||
|
||||
// Forward declaration.
|
||||
class GameControlState;
|
||||
|
||||
//clang-format off
|
||||
// Represents an in-game input.
|
||||
enum class GameKey {
|
||||
Up = 0,
|
||||
Down,
|
||||
Left,
|
||||
Right,
|
||||
A,
|
||||
B,
|
||||
L,
|
||||
R,
|
||||
Select,
|
||||
Start,
|
||||
MotionUp,
|
||||
MotionDown,
|
||||
MotionLeft,
|
||||
MotionRight,
|
||||
MotionIn,
|
||||
MotionOut,
|
||||
AutoA,
|
||||
AutoB,
|
||||
Speed,
|
||||
Capture,
|
||||
Gameshark,
|
||||
Last = Gameshark
|
||||
};
|
||||
|
||||
inline constexpr int kNbGameKeys = static_cast<size_t>(GameKey::Last) + 1;
|
||||
inline constexpr int kNbJoypads = 4;
|
||||
|
||||
inline constexpr std::array<GameKey, kNbGameKeys> kAllGameKeys = {
|
||||
GameKey::Up,
|
||||
GameKey::Down,
|
||||
GameKey::Left,
|
||||
GameKey::Right,
|
||||
GameKey::A,
|
||||
GameKey::B,
|
||||
GameKey::L,
|
||||
GameKey::R,
|
||||
GameKey::Select,
|
||||
GameKey::Start,
|
||||
GameKey::MotionUp,
|
||||
GameKey::MotionDown,
|
||||
GameKey::MotionLeft,
|
||||
GameKey::MotionRight,
|
||||
GameKey::MotionIn,
|
||||
GameKey::MotionOut,
|
||||
GameKey::AutoA,
|
||||
GameKey::AutoB,
|
||||
GameKey::Speed,
|
||||
GameKey::Capture,
|
||||
GameKey::Gameshark,
|
||||
};
|
||||
//clang-format on
|
||||
|
||||
// Conversion utility method. Returns empty string on failure.
|
||||
// This is O(1).
|
||||
wxString GameKeyToString(const GameKey& game_key);
|
||||
|
||||
// Conversion utility method. Returns std::nullopt on failure.
|
||||
// This is O(log(kNbGameKeys)).
|
||||
nonstd::optional<GameKey> StringToGameKey(const wxString& input);
|
||||
|
||||
// Abstraction for an in-game control, wich is made of a player index (from 0
|
||||
// to 3), and a GameKey.
|
||||
class GameControl {
|
||||
public:
|
||||
// Converts a string to a GameControl. Returns std::nullopt on failure.
|
||||
static nonstd::optional<GameControl> FromString(const wxString& name);
|
||||
|
||||
GameControl(int joypad, GameKey game_key);
|
||||
~GameControl();
|
||||
|
||||
wxString ToString() const { return config_string_; };
|
||||
|
||||
bool operator==(const GameControl& other) const;
|
||||
bool operator!=(const GameControl& other) const;
|
||||
bool operator<(const GameControl& other) const;
|
||||
bool operator<=(const GameControl& other) const;
|
||||
bool operator>(const GameControl& other) const;
|
||||
bool operator>=(const GameControl& other) const;
|
||||
|
||||
private:
|
||||
const int joypad_;
|
||||
const GameKey game_key_;
|
||||
const wxString config_string_;
|
||||
|
||||
friend class GameControlState;
|
||||
};
|
||||
|
||||
// Tracks in-game input and computes the joypad value used to send control input
|
||||
// data to the emulator.
|
||||
class GameControlState {
|
||||
public:
|
||||
// This is a global singleton.
|
||||
static GameControlState& Instance();
|
||||
|
||||
// Disable copy constructor and assignment operator.
|
||||
GameControlState(const GameControlState&) = delete;
|
||||
GameControlState& operator=(const GameControlState&) = delete;
|
||||
|
||||
// Processes `user_input` and updates the internal tracking state.
|
||||
// Returns true if `user_input` corresponds to a game input.
|
||||
bool OnInputPressed(const config::UserInput& user_input);
|
||||
bool OnInputReleased(const config::UserInput& user_input);
|
||||
|
||||
// Clears all input.
|
||||
void Reset();
|
||||
|
||||
// Recomputes internal bindinds. This is a potentially slow operation and
|
||||
// should only be called when the game input configuration has been changed.
|
||||
void OnGameBindingsChanged();
|
||||
|
||||
uint32_t GetJoypad(int joypad) const;
|
||||
|
||||
private:
|
||||
GameControlState();
|
||||
~GameControlState();
|
||||
|
||||
std::map<config::UserInput, std::set<GameControl>> input_bindings_;
|
||||
std::map<GameControl, std::set<config::UserInput>> active_controls_;
|
||||
std::set<config::UserInput> keys_pressed_;
|
||||
std::array<uint32_t, kNbJoypads> joypads_;
|
||||
};
|
||||
|
||||
} // namespace config
|
||||
|
||||
#endif // VBAM_WX_CONFIG_GAME_CONTROL_H_
|
|
@ -0,0 +1,873 @@
|
|||
#include "config/option.h"
|
||||
|
||||
// Helper implementation file to define and compile all of these huge constants
|
||||
// separately. These should not be updated very often, so having these in a
|
||||
// separate file improves incremental build time.
|
||||
|
||||
#include <wx/log.h>
|
||||
#include <algorithm>
|
||||
|
||||
#include "../common/ConfigManager.h"
|
||||
#include "../gb/gbGlobals.h"
|
||||
#include "opts.h"
|
||||
|
||||
#define VBAM_OPTION_INTERNAL_INCLUDE
|
||||
#include "config/internal/option-internal.h"
|
||||
#undef VBAM_OPTION_INTERNAL_INCLUDE
|
||||
|
||||
namespace config {
|
||||
|
||||
namespace {
|
||||
|
||||
// clang-format off
|
||||
// This enum must be kept in sync with the one in wxvbam.h
|
||||
// TODO: These 2 enums should be unified and a validator created for this enum.
|
||||
enum class FilterFunction {
|
||||
kNone,
|
||||
k2xsai,
|
||||
kSuper2xsai,
|
||||
kSupereagle,
|
||||
kPixelate,
|
||||
kAdvmame,
|
||||
kBilinear,
|
||||
kBilinearplus,
|
||||
kScanlines,
|
||||
kTvmode,
|
||||
kHQ2x,
|
||||
kLQ2x,
|
||||
kSimple2x,
|
||||
kSimple3x,
|
||||
kHQ3x,
|
||||
kSimple4x,
|
||||
kHQ4x,
|
||||
kXbrz2x,
|
||||
kXbrz3x,
|
||||
kXbrz4x,
|
||||
kXbrz5x,
|
||||
kXbrz6x,
|
||||
kPlugin, // This must always be last.
|
||||
|
||||
// Do not add anything under here.
|
||||
kLast,
|
||||
};
|
||||
constexpr size_t kNbFilterFunctions = static_cast<size_t>(FilterFunction::kLast);
|
||||
|
||||
// These MUST follow the same order as the definitions of the enum above.
|
||||
// Adding an option without adding to this array will result in a compiler
|
||||
// error since kNbFilterFunctions is automatically updated.
|
||||
static const std::array<wxString, kNbFilterFunctions> kFilterStrings = {
|
||||
"none",
|
||||
"2xsai",
|
||||
"super2xsai",
|
||||
"supereagle",
|
||||
"pixelate",
|
||||
"advmame",
|
||||
"bilinear",
|
||||
"bilinearplus",
|
||||
"scanlines",
|
||||
"tvmode",
|
||||
"hq2x",
|
||||
"lq2x",
|
||||
"simple2x",
|
||||
"simple3x",
|
||||
"hq3x",
|
||||
"simple4x",
|
||||
"hq4x",
|
||||
"xbrz2x",
|
||||
"xbrz3x",
|
||||
"xbrz4x",
|
||||
"xbrz5x",
|
||||
"xbrz6x",
|
||||
"plugin",
|
||||
};
|
||||
|
||||
// This enum must be kept in sync with the one in wxvbam.h
|
||||
// TODO: These 2 enums should be unified and a validator created for this enum.
|
||||
enum class Interframe {
|
||||
kNone = 0,
|
||||
kSmart,
|
||||
kMotionBlur,
|
||||
|
||||
// Do not add anything under here.
|
||||
kLast,
|
||||
};
|
||||
constexpr size_t kNbInterframes = static_cast<size_t>(Interframe::kLast);
|
||||
|
||||
// These MUST follow the same order as the definitions of the enum above.
|
||||
// Adding an option without adding to this array will result in a compiler
|
||||
// error since kNbInterframes is automatically updated.
|
||||
static const std::array<wxString, kNbInterframes> kInterframeStrings = {
|
||||
"none",
|
||||
"smart",
|
||||
"motionblur",
|
||||
};
|
||||
|
||||
// This enum must be kept in sync with the one in wxvbam.h
|
||||
// TODO: These 2 enums should be unified and a validator created for this enum.
|
||||
enum class RenderMethod {
|
||||
kSimple = 0,
|
||||
kOpenGL,
|
||||
#ifdef __WXMSW__
|
||||
kDirect3d,
|
||||
#elif defined(__WXMAC__)
|
||||
kQuartz2d,
|
||||
#endif
|
||||
|
||||
// Do not add anything under here.
|
||||
kLast,
|
||||
};
|
||||
constexpr size_t kNbRenderMethods = static_cast<size_t>(RenderMethod::kLast);
|
||||
|
||||
// These MUST follow the same order as the definitions of the enum above.
|
||||
// Adding an option without adding to this array will result in a compiler
|
||||
// error since kNbRenderMethods is automatically updated.
|
||||
static const std::array<wxString, kNbRenderMethods> kRenderMethodStrings = {
|
||||
"simple",
|
||||
"opengl",
|
||||
#ifdef __WXMSW__
|
||||
"direct3d",
|
||||
#elif defined(__WXMAC__)
|
||||
"quartz2d",
|
||||
#endif
|
||||
};
|
||||
|
||||
// This enum must be kept in sync with the one in wxvbam.h
|
||||
// TODO: These 2 enums should be unified and a validator created for this enum.
|
||||
// TODO: DirectSound and XAudio2 should only be used on Windows.
|
||||
enum class AudioApi {
|
||||
kSdl = 0,
|
||||
kOpenAL,
|
||||
kDirectSound,
|
||||
kXAudio2,
|
||||
kFaudio,
|
||||
|
||||
// Do not add anything under here.
|
||||
kLast,
|
||||
};
|
||||
constexpr size_t kNbAudioApis = static_cast<size_t>(AudioApi::kLast);
|
||||
|
||||
// These MUST follow the same order as the definitions of the enum above.
|
||||
// Adding an option without adding to this array will result in a compiler
|
||||
// error since kNbAudioApis is automatically updated.
|
||||
static const std::array<wxString, kNbAudioApis> kAudioApiStrings = {
|
||||
"sdl",
|
||||
"openal",
|
||||
"directsound",
|
||||
"xaudio2",
|
||||
"faudio",
|
||||
};
|
||||
|
||||
enum class SoundQuality {
|
||||
k48kHz = 0,
|
||||
k44kHz,
|
||||
k22kHz,
|
||||
k11kHz,
|
||||
|
||||
// Do not add anything under here.
|
||||
kLast,
|
||||
};
|
||||
constexpr size_t kNbSoundQualities = static_cast<size_t>(SoundQuality::kLast);
|
||||
|
||||
// These MUST follow the same order as the definitions of the enum above.
|
||||
// Adding an option without adding to this array will result in a compiler
|
||||
// error since kNbSoundQualities is automatically updated.
|
||||
static const std::array<wxString, kNbSoundQualities> kSoundQualityStrings = {
|
||||
"48",
|
||||
"44",
|
||||
"22",
|
||||
"11",
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
// Builds the "all enum values" string for a given array defined above.
|
||||
template <std::size_t SIZE>
|
||||
wxString AllEnumValuesForArray(const std::array<wxString, SIZE>& input) {
|
||||
// 15 characters per option is a reasonable higher bound. Probably.
|
||||
static constexpr size_t kMaxOptionLength = 15u;
|
||||
|
||||
wxString all_options;
|
||||
all_options.reserve(kMaxOptionLength * SIZE);
|
||||
|
||||
std::for_each(input.cbegin(), input.cend(),
|
||||
[&all_options](const auto& elt) {
|
||||
all_options.append(elt);
|
||||
all_options.append('|');
|
||||
});
|
||||
// Remove last value
|
||||
all_options.RemoveLast(1u);
|
||||
return all_options;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
// static
|
||||
std::array<Option, kNbOptions>& Option::AllOptions() {
|
||||
// These MUST follow the same order as the definitions in OptionID.
|
||||
// Adding an option without adding to this array will result in a compiler
|
||||
// error since kNbOptions is automatically updated.
|
||||
// This will be initialized on the first call, in load_opts(), ensuring the
|
||||
// translation initialization has already happened.
|
||||
static std::array<Option, kNbOptions> g_all_opts = {
|
||||
/// Display
|
||||
Option(OptionID::kDisplayBilinear, &gopts.bilinear),
|
||||
Option(OptionID::kDisplayFilter, &gopts.filter),
|
||||
Option(OptionID::kDisplayFilterPlugin, &gopts.filter_plugin),
|
||||
Option(OptionID::kDisplayIFB, &gopts.ifb),
|
||||
Option(OptionID::kDisplayKeepOnTop, &gopts.keep_on_top),
|
||||
Option(OptionID::kDisplayMaxThreads, &gopts.max_threads, 1, 256),
|
||||
Option(OptionID::kDisplayRenderMethod, &gopts.render_method),
|
||||
Option(OptionID::kDisplayScale, &gopts.video_scale, 1, 6),
|
||||
Option(OptionID::kDisplayStretch, &gopts.retain_aspect),
|
||||
|
||||
/// GB
|
||||
Option(OptionID::kGBBiosFile, &gopts.gb_bios),
|
||||
Option(OptionID::kGBColorOption, &gbColorOption, 0, 1),
|
||||
Option(OptionID::kGBColorizerHack, &colorizerHack, 0, 1),
|
||||
Option(OptionID::kGBLCDFilter, &gbLcdFilter),
|
||||
Option(OptionID::kGBGBCBiosFile, &gopts.gbc_bios),
|
||||
Option(OptionID::kGBPalette0, systemGbPalette),
|
||||
Option(OptionID::kGBPalette1, systemGbPalette + 8),
|
||||
Option(OptionID::kGBPalette2, systemGbPalette + 16),
|
||||
Option(OptionID::kGBPrintAutoPage, &gopts.print_auto_page),
|
||||
Option(OptionID::kGBPrintScreenCap, &gopts.print_screen_cap),
|
||||
Option(OptionID::kGBROMDir, &gopts.gb_rom_dir),
|
||||
Option(OptionID::kGBGBCROMDir, &gopts.gbc_rom_dir),
|
||||
|
||||
/// GBA
|
||||
Option(OptionID::kGBABiosFile, &gopts.gba_bios),
|
||||
Option(OptionID::kGBALCDFilter, &gbaLcdFilter),
|
||||
#ifndef NO_LINK
|
||||
Option(OptionID::kGBALinkAuto, &gopts.link_auto),
|
||||
Option(OptionID::kGBALinkFast, &linkHacks, 0, 1),
|
||||
Option(OptionID::kGBALinkHost, &gopts.link_host),
|
||||
Option(OptionID::kGBAServerIP, &gopts.server_ip),
|
||||
Option(OptionID::kGBALinkPort, &gopts.link_port, 0, 65535),
|
||||
Option(OptionID::kGBALinkProto, &gopts.link_proto, 0, 1),
|
||||
Option(OptionID::kGBALinkTimeout, &linkTimeout, 0, 9999999),
|
||||
Option(OptionID::kGBALinkType, &gopts.gba_link_type, 0, 5),
|
||||
#endif
|
||||
Option(OptionID::kGBAROMDir, &gopts.gba_rom_dir),
|
||||
|
||||
/// General
|
||||
Option(OptionID::kGeneralAutoLoadLastState, &gopts.autoload_state),
|
||||
Option(OptionID::kGeneralBatteryDir, &gopts.battery_dir),
|
||||
Option(OptionID::kGeneralFreezeRecent, &gopts.recent_freeze),
|
||||
Option(OptionID::kGeneralRecordingDir, &gopts.recording_dir),
|
||||
Option(OptionID::kGeneralRewindInterval, &gopts.rewind_interval, 0,
|
||||
600),
|
||||
Option(OptionID::kGeneralScreenshotDir, &gopts.scrshot_dir),
|
||||
Option(OptionID::kGeneralStateDir, &gopts.state_dir),
|
||||
Option(OptionID::kGeneralStatusBar, &gopts.statusbar, 0, 1),
|
||||
|
||||
/// Joypad
|
||||
Option(OptionID::kJoypad),
|
||||
Option(OptionID::kJoypadAutofireThrottle, &gopts.autofire_rate, 1,
|
||||
1000),
|
||||
Option(OptionID::kJoypadDefault, &gopts.default_stick, 1, 4),
|
||||
|
||||
/// Keyboard
|
||||
Option(OptionID::kKeyboard),
|
||||
|
||||
// Core
|
||||
Option(OptionID::kpreferencesagbPrint, &agbPrint, 0, 1),
|
||||
Option(OptionID::kpreferencesautoFrameSkip, &autoFrameSkip, 0, 1),
|
||||
Option(OptionID::kpreferencesautoPatch, &autoPatch, 0, 1),
|
||||
Option(OptionID::kpreferencesautoSaveLoadCheatList,
|
||||
&gopts.autoload_cheats),
|
||||
Option(OptionID::kpreferencesborderAutomatic, &gbBorderAutomatic, 0, 1),
|
||||
Option(OptionID::kpreferencesborderOn, &gbBorderOn, 0, 1),
|
||||
Option(OptionID::kpreferencescaptureFormat, &captureFormat, 0, 1),
|
||||
Option(OptionID::kpreferencescheatsEnabled, &cheatsEnabled, 0, 1),
|
||||
#ifdef MMX
|
||||
Option(OptionID::kpreferencesenableMMX, &enableMMX, 0, 1),
|
||||
#endif
|
||||
Option(OptionID::kpreferencesdisableStatus, &disableStatusMessages, 0,
|
||||
1),
|
||||
Option(OptionID::kpreferencesemulatorType, &gbEmulatorType, 0, 5),
|
||||
Option(OptionID::kpreferencesflashSize, &optFlashSize, 0, 1),
|
||||
Option(OptionID::kpreferencesframeSkip, &frameSkip, -1, 9),
|
||||
Option(OptionID::kpreferencesfsColorDepth, &fsColorDepth, 0, 999),
|
||||
Option(OptionID::kpreferencesfsFrequency, &fsFrequency, 0, 999),
|
||||
Option(OptionID::kpreferencesfsHeight, &fsHeight, 0, 99999),
|
||||
Option(OptionID::kpreferencesfsWidth, &fsWidth, 0, 99999),
|
||||
Option(OptionID::kpreferencesgbPaletteOption, &gbPaletteOption, 0, 2),
|
||||
Option(OptionID::kpreferencesgbPrinter, &winGbPrinterEnabled, 0, 1),
|
||||
Option(OptionID::kpreferencesgdbBreakOnLoad, &gdbBreakOnLoad, 0, 1),
|
||||
Option(OptionID::kpreferencesgdbPort, &gdbPort, 0, 65535),
|
||||
#ifndef NO_LINK
|
||||
Option(OptionID::kpreferencesLinkNumPlayers, &linkNumPlayers, 2, 4),
|
||||
#endif
|
||||
Option(OptionID::kpreferencesmaxScale, &maxScale, 0, 100),
|
||||
Option(OptionID::kpreferencespauseWhenInactive, &pauseWhenInactive, 0,
|
||||
1),
|
||||
Option(OptionID::kpreferencesrtcEnabled, &rtcEnabled, 0, 1),
|
||||
Option(OptionID::kpreferencessaveType, &cpuSaveType, 0, 5),
|
||||
Option(OptionID::kpreferencesshowSpeed, &showSpeed, 0, 2),
|
||||
Option(OptionID::kpreferencesshowSpeedTransparent,
|
||||
&showSpeedTransparent, 0, 1),
|
||||
Option(OptionID::kpreferencesskipBios, &skipBios, 0, 1),
|
||||
Option(OptionID::kpreferencesskipSaveGameCheats, &skipSaveGameCheats, 0,
|
||||
1),
|
||||
Option(OptionID::kpreferencesskipSaveGameBattery, &skipSaveGameBattery,
|
||||
0, 1),
|
||||
Option(OptionID::kpreferencesthrottle, &throttle, 0, 450),
|
||||
Option(OptionID::kpreferencesspeedupThrottle, &speedup_throttle, 0,
|
||||
3000),
|
||||
Option(OptionID::kpreferencesspeedupFrameSkip, &speedup_frame_skip, 0,
|
||||
300),
|
||||
Option(OptionID::kpreferencesspeedupThrottleFrameSkip,
|
||||
&speedup_throttle_frame_skip),
|
||||
Option(OptionID::kpreferencesuseBiosGB, &useBiosFileGB, 0, 1),
|
||||
Option(OptionID::kpreferencesuseBiosGBA, &useBiosFileGBA, 0, 1),
|
||||
Option(OptionID::kpreferencesuseBiosGBC, &useBiosFileGBC, 0, 1),
|
||||
Option(OptionID::kpreferencesvsync, &vsync, 0, 1),
|
||||
|
||||
/// Geometry
|
||||
Option(OptionID::kgeometryfullScreen, &fullScreen, 0, 1),
|
||||
Option(OptionID::kgeometryisMaximized, &windowMaximized, 0, 1),
|
||||
Option(OptionID::kgeometrywindowHeight, &windowHeight, 0, 99999),
|
||||
Option(OptionID::kgeometrywindowWidth, &windowWidth, 0, 99999),
|
||||
Option(OptionID::kgeometrywindowX, &windowPositionX, -1, 99999),
|
||||
Option(OptionID::kgeometrywindowY, &windowPositionY, -1, 99999),
|
||||
|
||||
/// UI
|
||||
Option(OptionID::kuiallowKeyboardBackgroundInput,
|
||||
&allowKeyboardBackgroundInput),
|
||||
Option(OptionID::kuiallowJoystickBackgroundInput,
|
||||
&allowJoystickBackgroundInput),
|
||||
Option(OptionID::kuihideMenuBar, &gopts.hide_menu_bar),
|
||||
|
||||
/// Sound
|
||||
Option(OptionID::kSoundAudioAPI, &gopts.audio_api),
|
||||
Option(OptionID::kSoundAudioDevice, &gopts.audio_dev),
|
||||
Option(OptionID::kSoundBuffers, &gopts.audio_buffers, 2, 10),
|
||||
Option(OptionID::kSoundEnable, &gopts.sound_en, 0, 0x30f),
|
||||
Option(OptionID::kSoundGBAFiltering, &gopts.gba_sound_filter, 0, 100),
|
||||
Option(OptionID::kSoundGBAInterpolation, &gopts.soundInterpolation),
|
||||
Option(OptionID::kSoundGBDeclicking, &gopts.gb_declick),
|
||||
Option(OptionID::kSoundGBEcho, &gopts.gb_echo, 0, 100),
|
||||
Option(OptionID::kSoundGBEnableEffects,
|
||||
&gopts.gb_effects_config_enabled),
|
||||
Option(OptionID::kSoundGBStereo, &gopts.gb_stereo, 0, 100),
|
||||
Option(OptionID::kSoundGBSurround, &gopts.gb_effects_config_surround),
|
||||
Option(OptionID::kSoundQuality, &gopts.sound_qual),
|
||||
Option(OptionID::kSoundVolume, &gopts.sound_vol, 0, 200),
|
||||
};
|
||||
return g_all_opts;
|
||||
}
|
||||
|
||||
namespace internal {
|
||||
|
||||
// These MUST follow the same order as the definitions in OptionID.
|
||||
// Adding an option without adding to this array will result in a compiler
|
||||
// error since kNbOptions is automatically updated.
|
||||
const std::array<OptionData, kNbOptions + 1> kAllOptionsData = {
|
||||
/// Display
|
||||
OptionData{"Display/Bilinear", "Bilinear",
|
||||
_("Use bilinear filter with 3d renderer"), Option::Type::kBool},
|
||||
OptionData{"Display/Filter", "", _("Full-screen filter to apply"),
|
||||
Option::Type::kFilter},
|
||||
OptionData{"Display/FilterPlugin", "", _("Filter plugin library"),
|
||||
Option::Type::kString},
|
||||
OptionData{"Display/IFB", "", _("Interframe blending function"),
|
||||
Option::Type::kInterframe},
|
||||
OptionData{"Display/KeepOnTop", "KeepOnTop", _("Keep window on top"),
|
||||
Option::Type::kBool},
|
||||
OptionData{"Display/MaxThreads", "Multithread",
|
||||
_("Maximum number of threads to run filters in"),
|
||||
Option::Type::kInt},
|
||||
OptionData{"Display/RenderMethod", "",
|
||||
_("Render method; if unsupported, simple method will be used"),
|
||||
Option::Type::kRenderMethod},
|
||||
OptionData{"Display/Scale", "", _("Default scale factor"),
|
||||
Option::Type::kDouble},
|
||||
OptionData{"Display/Stretch", "RetainAspect",
|
||||
_("Retain aspect ratio when resizing"), Option::Type::kBool},
|
||||
|
||||
/// GB
|
||||
OptionData{"GB/BiosFile", "", _("BIOS file to use for GB, if enabled"),
|
||||
Option::Type::kString},
|
||||
OptionData{"GB/ColorOption", "GBColorOption",
|
||||
_("GB color enhancement, if enabled"), Option::Type::kInt},
|
||||
OptionData{"GB/ColorizerHack", "ColorizerHack",
|
||||
_("Enable DX Colorization Hacks"), Option::Type::kInt},
|
||||
OptionData{"GB/LCDFilter", "GBLcdFilter", _("Apply LCD filter, if enabled"),
|
||||
Option::Type::kBool},
|
||||
OptionData{"GB/GBCBiosFile", "", _("BIOS file to use for GBC, if enabled"),
|
||||
Option::Type::kString},
|
||||
OptionData{"GB/Palette0", "",
|
||||
_("The default palette, as 8 comma-separated 4-digit hex "
|
||||
"integers (rgb555)."),
|
||||
Option::Type::kGbPalette},
|
||||
OptionData{"GB/Palette1", "",
|
||||
_("The first user palette, as 8 comma-separated 4-digit hex "
|
||||
"integers (rgb555)."),
|
||||
Option::Type::kGbPalette},
|
||||
OptionData{"GB/Palette2", "",
|
||||
_("The second user palette, as 8 comma-separated 4-digit hex "
|
||||
"integers (rgb555)."),
|
||||
Option::Type::kGbPalette},
|
||||
OptionData{"GB/PrintAutoPage", "PrintGather",
|
||||
_("Automatically gather a full page before printing"),
|
||||
Option::Type::kBool},
|
||||
OptionData{
|
||||
"GB/PrintScreenCap", "PrintSnap",
|
||||
_("Automatically save printouts as screen captures with -print suffix"),
|
||||
Option::Type::kBool},
|
||||
OptionData{"GB/ROMDir", "", _("Directory to look for ROM files"),
|
||||
Option::Type::kString},
|
||||
OptionData{"GB/GBCROMDir", "", _("Directory to look for GBC ROM files"),
|
||||
Option::Type::kString},
|
||||
|
||||
/// GBA
|
||||
OptionData{"GBA/BiosFile", "", _("BIOS file to use, if enabled"),
|
||||
Option::Type::kString},
|
||||
OptionData{"GBA/LCDFilter", "GBALcdFilter",
|
||||
_("Apply LCD filter, if enabled"), Option::Type::kBool},
|
||||
#ifndef NO_LINK
|
||||
OptionData{"GBA/LinkAuto", "LinkAuto", _("Enable link at boot"),
|
||||
Option::Type::kBool},
|
||||
OptionData{"GBA/LinkFast", "SpeedOn",
|
||||
_("Enable faster network protocol by default"),
|
||||
Option::Type::kInt},
|
||||
OptionData{"GBA/LinkHost", "", _("Default network link client host"),
|
||||
Option::Type::kString},
|
||||
OptionData{"GBA/ServerIP", "", _("Default network link server IP to bind"),
|
||||
Option::Type::kString},
|
||||
OptionData{"GBA/LinkPort", "",
|
||||
_("Default network link port (server and client)"),
|
||||
Option::Type::kUnsigned},
|
||||
OptionData{"GBA/LinkProto", "LinkProto", _("Default network protocol"),
|
||||
Option::Type::kInt},
|
||||
OptionData{"GBA/LinkTimeout", "LinkTimeout", _("Link timeout (ms)"),
|
||||
Option::Type::kInt},
|
||||
OptionData{"GBA/LinkType", "LinkType", _("Link cable type"),
|
||||
Option::Type::kInt},
|
||||
#endif
|
||||
OptionData{"GBA/ROMDir", "", _("Directory to look for ROM files"),
|
||||
Option::Type::kString},
|
||||
|
||||
/// General
|
||||
OptionData{"General/AutoLoadLastState", "",
|
||||
_("Automatically load last saved state"), Option::Type::kBool},
|
||||
OptionData{"General/BatteryDir", "",
|
||||
_("Directory to store game save files (relative paths are "
|
||||
"relative to ROM; blank is config dir)"),
|
||||
Option::Type::kString},
|
||||
OptionData{"General/FreezeRecent", "", _("Freeze recent load list"),
|
||||
Option::Type::kBool},
|
||||
OptionData{"General/RecordingDir", "",
|
||||
_("Directory to store A/V and game recordings (relative paths "
|
||||
"are relative to ROM)"),
|
||||
Option::Type::kString},
|
||||
OptionData{"General/RewindInterval", "",
|
||||
_("Number of seconds between rewind snapshots (0 to disable)"),
|
||||
Option::Type::kInt},
|
||||
OptionData{"General/ScreenshotDir", "",
|
||||
_("Directory to store screenshots (relative paths are relative "
|
||||
"to ROM)"),
|
||||
Option::Type::kString},
|
||||
OptionData{"General/StateDir", "",
|
||||
_("Directory to store saved state files (relative paths are "
|
||||
"relative to BatteryDir)"),
|
||||
Option::Type::kString},
|
||||
OptionData{"General/StatusBar", "StatusBar", _("Enable status bar"),
|
||||
Option::Type::kInt},
|
||||
|
||||
/// Joypad
|
||||
OptionData{"Joypad/*/*", "",
|
||||
_("The parameter Joypad/<n>/<button> contains a comma-separated "
|
||||
"list of key names which map to joypad #<n> button <button>. "
|
||||
"Button is one of Up, Down, Left, Right, A, B, L, R, Select, "
|
||||
"Start, MotionUp, MotionDown, MotionLeft, MotionRight, AutoA, "
|
||||
"AutoB, Speed, Capture, GS"),
|
||||
Option::Type::kNone},
|
||||
OptionData{"Joypad/AutofireThrottle", "",
|
||||
_("The autofire toggle period, in frames (1/60 s)"),
|
||||
Option::Type::kInt},
|
||||
OptionData{"Joypad/Default", "",
|
||||
_("The number of the stick to use in single-player mode"),
|
||||
Option::Type::kInt},
|
||||
|
||||
/// Keyboard
|
||||
OptionData{"Keyboard/*", "",
|
||||
_("The parameter Keyboard/<cmd> contains a comma-separated list "
|
||||
"of key names (e.g. Alt-Shift-F1). When the named key is "
|
||||
"pressed, the command <cmd> is executed."),
|
||||
Option::Type::kNone},
|
||||
|
||||
// Core
|
||||
OptionData{"preferences/agbPrint", "AGBPrinter",
|
||||
_("Enable AGB debug print"), Option::Type::kInt},
|
||||
OptionData{"preferences/autoFrameSkip", "FrameSkipAuto",
|
||||
_("Auto skip frames."), Option::Type::kInt},
|
||||
OptionData{"preferences/autoPatch", "ApplyPatches",
|
||||
_("Apply IPS/UPS/IPF patches if found"), Option::Type::kInt},
|
||||
OptionData{"preferences/autoSaveLoadCheatList", "",
|
||||
_("Automatically save and load cheat list"),
|
||||
Option::Type::kBool},
|
||||
OptionData{"preferences/borderAutomatic", "",
|
||||
_("Automatically enable border for Super GameBoy games"),
|
||||
Option::Type::kInt},
|
||||
OptionData{"preferences/borderOn", "", _("Always enable border"),
|
||||
Option::Type::kInt},
|
||||
OptionData{"preferences/captureFormat", "", _("Screen capture file format"),
|
||||
Option::Type::kInt},
|
||||
OptionData{"preferences/cheatsEnabled", "", _("Enable cheats"),
|
||||
Option::Type::kInt},
|
||||
#ifdef MMX
|
||||
OptionData{"preferences/enableMMX", "MMX", _("Enable MMX"),
|
||||
Option::Type::kInt},
|
||||
#endif
|
||||
OptionData{"preferences/disableStatus", "NoStatusMsg",
|
||||
_("Disable on-screen status messages"), Option::Type::kInt},
|
||||
OptionData{"preferences/emulatorType", "", _("Type of system to emulate"),
|
||||
Option::Type::kInt},
|
||||
OptionData{"preferences/flashSize", "", _("Flash size 0 = 64KB 1 = 128KB"),
|
||||
Option::Type::kInt},
|
||||
OptionData{"preferences/frameSkip", "FrameSkip",
|
||||
_("Skip frames. Values are 0-9 or -1 to skip automatically "
|
||||
"based on time."),
|
||||
Option::Type::kInt},
|
||||
OptionData{"preferences/fsColorDepth", "",
|
||||
_("Fullscreen mode color depth (0 = any)"), Option::Type::kInt},
|
||||
OptionData{"preferences/fsFrequency", "",
|
||||
_("Fullscreen mode frequency (0 = any)"), Option::Type::kInt},
|
||||
OptionData{"preferences/fsHeight", "",
|
||||
_("Fullscreen mode height (0 = desktop)"), Option::Type::kInt},
|
||||
OptionData{"preferences/fsWidth", "",
|
||||
_("Fullscreen mode width (0 = desktop)"), Option::Type::kInt},
|
||||
OptionData{"preferences/gbPaletteOption", "", _("The palette to use"),
|
||||
Option::Type::kInt},
|
||||
OptionData{"preferences/gbPrinter", "Printer",
|
||||
_("Enable printer emulation"), Option::Type::kInt},
|
||||
OptionData{"preferences/gdbBreakOnLoad", "DebugGDBBreakOnLoad",
|
||||
_("Break into GDB after loading the game."), Option::Type::kInt},
|
||||
OptionData{"preferences/gdbPort", "DebugGDBPort",
|
||||
_("Port to connect GDB to."), Option::Type::kInt},
|
||||
#ifndef NO_LINK
|
||||
OptionData{"preferences/LinkNumPlayers", "",
|
||||
_("Number of players in network"), Option::Type::kInt},
|
||||
#endif
|
||||
OptionData{"preferences/maxScale", "",
|
||||
_("Maximum scale factor (0 = no limit)"), Option::Type::kInt},
|
||||
OptionData{"preferences/pauseWhenInactive", "PauseWhenInactive",
|
||||
_("Pause game when main window loses focus"),
|
||||
Option::Type::kInt},
|
||||
OptionData{"preferences/rtcEnabled", "RTC",
|
||||
_("Enable RTC (vba-over.ini override is rtcEnabled"),
|
||||
Option::Type::kInt},
|
||||
OptionData{"preferences/saveType", "",
|
||||
_("Native save (\"battery\") hardware type"),
|
||||
Option::Type::kInt},
|
||||
OptionData{"preferences/showSpeed", "", _("Show speed indicator"),
|
||||
Option::Type::kInt},
|
||||
OptionData{"preferences/showSpeedTransparent", "Transparent",
|
||||
_("Draw on-screen messages transparently"), Option::Type::kInt},
|
||||
OptionData{"preferences/skipBios", "SkipIntro",
|
||||
_("Skip BIOS initialization"), Option::Type::kInt},
|
||||
OptionData{"preferences/skipSaveGameCheats", "",
|
||||
_("Do not overwrite cheat list when loading state"),
|
||||
Option::Type::kInt},
|
||||
OptionData{"preferences/skipSaveGameBattery", "",
|
||||
_("Do not overwrite native (battery) save when loading state"),
|
||||
Option::Type::kInt},
|
||||
OptionData{"preferences/throttle", "",
|
||||
_("Throttle game speed, even when accelerated (0-450%, 0 = no "
|
||||
"throttle)"),
|
||||
Option::Type::kUnsigned},
|
||||
OptionData{"preferences/speedupThrottle", "",
|
||||
_("Set throttle for speedup key (0-3000%, 0 = no throttle)"),
|
||||
Option::Type::kUnsigned},
|
||||
OptionData{"preferences/speedupFrameSkip", "",
|
||||
_("Number of frames to skip with speedup (instead of speedup "
|
||||
"throttle)"),
|
||||
Option::Type::kUnsigned},
|
||||
OptionData{"preferences/speedupThrottleFrameSkip", "",
|
||||
_("Use frame skip for speedup throttle"), Option::Type::kBool},
|
||||
OptionData{"preferences/useBiosGB", "BootRomGB",
|
||||
_("Use the specified BIOS file for GB"), Option::Type::kInt},
|
||||
OptionData{"preferences/useBiosGBA", "BootRomEn",
|
||||
_("Use the specified BIOS file"), Option::Type::kInt},
|
||||
OptionData{"preferences/useBiosGBC", "BootRomGBC",
|
||||
_("Use the specified BIOS file for GBC"), Option::Type::kInt},
|
||||
OptionData{"preferences/vsync", "VSync", _("Wait for vertical sync"),
|
||||
Option::Type::kInt},
|
||||
|
||||
/// Geometry
|
||||
OptionData{"geometry/fullScreen", "Fullscreen",
|
||||
_("Enter fullscreen mode at startup"), Option::Type::kInt},
|
||||
OptionData{"geometry/isMaximized", "Maximized", _("Window maximized"),
|
||||
Option::Type::kInt},
|
||||
OptionData{"geometry/windowHeight", "Height", _("Window height at startup"),
|
||||
Option::Type::kUnsigned},
|
||||
OptionData{"geometry/windowWidth", "Width", _("Window width at startup"),
|
||||
Option::Type::kUnsigned},
|
||||
OptionData{"geometry/windowX", "X", _("Window axis X position at startup"),
|
||||
Option::Type::kInt},
|
||||
OptionData{"geometry/windowY", "Y", _("Window axis Y position at startup"),
|
||||
Option::Type::kInt},
|
||||
|
||||
/// UI
|
||||
OptionData{
|
||||
"ui/allowKeyboardBackgroundInput", "AllowKeyboardBackgroundInput",
|
||||
_("Capture key events while on background"), Option::Type::kBool},
|
||||
OptionData{
|
||||
"ui/allowJoystickBackgroundInput", "AllowJoystickBackgroundInput",
|
||||
_("Capture joy events while on background"), Option::Type::kBool},
|
||||
OptionData{"ui/hideMenuBar", "", _("Hide menu bar when mouse is inactive"),
|
||||
Option::Type::kBool},
|
||||
|
||||
/// Sound
|
||||
OptionData{"Sound/AudioAPI", "",
|
||||
_("Sound API; if unsupported, default API will be used"),
|
||||
Option::Type::kAudioApi},
|
||||
OptionData{"Sound/AudioDevice", "",
|
||||
_("Device ID of chosen audio device for chosen driver"),
|
||||
Option::Type::kString},
|
||||
OptionData{"Sound/Buffers", "", _("Number of sound buffers"),
|
||||
Option::Type::kInt},
|
||||
OptionData{"Sound/Enable", "", _("Bit mask of sound channels to enable"),
|
||||
Option::Type::kInt},
|
||||
OptionData{"Sound/GBAFiltering", "", _("GBA sound filtering (%)"),
|
||||
Option::Type::kInt},
|
||||
OptionData{"Sound/GBAInterpolation", "GBASoundInterpolation",
|
||||
_("GBA sound interpolation"), Option::Type::kBool},
|
||||
OptionData{"Sound/GBDeclicking", "GBDeclicking", _("GB sound declicking"),
|
||||
Option::Type::kBool},
|
||||
OptionData{"Sound/GBEcho", "", _("GB echo effect (%)"), Option::Type::kInt},
|
||||
OptionData{"Sound/GBEnableEffects", "GBEnhanceSound",
|
||||
_("Enable GB sound effects"), Option::Type::kBool},
|
||||
OptionData{"Sound/GBStereo", "", _("GB stereo effect (%)"),
|
||||
Option::Type::kInt},
|
||||
OptionData{"Sound/GBSurround", "GBSurround",
|
||||
_("GB surround sound effect (%)"), Option::Type::kBool},
|
||||
OptionData{"Sound/Quality", "", _("Sound sample rate (kHz)"),
|
||||
Option::Type::kSoundQuality},
|
||||
OptionData{"Sound/Volume", "", _("Sound volume (%)"), Option::Type::kInt},
|
||||
|
||||
// Last. This should never be used, it actually maps to OptionID::kLast.
|
||||
// This is to prevent a memory access violation error in case something
|
||||
// attempts to instantiate a OptionID::kLast. It will trigger a check
|
||||
// in the Option constructor, but that is after the constructor has
|
||||
// accessed this entry.
|
||||
OptionData{"", "", "", Option::Type::kNone},
|
||||
};
|
||||
|
||||
nonstd::optional<OptionID> StringToOptionId(const wxString& input) {
|
||||
static std::map<wxString, OptionID> kStringToOptionId;
|
||||
if (kStringToOptionId.empty()) {
|
||||
for (size_t i = 0; i < kNbOptions; i++) {
|
||||
kStringToOptionId.emplace(kAllOptionsData[i].config_name,
|
||||
static_cast<OptionID>(i));
|
||||
}
|
||||
assert(kStringToOptionId.size() == kNbOptions);
|
||||
}
|
||||
|
||||
const auto iter = kStringToOptionId.find(input);
|
||||
if (iter == kStringToOptionId.end()) {
|
||||
return nonstd::nullopt;
|
||||
}
|
||||
return iter->second;
|
||||
}
|
||||
|
||||
wxString FilterToString(int value) {
|
||||
assert(value >= 0 && static_cast<size_t>(value) < kNbFilterFunctions);
|
||||
return kFilterStrings[value];
|
||||
}
|
||||
|
||||
wxString InterframeToString(int value) {
|
||||
assert(value >= 0 && static_cast<size_t>(value) < kNbInterframes);
|
||||
return kInterframeStrings[value];
|
||||
}
|
||||
|
||||
wxString RenderMethodToString(int value) {
|
||||
assert(value >= 0 && static_cast<size_t>(value) < kNbRenderMethods);
|
||||
return kRenderMethodStrings[value];
|
||||
}
|
||||
|
||||
wxString AudioApiToString(int value) {
|
||||
assert(value >= 0 && static_cast<size_t>(value) < kNbAudioApis);
|
||||
return kAudioApiStrings[value];
|
||||
}
|
||||
|
||||
wxString SoundQualityToString(int value) {
|
||||
assert(value >= 0 && static_cast<size_t>(value) < kNbSoundQualities);
|
||||
return kSoundQualityStrings[value];
|
||||
}
|
||||
|
||||
int StringToFilter(const wxString& config_name, const wxString& input) {
|
||||
static std::map<wxString, FilterFunction> kStringToFilter;
|
||||
if (kStringToFilter.empty()) {
|
||||
for (size_t i = 0; i < kNbFilterFunctions; i++) {
|
||||
kStringToFilter.emplace(kFilterStrings[i],
|
||||
static_cast<FilterFunction>(i));
|
||||
}
|
||||
assert(kStringToFilter.size() == kNbFilterFunctions);
|
||||
}
|
||||
|
||||
const auto iter = kStringToFilter.find(input);
|
||||
if (iter == kStringToFilter.end()) {
|
||||
wxLogWarning(_("Invalid value %s for option %s; valid values are %s"),
|
||||
input, config_name,
|
||||
AllEnumValuesForType(Option::Type::kFilter));
|
||||
return 0;
|
||||
}
|
||||
return static_cast<int>(iter->second);
|
||||
}
|
||||
|
||||
int StringToInterframe(const wxString& config_name, const wxString& input) {
|
||||
static std::map<wxString, Interframe> kStringToInterframe;
|
||||
if (kStringToInterframe.empty()) {
|
||||
for (size_t i = 0; i < kNbInterframes; i++) {
|
||||
kStringToInterframe.emplace(kInterframeStrings[i],
|
||||
static_cast<Interframe>(i));
|
||||
}
|
||||
assert(kStringToInterframe.size() == kNbInterframes);
|
||||
}
|
||||
|
||||
const auto iter = kStringToInterframe.find(input);
|
||||
if (iter == kStringToInterframe.end()) {
|
||||
wxLogWarning(_("Invalid value %s for option %s; valid values are %s"),
|
||||
input, config_name,
|
||||
AllEnumValuesForType(Option::Type::kInterframe));
|
||||
return 0;
|
||||
}
|
||||
return static_cast<int>(iter->second);
|
||||
}
|
||||
|
||||
int StringToRenderMethod(const wxString& config_name, const wxString& input) {
|
||||
static std::map<wxString, RenderMethod> kStringToRenderMethod;
|
||||
if (kStringToRenderMethod.empty()) {
|
||||
for (size_t i = 0; i < kNbRenderMethods; i++) {
|
||||
kStringToRenderMethod.emplace(kRenderMethodStrings[i],
|
||||
static_cast<RenderMethod>(i));
|
||||
}
|
||||
assert(kStringToRenderMethod.size() == kNbRenderMethods);
|
||||
}
|
||||
|
||||
const auto iter = kStringToRenderMethod.find(input);
|
||||
if (iter == kStringToRenderMethod.end()) {
|
||||
wxLogWarning(_("Invalid value %s for option %s; valid values are %s"),
|
||||
input, config_name,
|
||||
AllEnumValuesForType(Option::Type::kRenderMethod));
|
||||
return 0;
|
||||
}
|
||||
return static_cast<int>(iter->second);
|
||||
}
|
||||
|
||||
int StringToAudioApi(const wxString& config_name, const wxString& input) {
|
||||
static std::map<wxString, AudioApi> kStringToAudioApi;
|
||||
if (kStringToAudioApi.empty()) {
|
||||
for (size_t i = 0; i < kNbAudioApis; i++) {
|
||||
kStringToAudioApi.emplace(kAudioApiStrings[i],
|
||||
static_cast<AudioApi>(i));
|
||||
}
|
||||
assert(kStringToAudioApi.size() == kNbAudioApis);
|
||||
}
|
||||
|
||||
const auto iter = kStringToAudioApi.find(input);
|
||||
if (iter == kStringToAudioApi.end()) {
|
||||
wxLogWarning(_("Invalid value %s for option %s; valid values are %s"),
|
||||
input, config_name,
|
||||
AllEnumValuesForType(Option::Type::kAudioApi));
|
||||
return 0;
|
||||
}
|
||||
return static_cast<int>(iter->second);
|
||||
}
|
||||
|
||||
int StringToSoundQuality(const wxString& config_name, const wxString& input) {
|
||||
static std::map<wxString, SoundQuality> kStringToSoundQuality;
|
||||
if (kStringToSoundQuality.empty()) {
|
||||
for (size_t i = 0; i < kNbSoundQualities; i++) {
|
||||
kStringToSoundQuality.emplace(kSoundQualityStrings[i],
|
||||
static_cast<SoundQuality>(i));
|
||||
}
|
||||
assert(kStringToSoundQuality.size() == kNbSoundQualities);
|
||||
}
|
||||
|
||||
const auto iter = kStringToSoundQuality.find(input);
|
||||
if (iter == kStringToSoundQuality.end()) {
|
||||
wxLogWarning(_("Invalid value %s for option %s; valid values are %s"),
|
||||
input, config_name,
|
||||
AllEnumValuesForType(Option::Type::kSoundQuality));
|
||||
return 0;
|
||||
}
|
||||
return static_cast<int>(iter->second);
|
||||
}
|
||||
|
||||
wxString AllEnumValuesForType(Option::Type type) {
|
||||
switch (type) {
|
||||
case Option::Type::kFilter: {
|
||||
static const wxString kAllFilterValues =
|
||||
AllEnumValuesForArray(kFilterStrings);
|
||||
return kAllFilterValues;
|
||||
}
|
||||
case Option::Type::kInterframe: {
|
||||
static const wxString kAllInterframeValues =
|
||||
AllEnumValuesForArray(kInterframeStrings);
|
||||
return kAllInterframeValues;
|
||||
}
|
||||
case Option::Type::kRenderMethod: {
|
||||
static const wxString kAllRenderValues =
|
||||
AllEnumValuesForArray(kRenderMethodStrings);
|
||||
return kAllRenderValues;
|
||||
}
|
||||
case Option::Type::kAudioApi: {
|
||||
static const wxString kAllAudioApiValues =
|
||||
AllEnumValuesForArray(kAudioApiStrings);
|
||||
return kAllAudioApiValues;
|
||||
}
|
||||
case Option::Type::kSoundQuality: {
|
||||
static const wxString kAllSoundQualityValues =
|
||||
AllEnumValuesForArray(kSoundQualityStrings);
|
||||
return kAllSoundQualityValues;
|
||||
}
|
||||
|
||||
// We don't use default here to explicitly trigger a compiler warning
|
||||
// when adding a new value.
|
||||
case Option::Type::kNone:
|
||||
case Option::Type::kBool:
|
||||
case Option::Type::kDouble:
|
||||
case Option::Type::kInt:
|
||||
case Option::Type::kUnsigned:
|
||||
case Option::Type::kString:
|
||||
case Option::Type::kGbPalette:
|
||||
assert(false);
|
||||
return wxEmptyString;
|
||||
}
|
||||
assert(false);
|
||||
return wxEmptyString;
|
||||
}
|
||||
|
||||
int MaxForType(Option::Type type) {
|
||||
switch (type) {
|
||||
case Option::Type::kFilter:
|
||||
return kNbFilterFunctions;
|
||||
case Option::Type::kInterframe:
|
||||
return kNbInterframes;
|
||||
case Option::Type::kRenderMethod:
|
||||
return kNbRenderMethods;
|
||||
case Option::Type::kAudioApi:
|
||||
return kNbAudioApis;
|
||||
case Option::Type::kSoundQuality:
|
||||
return kNbSoundQualities;
|
||||
|
||||
// We don't use default here to explicitly trigger a compiler warning
|
||||
// when adding a new value.
|
||||
case Option::Type::kNone:
|
||||
case Option::Type::kBool:
|
||||
case Option::Type::kDouble:
|
||||
case Option::Type::kInt:
|
||||
case Option::Type::kUnsigned:
|
||||
case Option::Type::kString:
|
||||
case Option::Type::kGbPalette:
|
||||
assert(false);
|
||||
return 0;
|
||||
}
|
||||
assert(false);
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace config
|
|
@ -1,28 +1,29 @@
|
|||
#ifndef VBAM_OPTIONS_INTERNAL_INCLUDE
|
||||
#error "Do not include "vbam-options-internal.h" outside of the implementation."
|
||||
#ifndef VBAM_OPTION_INTERNAL_INCLUDE
|
||||
#error "Do not include "config/internal/option-internal.h" outside of the implementation."
|
||||
#endif
|
||||
|
||||
#include <wx/string.h>
|
||||
#include <array>
|
||||
#include <string>
|
||||
#include <wx/string.h>
|
||||
|
||||
#include "config/option.h"
|
||||
#include "nonstd/optional.hpp"
|
||||
#include "vbam-options.h"
|
||||
|
||||
namespace config {
|
||||
namespace internal {
|
||||
|
||||
struct VbamOptionData {
|
||||
struct OptionData {
|
||||
const wxString config_name;
|
||||
const wxString command;
|
||||
const wxString ux_helper;
|
||||
const VbamOption::Type type;
|
||||
const Option::Type type;
|
||||
};
|
||||
|
||||
// Static data to initialize global values.
|
||||
extern const std::array<VbamOptionData, kNbOptions + 1> kAllOptionsData;
|
||||
extern const std::array<OptionData, kNbOptions + 1> kAllOptionsData;
|
||||
|
||||
// Conversion utilities.
|
||||
nonstd::optional<VbamOptionID> StringToOptionId(const wxString& input);
|
||||
nonstd::optional<OptionID> StringToOptionId(const wxString& input);
|
||||
wxString FilterToString(int value);
|
||||
wxString InterframeToString(int value);
|
||||
wxString RenderMethodToString(int value);
|
||||
|
@ -34,9 +35,10 @@ int StringToRenderMethod(const wxString& config_name, const wxString& input);
|
|||
int StringToAudioApi(const wxString& config_name, const wxString& input);
|
||||
int StringToSoundQuality(const wxString& config_name, const wxString& input);
|
||||
|
||||
wxString AllEnumValuesForType(VbamOption::Type type);
|
||||
wxString AllEnumValuesForType(Option::Type type);
|
||||
|
||||
// Max value for enum types.
|
||||
int MaxForType(VbamOption::Type type);
|
||||
int MaxForType(Option::Type type);
|
||||
|
||||
} // namespace internal
|
||||
} // namespace config
|
|
@ -0,0 +1,389 @@
|
|||
#include "config/option.h"
|
||||
|
||||
#include "nonstd/variant.hpp"
|
||||
|
||||
#include <wx/log.h>
|
||||
#include <wx/translation.h>
|
||||
|
||||
#define VBAM_OPTION_INTERNAL_INCLUDE
|
||||
#include "config/internal/option-internal.h"
|
||||
#undef VBAM_OPTION_INTERNAL_INCLUDE
|
||||
|
||||
namespace config {
|
||||
|
||||
// static
|
||||
Option const* Option::FindByName(const wxString& config_name) {
|
||||
nonstd::optional<OptionID> option_id =
|
||||
internal::StringToOptionId(config_name);
|
||||
if (!option_id) {
|
||||
return nullptr;
|
||||
}
|
||||
return &FindByID(option_id.value());
|
||||
}
|
||||
|
||||
// static
|
||||
Option& Option::FindByID(OptionID id) {
|
||||
assert(id != OptionID::Last);
|
||||
return AllOptions()[static_cast<size_t>(id)];
|
||||
}
|
||||
|
||||
Option::~Option() = default;
|
||||
|
||||
Option::Option(OptionID id)
|
||||
: id_(id),
|
||||
config_name_(
|
||||
internal::kAllOptionsData[static_cast<size_t>(id)].config_name),
|
||||
command_(internal::kAllOptionsData[static_cast<size_t>(id)].command),
|
||||
ux_helper_(wxGetTranslation(
|
||||
internal::kAllOptionsData[static_cast<size_t>(id)].ux_helper)),
|
||||
type_(internal::kAllOptionsData[static_cast<size_t>(id)].type),
|
||||
value_(),
|
||||
min_(),
|
||||
max_() {
|
||||
assert(id != OptionID::Last);
|
||||
assert(is_none());
|
||||
}
|
||||
|
||||
Option::Option(OptionID id, bool* option)
|
||||
: id_(id),
|
||||
config_name_(
|
||||
internal::kAllOptionsData[static_cast<size_t>(id)].config_name),
|
||||
command_(internal::kAllOptionsData[static_cast<size_t>(id)].command),
|
||||
ux_helper_(wxGetTranslation(
|
||||
internal::kAllOptionsData[static_cast<size_t>(id)].ux_helper)),
|
||||
type_(internal::kAllOptionsData[static_cast<size_t>(id)].type),
|
||||
value_(option),
|
||||
min_(),
|
||||
max_() {
|
||||
assert(id != OptionID::Last);
|
||||
assert(is_bool());
|
||||
}
|
||||
|
||||
Option::Option(OptionID id, double* option, double min, double max)
|
||||
: id_(id),
|
||||
config_name_(
|
||||
internal::kAllOptionsData[static_cast<size_t>(id)].config_name),
|
||||
command_(internal::kAllOptionsData[static_cast<size_t>(id)].command),
|
||||
ux_helper_(wxGetTranslation(
|
||||
internal::kAllOptionsData[static_cast<size_t>(id)].ux_helper)),
|
||||
type_(internal::kAllOptionsData[static_cast<size_t>(id)].type),
|
||||
value_(option),
|
||||
min_(min),
|
||||
max_(max) {
|
||||
assert(id != OptionID::Last);
|
||||
assert(is_double());
|
||||
|
||||
// Validate the initial value.
|
||||
SetDouble(*option);
|
||||
}
|
||||
|
||||
Option::Option(OptionID id, int32_t* option, int32_t min, int32_t max)
|
||||
: id_(id),
|
||||
config_name_(
|
||||
internal::kAllOptionsData[static_cast<size_t>(id)].config_name),
|
||||
command_(internal::kAllOptionsData[static_cast<size_t>(id)].command),
|
||||
ux_helper_(wxGetTranslation(
|
||||
internal::kAllOptionsData[static_cast<size_t>(id)].ux_helper)),
|
||||
type_(internal::kAllOptionsData[static_cast<size_t>(id)].type),
|
||||
value_(option),
|
||||
min_(min),
|
||||
max_(max) {
|
||||
assert(id != OptionID::Last);
|
||||
assert(is_int());
|
||||
|
||||
// Validate the initial value.
|
||||
SetInt(*option);
|
||||
}
|
||||
|
||||
Option::Option(OptionID id, uint32_t* option, uint32_t min, uint32_t max)
|
||||
: id_(id),
|
||||
config_name_(
|
||||
internal::kAllOptionsData[static_cast<size_t>(id)].config_name),
|
||||
command_(internal::kAllOptionsData[static_cast<size_t>(id)].command),
|
||||
ux_helper_(wxGetTranslation(
|
||||
internal::kAllOptionsData[static_cast<size_t>(id)].ux_helper)),
|
||||
type_(internal::kAllOptionsData[static_cast<size_t>(id)].type),
|
||||
value_(option),
|
||||
min_(min),
|
||||
max_(max) {
|
||||
assert(id != OptionID::Last);
|
||||
assert(is_unsigned());
|
||||
|
||||
// Validate the initial value.
|
||||
SetUnsigned(*option);
|
||||
}
|
||||
|
||||
Option::Option(OptionID id, wxString* option)
|
||||
: id_(id),
|
||||
config_name_(
|
||||
internal::kAllOptionsData[static_cast<size_t>(id)].config_name),
|
||||
command_(internal::kAllOptionsData[static_cast<size_t>(id)].command),
|
||||
ux_helper_(wxGetTranslation(
|
||||
internal::kAllOptionsData[static_cast<size_t>(id)].ux_helper)),
|
||||
type_(internal::kAllOptionsData[static_cast<size_t>(id)].type),
|
||||
value_(option),
|
||||
min_(),
|
||||
max_() {
|
||||
assert(id != OptionID::Last);
|
||||
assert(is_string());
|
||||
}
|
||||
|
||||
Option::Option(OptionID id, int* option)
|
||||
: id_(id),
|
||||
config_name_(
|
||||
internal::kAllOptionsData[static_cast<size_t>(id)].config_name),
|
||||
command_(internal::kAllOptionsData[static_cast<size_t>(id)].command),
|
||||
ux_helper_(wxGetTranslation(
|
||||
internal::kAllOptionsData[static_cast<size_t>(id)].ux_helper)),
|
||||
type_(internal::kAllOptionsData[static_cast<size_t>(id)].type),
|
||||
value_(option),
|
||||
min_(0),
|
||||
max_(internal::MaxForType(type_)) {
|
||||
assert(id != OptionID::Last);
|
||||
assert(is_filter() || is_interframe() || is_render_method() ||
|
||||
is_audio_api() || is_sound_quality());
|
||||
|
||||
// Validate the initial value.
|
||||
SetEnumInt(*option);
|
||||
}
|
||||
|
||||
Option::Option(OptionID id, uint16_t* option)
|
||||
: id_(id),
|
||||
config_name_(
|
||||
internal::kAllOptionsData[static_cast<size_t>(id)].config_name),
|
||||
command_(internal::kAllOptionsData[static_cast<size_t>(id)].command),
|
||||
ux_helper_(wxGetTranslation(
|
||||
internal::kAllOptionsData[static_cast<size_t>(id)].ux_helper)),
|
||||
type_(internal::kAllOptionsData[static_cast<size_t>(id)].type),
|
||||
value_(option),
|
||||
min_(),
|
||||
max_() {
|
||||
assert(id != OptionID::Last);
|
||||
assert(is_gb_palette());
|
||||
}
|
||||
|
||||
bool Option::GetBool() const {
|
||||
assert(is_bool());
|
||||
return *(nonstd::get<bool*>(value_));
|
||||
}
|
||||
|
||||
double Option::GetDouble() const {
|
||||
assert(is_double());
|
||||
return *(nonstd::get<double*>(value_));
|
||||
}
|
||||
|
||||
int32_t Option::GetInt() const {
|
||||
assert(is_int());
|
||||
return *(nonstd::get<int32_t*>(value_));
|
||||
}
|
||||
|
||||
uint32_t Option::GetUnsigned() const {
|
||||
assert(is_unsigned());
|
||||
return *(nonstd::get<uint32_t*>(value_));
|
||||
}
|
||||
|
||||
const wxString Option::GetString() const {
|
||||
assert(is_string());
|
||||
return *(nonstd::get<wxString*>(value_));
|
||||
}
|
||||
|
||||
wxString Option::GetEnumString() const {
|
||||
switch (type_) {
|
||||
case Option::Type::kFilter:
|
||||
return internal::FilterToString(*(nonstd::get<int32_t*>(value_)));
|
||||
case Option::Type::kInterframe:
|
||||
return internal::InterframeToString(
|
||||
*(nonstd::get<int32_t*>(value_)));
|
||||
case Option::Type::kRenderMethod:
|
||||
return internal::RenderMethodToString(
|
||||
*(nonstd::get<int32_t*>(value_)));
|
||||
case Option::Type::kAudioApi:
|
||||
return internal::AudioApiToString(*(nonstd::get<int32_t*>(value_)));
|
||||
case Option::Type::kSoundQuality:
|
||||
return internal::SoundQualityToString(
|
||||
*(nonstd::get<int32_t*>(value_)));
|
||||
|
||||
// We don't use default here to explicitly trigger a compiler warning
|
||||
// when adding a new value.
|
||||
case Option::Type::kNone:
|
||||
case Option::Type::kBool:
|
||||
case Option::Type::kDouble:
|
||||
case Option::Type::kInt:
|
||||
case Option::Type::kUnsigned:
|
||||
case Option::Type::kString:
|
||||
case Option::Type::kGbPalette:
|
||||
assert(false);
|
||||
return wxEmptyString;
|
||||
}
|
||||
assert(false);
|
||||
return wxEmptyString;
|
||||
}
|
||||
|
||||
wxString Option::GetGbPaletteString() const {
|
||||
assert(is_gb_palette());
|
||||
|
||||
wxString palette_string;
|
||||
uint16_t const* value = nonstd::get<uint16_t*>(value_);
|
||||
palette_string.Printf("%04X,%04X,%04X,%04X,%04X,%04X,%04X,%04X", value[0],
|
||||
value[1], value[2], value[3], value[4], value[5],
|
||||
value[6], value[7]);
|
||||
return palette_string;
|
||||
}
|
||||
|
||||
void Option::SetBool(bool value) const {
|
||||
assert(is_bool());
|
||||
*nonstd::get<bool*>(value_) = value;
|
||||
}
|
||||
|
||||
void Option::SetDouble(double value) const {
|
||||
assert(is_double());
|
||||
if (value < nonstd::get<double>(min_) ||
|
||||
value > nonstd::get<double>(max_)) {
|
||||
wxLogWarning(
|
||||
_("Invalid value %f for option %s; valid values are %f - %f"),
|
||||
value, config_name_, nonstd::get<double>(min_),
|
||||
nonstd::get<double>(max_));
|
||||
return;
|
||||
}
|
||||
*nonstd::get<double*>(value_) = value;
|
||||
}
|
||||
|
||||
void Option::SetInt(int32_t value) const {
|
||||
assert(is_int());
|
||||
if (value < nonstd::get<int32_t>(min_) ||
|
||||
value > nonstd::get<int32_t>(max_)) {
|
||||
wxLogWarning(
|
||||
_("Invalid value %d for option %s; valid values are %d - %d"),
|
||||
value, config_name_, nonstd::get<int32_t>(min_),
|
||||
nonstd::get<int32_t>(max_));
|
||||
return;
|
||||
}
|
||||
*nonstd::get<int32_t*>(value_) = value;
|
||||
}
|
||||
|
||||
void Option::SetUnsigned(uint32_t value) const {
|
||||
assert(is_unsigned());
|
||||
if (value < nonstd::get<uint32_t>(min_) ||
|
||||
value > nonstd::get<uint32_t>(max_)) {
|
||||
wxLogWarning(
|
||||
_("Invalid value %d for option %s; valid values are %d - %d"),
|
||||
value, config_name_, nonstd::get<uint32_t>(min_),
|
||||
nonstd::get<uint32_t>(max_));
|
||||
return;
|
||||
}
|
||||
*nonstd::get<uint32_t*>(value_) = value;
|
||||
}
|
||||
|
||||
void Option::SetString(const wxString& value) const {
|
||||
assert(is_string());
|
||||
*nonstd::get<wxString*>(value_) = value;
|
||||
}
|
||||
|
||||
void Option::SetEnumString(const wxString& value) const {
|
||||
switch (type_) {
|
||||
case Option::Type::kFilter:
|
||||
SetEnumInt(internal::StringToFilter(config_name_, value));
|
||||
return;
|
||||
case Option::Type::kInterframe:
|
||||
SetEnumInt(internal::StringToInterframe(config_name_, value));
|
||||
return;
|
||||
case Option::Type::kRenderMethod:
|
||||
SetEnumInt(internal::StringToRenderMethod(config_name_, value));
|
||||
return;
|
||||
case Option::Type::kAudioApi:
|
||||
SetEnumInt(internal::StringToAudioApi(config_name_, value));
|
||||
return;
|
||||
case Option::Type::kSoundQuality:
|
||||
SetEnumInt(internal::StringToSoundQuality(config_name_, value));
|
||||
return;
|
||||
|
||||
// We don't use default here to explicitly trigger a compiler warning
|
||||
// when adding a new value.
|
||||
case Option::Type::kNone:
|
||||
case Option::Type::kBool:
|
||||
case Option::Type::kDouble:
|
||||
case Option::Type::kInt:
|
||||
case Option::Type::kUnsigned:
|
||||
case Option::Type::kString:
|
||||
case Option::Type::kGbPalette:
|
||||
assert(false);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void Option::SetEnumInt(int value) const {
|
||||
assert(is_filter() || is_interframe() || is_render_method() ||
|
||||
is_audio_api() || is_sound_quality());
|
||||
if (value < nonstd::get<int32_t>(min_) ||
|
||||
value > nonstd::get<int32_t>(max_)) {
|
||||
wxLogWarning(_("Invalid value %d for option %s; valid values are %s"),
|
||||
value, config_name_,
|
||||
internal::AllEnumValuesForType(type_));
|
||||
return;
|
||||
}
|
||||
*nonstd::get<int32_t*>(value_) = value;
|
||||
}
|
||||
|
||||
void Option::SetGbPalette(const wxString& value) const {
|
||||
assert(is_gb_palette());
|
||||
|
||||
// 8 values of 4 chars and 7 commas.
|
||||
static constexpr size_t kPaletteStringSize = 8 * 4 + 7;
|
||||
|
||||
if (value.size() != kPaletteStringSize) {
|
||||
wxLogWarning(_("Invalid value %s for option %s"), value, config_name_);
|
||||
return;
|
||||
}
|
||||
uint16_t* dest = nonstd::get<uint16_t*>(value_);
|
||||
|
||||
for (size_t i = 0; i < 8; i++) {
|
||||
wxString number = value.substr(i * 5, 4);
|
||||
long temp = 0;
|
||||
if (number.ToLong(&temp, 16)) {
|
||||
dest[i] = temp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
wxString Option::ToHelperString() const {
|
||||
wxString helper_string = config_name_;
|
||||
|
||||
switch (type_) {
|
||||
case Option::Type::kNone:
|
||||
break;
|
||||
case Option::Type::kBool:
|
||||
helper_string.Append(" (flag)");
|
||||
break;
|
||||
case Option::Type::kDouble:
|
||||
helper_string.Append(" (decimal)");
|
||||
break;
|
||||
case Option::Type::kInt:
|
||||
helper_string.Append(" (int)");
|
||||
break;
|
||||
case Option::Type::kUnsigned:
|
||||
helper_string.Append(" (unsigned)");
|
||||
break;
|
||||
case Option::Type::kString:
|
||||
helper_string.Append(" (string)");
|
||||
break;
|
||||
case Option::Type::kFilter:
|
||||
case Option::Type::kInterframe:
|
||||
case Option::Type::kRenderMethod:
|
||||
case Option::Type::kAudioApi:
|
||||
case Option::Type::kSoundQuality:
|
||||
helper_string.Append(" (");
|
||||
helper_string.Append(internal::AllEnumValuesForType(type_));
|
||||
helper_string.Append(")");
|
||||
break;
|
||||
case Option::Type::kGbPalette:
|
||||
helper_string.Append(" (XXXX,XXXX,XXXX,XXXX,XXXX,XXXX,XXXX,XXXX)");
|
||||
break;
|
||||
}
|
||||
helper_string.Append("\n\t");
|
||||
helper_string.Append(ux_helper_);
|
||||
helper_string.Append("\n");
|
||||
|
||||
return helper_string;
|
||||
}
|
||||
|
||||
} // namespace config
|
|
@ -1,5 +1,5 @@
|
|||
#ifndef VBAM_OPTIONS_H
|
||||
#define VBAM_OPTIONS_H
|
||||
#ifndef VBAM_WX_CONFIG_OPTIONS_H_
|
||||
#define VBAM_WX_CONFIG_OPTIONS_H_
|
||||
|
||||
#include "nonstd/variant.hpp"
|
||||
|
||||
|
@ -7,7 +7,9 @@
|
|||
|
||||
#include <wx/string.h>
|
||||
|
||||
enum class VbamOptionID {
|
||||
namespace config {
|
||||
|
||||
enum class OptionID {
|
||||
// Display
|
||||
kDisplayBilinear = 0,
|
||||
kDisplayFilter,
|
||||
|
@ -144,23 +146,23 @@ enum class VbamOptionID {
|
|||
Last,
|
||||
};
|
||||
|
||||
constexpr size_t kNbOptions = static_cast<size_t>(VbamOptionID::Last);
|
||||
constexpr size_t kNbOptions = static_cast<size_t>(OptionID::Last);
|
||||
|
||||
// Represents a single option saved in the INI file. VbamOption does not own the
|
||||
// Represents a single option saved in the INI file. Option does not own the
|
||||
// individual option, but keeps a pointer to where the data is actually saved.
|
||||
//
|
||||
// Ideally, options in the UI code should only be accessed and set via this
|
||||
// class, which should also take care of updating the INI file when
|
||||
// VbamOption::Set*() is called. This should also handle keyboard and joystick
|
||||
// Option::Set*() is called. This should also handle keyboard and joystick
|
||||
// configuration so option parsing can be done in a uniform manner. If we ever
|
||||
// get to that point, we would be able to remove most update_opts() calls and
|
||||
// have individual UI elements access the option via
|
||||
// VbamOption::FindOptionByID().
|
||||
// Option::FindByID().
|
||||
//
|
||||
// The implementation for this class is largely inspired by base::Value in
|
||||
// Chromium.
|
||||
// https://source.chromium.org/chromium/chromium/src/+/main:base/values.h
|
||||
class VbamOption {
|
||||
class Option {
|
||||
public:
|
||||
enum class Type {
|
||||
kNone = 0,
|
||||
|
@ -177,15 +179,15 @@ public:
|
|||
kGbPalette,
|
||||
};
|
||||
|
||||
static std::array<VbamOption, kNbOptions>& AllOptions();
|
||||
static std::array<Option, kNbOptions>& AllOptions();
|
||||
|
||||
// O(log(kNbOptions))
|
||||
static VbamOption const* FindOptionByName(const wxString& config_name);
|
||||
static Option const* FindByName(const wxString& config_name);
|
||||
|
||||
// O(1)
|
||||
static VbamOption& FindOptionByID(VbamOptionID id);
|
||||
static Option& FindByID(OptionID id);
|
||||
|
||||
~VbamOption();
|
||||
~Option();
|
||||
|
||||
// Accessors.
|
||||
const wxString& config_name() const { return config_name_; }
|
||||
|
@ -235,37 +237,38 @@ public:
|
|||
|
||||
private:
|
||||
// Disable copy and assignment. Every individual option is unique.
|
||||
VbamOption(const VbamOption&) = delete;
|
||||
VbamOption& operator=(const VbamOption&) = delete;
|
||||
Option(const Option&) = delete;
|
||||
Option& operator=(const Option&) = delete;
|
||||
|
||||
VbamOption(VbamOptionID id);
|
||||
VbamOption(VbamOptionID id, bool* option);
|
||||
VbamOption(VbamOptionID id, double* option, double min, double max);
|
||||
VbamOption(VbamOptionID id, int32_t* option, int32_t min, int32_t max);
|
||||
VbamOption(VbamOptionID id, uint32_t* option, uint32_t min, uint32_t max);
|
||||
VbamOption(VbamOptionID id, wxString* option);
|
||||
VbamOption(VbamOptionID id, int* option);
|
||||
VbamOption(VbamOptionID id, uint16_t* option);
|
||||
Option(OptionID id);
|
||||
Option(OptionID id, bool* option);
|
||||
Option(OptionID id, double* option, double min, double max);
|
||||
Option(OptionID id, int32_t* option, int32_t min, int32_t max);
|
||||
Option(OptionID id, uint32_t* option, uint32_t min, uint32_t max);
|
||||
Option(OptionID id, wxString* option);
|
||||
Option(OptionID id, int* option);
|
||||
Option(OptionID id, uint16_t* option);
|
||||
|
||||
const VbamOptionID id_;
|
||||
const OptionID id_;
|
||||
|
||||
const wxString config_name_;
|
||||
const wxString command_;
|
||||
const wxString ux_helper_;
|
||||
|
||||
const Type type_;
|
||||
const nonstd::variant<
|
||||
nonstd::monostate,
|
||||
bool*,
|
||||
double*,
|
||||
int32_t*,
|
||||
uint32_t*,
|
||||
wxString*,
|
||||
uint16_t*>
|
||||
const nonstd::variant<nonstd::monostate,
|
||||
bool*,
|
||||
double*,
|
||||
int32_t*,
|
||||
uint32_t*,
|
||||
wxString*,
|
||||
uint16_t*>
|
||||
value_;
|
||||
|
||||
const nonstd::variant<nonstd::monostate, double, int32_t, uint32_t> min_;
|
||||
const nonstd::variant<nonstd::monostate, double, int32_t, uint32_t> max_;
|
||||
};
|
||||
|
||||
#endif /* VBAM_OPTIONS_H */
|
||||
} // namespace config
|
||||
|
||||
#endif // VBAM_WX_CONFIG_OPTIONS_H_
|
|
@ -23,11 +23,11 @@
|
|||
#include <wx/txtstrm.h>
|
||||
#include <wx/wfstream.h>
|
||||
|
||||
#include "../gba/CheatSearch.h"
|
||||
#include "config/game-control.h"
|
||||
#include "config/option.h"
|
||||
#include "config/user-input.h"
|
||||
#include "opts.h"
|
||||
#include "vbam-options.h"
|
||||
#include "wx/gamecontrol.h"
|
||||
#include "../gba/CheatSearch.h"
|
||||
|
||||
#if defined(__WXGTK__)
|
||||
#include "wayland.h"
|
||||
|
@ -1673,8 +1673,8 @@ public:
|
|||
// For the individual clear buttons, we assume their name is
|
||||
// "Clear" + control_name
|
||||
// ClearUp for Up; ClearR for R etc
|
||||
for (const wxGameKey& game_key : kAllGameKeys) {
|
||||
const wxString control_name = GameKeyToString(game_key);
|
||||
for (const config::GameKey& game_key : config::kAllGameKeys) {
|
||||
const wxString control_name = config::GameKeyToString(game_key);
|
||||
wxJoyKeyTextCtrl* tc = XRCCTRL_D(*p, control_name, wxJoyKeyTextCtrl);
|
||||
wxString singleClearButton("Clear" + control_name);
|
||||
if (ev.GetId() == XRCID(singleClearButton.c_str())) {
|
||||
|
@ -1683,17 +1683,16 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
for (const wxGameKey& game_key : kAllGameKeys) {
|
||||
wxJoyKeyTextCtrl* tc =
|
||||
XRCCTRL_D(*p, GameKeyToString(game_key), wxJoyKeyTextCtrl);
|
||||
for (const config::GameKey& game_key : config::kAllGameKeys) {
|
||||
wxJoyKeyTextCtrl* tc = XRCCTRL_D(
|
||||
*p, config::GameKeyToString(game_key), wxJoyKeyTextCtrl);
|
||||
|
||||
if (clear) {
|
||||
tc->SetValue(wxEmptyString);
|
||||
} else {
|
||||
tc->SetValue(
|
||||
config::UserInput::SpanToString(
|
||||
kDefaultBindings.find(
|
||||
wxGameControl(0, game_key))->second));
|
||||
tc->SetValue(config::UserInput::SpanToString(
|
||||
kDefaultBindings.find(config::GameControl(0, game_key))
|
||||
->second));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2977,7 +2976,8 @@ bool MainFrame::BindControls()
|
|||
checkable_mi_t cmi = { cmdtab[i].cmd_id, mi, 0, 0 };
|
||||
checkable_mi.push_back(cmi);
|
||||
|
||||
for (const VbamOption& option : VbamOption::AllOptions()) {
|
||||
for (const config::Option& option :
|
||||
config::Option::AllOptions()) {
|
||||
if (cmdtab[i].cmd == option.command()) {
|
||||
if (option.is_int()) {
|
||||
MenuOptionIntMask(
|
||||
|
@ -3861,8 +3861,8 @@ bool MainFrame::BindControls()
|
|||
cb->SetValidator(wxBoolIntValidator(&gopts.default_stick, i + 1));
|
||||
wxWindow *prev = NULL, *prevp = NULL;
|
||||
|
||||
for (const wxGameKey& game_key : kAllGameKeys) {
|
||||
const wxString control_name = GameKeyToString(game_key);
|
||||
for (const config::GameKey& game_key : config::kAllGameKeys) {
|
||||
const wxString control_name = config::GameKeyToString(game_key);
|
||||
wxJoyKeyTextCtrl* tc = XRCCTRL_D(*w, control_name, wxJoyKeyTextCtrl);
|
||||
CheckThrowXRCError(tc, control_name);
|
||||
wxWindow* p = tc->GetParent();
|
||||
|
@ -3872,7 +3872,8 @@ bool MainFrame::BindControls()
|
|||
|
||||
prev = tc;
|
||||
prevp = p;
|
||||
tc->SetValidator(wxJoyKeyValidator(wxGameControl(i, game_key)));
|
||||
tc->SetValidator(
|
||||
wxJoyKeyValidator(config::GameControl(i, game_key)));
|
||||
}
|
||||
|
||||
JoyPadConfigHandler[i].p = w;
|
||||
|
@ -3882,8 +3883,8 @@ bool MainFrame::BindControls()
|
|||
w->Connect(XRCID("Clear"), wxEVT_COMMAND_BUTTON_CLICKED,
|
||||
wxCommandEventHandler(JoyPadConfig_t::JoypadConfigButtons),
|
||||
NULL, &JoyPadConfigHandler[i]);
|
||||
for (const wxGameKey& game_key : kAllGameKeys) {
|
||||
const wxString control_name = GameKeyToString(game_key);
|
||||
for (const config::GameKey& game_key : config::kAllGameKeys) {
|
||||
const wxString control_name = config::GameKeyToString(game_key);
|
||||
w->Connect(XRCID(wxString("Clear" + control_name).c_str()),
|
||||
wxEVT_COMMAND_BUTTON_CLICKED,
|
||||
wxCommandEventHandler(JoyPadConfig_t::JoypadConfigButtons),
|
||||
|
|
260
src/wx/opts.cpp
260
src/wx/opts.cpp
|
@ -6,7 +6,7 @@
|
|||
#include <wx/log.h>
|
||||
#include <wx/display.h>
|
||||
|
||||
#include "vbam-options.h"
|
||||
#include "config/option.h"
|
||||
#include "wxvbam.h"
|
||||
#include "strutils.h"
|
||||
|
||||
|
@ -115,138 +115,138 @@ const wxAcceleratorEntryUnicode default_accels[] = {
|
|||
};
|
||||
const int num_def_accels = sizeof(default_accels) / sizeof(default_accels[0]);
|
||||
|
||||
const std::map<wxGameControl, std::set<config::UserInput>> kDefaultBindings = {
|
||||
{ wxGameControl(0, wxGameKey::Up), {
|
||||
const std::map<config::GameControl, std::set<config::UserInput>> kDefaultBindings = {
|
||||
{ config::GameControl(0, config::GameKey::Up), {
|
||||
WJKB(wxT('W')),
|
||||
WJKB(11, wxJoyControl::Button, 1),
|
||||
WJKB(1, wxJoyControl::AxisMinus, 1),
|
||||
WJKB(3, wxJoyControl::AxisMinus, 1),
|
||||
}},
|
||||
{ wxGameControl(0, wxGameKey::Down), {
|
||||
{ config::GameControl(0, config::GameKey::Down), {
|
||||
WJKB(wxT('S')),
|
||||
WJKB(12, wxJoyControl::Button, 1),
|
||||
WJKB(1, wxJoyControl::AxisPlus, 1),
|
||||
WJKB(3, wxJoyControl::AxisPlus, 1),
|
||||
}},
|
||||
{ wxGameControl(0, wxGameKey::Left), {
|
||||
{ config::GameControl(0, config::GameKey::Left), {
|
||||
WJKB(wxT('A')),
|
||||
WJKB(13, wxJoyControl::Button, 1),
|
||||
WJKB(0, wxJoyControl::AxisMinus, 1),
|
||||
WJKB(2, wxJoyControl::AxisMinus, 1),
|
||||
}},
|
||||
{ wxGameControl(0, wxGameKey::Right), {
|
||||
{ config::GameControl(0, config::GameKey::Right), {
|
||||
WJKB(wxT('D')),
|
||||
WJKB(14, wxJoyControl::Button, 1),
|
||||
WJKB(0, wxJoyControl::AxisPlus, 1),
|
||||
WJKB(2, wxJoyControl::AxisPlus, 1),
|
||||
}},
|
||||
{ wxGameControl(0, wxGameKey::A), {
|
||||
{ config::GameControl(0, config::GameKey::A), {
|
||||
WJKB(wxT('L')),
|
||||
WJKB(0, wxJoyControl::Button, 1),
|
||||
}},
|
||||
{ wxGameControl(0, wxGameKey::B), {
|
||||
{ config::GameControl(0, config::GameKey::B), {
|
||||
WJKB(wxT('K')),
|
||||
WJKB(1, wxJoyControl::Button, 1),
|
||||
}},
|
||||
{ wxGameControl(0, wxGameKey::L), {
|
||||
{ config::GameControl(0, config::GameKey::L), {
|
||||
WJKB(wxT('I')),
|
||||
WJKB(2, wxJoyControl::Button, 1),
|
||||
WJKB(9, wxJoyControl::Button, 1),
|
||||
WJKB(4, wxJoyControl::AxisPlus, 1),
|
||||
}},
|
||||
{ wxGameControl(0, wxGameKey::R), {
|
||||
{ config::GameControl(0, config::GameKey::R), {
|
||||
WJKB(wxT('O')),
|
||||
WJKB(3, wxJoyControl::Button, 1),
|
||||
WJKB(10, wxJoyControl::Button, 1),
|
||||
WJKB(5, wxJoyControl::AxisPlus, 1),
|
||||
}},
|
||||
{ wxGameControl(0, wxGameKey::Select), {
|
||||
{ config::GameControl(0, config::GameKey::Select), {
|
||||
WJKB(WXK_BACK),
|
||||
WJKB(4, wxJoyControl::Button, 1),
|
||||
}},
|
||||
{ wxGameControl(0, wxGameKey::Start), {
|
||||
{ config::GameControl(0, config::GameKey::Start), {
|
||||
WJKB(WXK_RETURN),
|
||||
WJKB(6, wxJoyControl::Button, 1),
|
||||
}},
|
||||
{ wxGameControl(0, wxGameKey::MotionUp), {}},
|
||||
{ wxGameControl(0, wxGameKey::MotionDown), {}},
|
||||
{ wxGameControl(0, wxGameKey::MotionLeft), {}},
|
||||
{ wxGameControl(0, wxGameKey::MotionRight), {}},
|
||||
{ wxGameControl(0, wxGameKey::MotionIn), {}},
|
||||
{ wxGameControl(0, wxGameKey::MotionOut), {}},
|
||||
{ wxGameControl(0, wxGameKey::AutoA), {}},
|
||||
{ wxGameControl(0, wxGameKey::AutoB), {}},
|
||||
{ wxGameControl(0, wxGameKey::Speed), {
|
||||
{ config::GameControl(0, config::GameKey::MotionUp), {}},
|
||||
{ config::GameControl(0, config::GameKey::MotionDown), {}},
|
||||
{ config::GameControl(0, config::GameKey::MotionLeft), {}},
|
||||
{ config::GameControl(0, config::GameKey::MotionRight), {}},
|
||||
{ config::GameControl(0, config::GameKey::MotionIn), {}},
|
||||
{ config::GameControl(0, config::GameKey::MotionOut), {}},
|
||||
{ config::GameControl(0, config::GameKey::AutoA), {}},
|
||||
{ config::GameControl(0, config::GameKey::AutoB), {}},
|
||||
{ config::GameControl(0, config::GameKey::Speed), {
|
||||
WJKB(WXK_SPACE),
|
||||
}},
|
||||
{ wxGameControl(0, wxGameKey::Capture), {}},
|
||||
{ wxGameControl(0, wxGameKey::Gameshark), {}},
|
||||
{ config::GameControl(0, config::GameKey::Capture), {}},
|
||||
{ config::GameControl(0, config::GameKey::Gameshark), {}},
|
||||
|
||||
{ wxGameControl(1, wxGameKey::Up), {}},
|
||||
{ wxGameControl(1, wxGameKey::Down), {}},
|
||||
{ wxGameControl(1, wxGameKey::Left), {}},
|
||||
{ wxGameControl(1, wxGameKey::Right), {}},
|
||||
{ wxGameControl(1, wxGameKey::A), {}},
|
||||
{ wxGameControl(1, wxGameKey::B), {}},
|
||||
{ wxGameControl(1, wxGameKey::L), {}},
|
||||
{ wxGameControl(1, wxGameKey::R), {}},
|
||||
{ wxGameControl(1, wxGameKey::Select), {}},
|
||||
{ wxGameControl(1, wxGameKey::Start), {}},
|
||||
{ wxGameControl(1, wxGameKey::MotionUp), {}},
|
||||
{ wxGameControl(1, wxGameKey::MotionDown), {}},
|
||||
{ wxGameControl(1, wxGameKey::MotionLeft), {}},
|
||||
{ wxGameControl(1, wxGameKey::MotionRight), {}},
|
||||
{ wxGameControl(1, wxGameKey::MotionIn), {}},
|
||||
{ wxGameControl(1, wxGameKey::MotionOut), {}},
|
||||
{ wxGameControl(1, wxGameKey::AutoA), {}},
|
||||
{ wxGameControl(1, wxGameKey::AutoB), {}},
|
||||
{ wxGameControl(1, wxGameKey::Speed), {}},
|
||||
{ wxGameControl(1, wxGameKey::Capture), {}},
|
||||
{ wxGameControl(1, wxGameKey::Gameshark), {}},
|
||||
{ config::GameControl(1, config::GameKey::Up), {}},
|
||||
{ config::GameControl(1, config::GameKey::Down), {}},
|
||||
{ config::GameControl(1, config::GameKey::Left), {}},
|
||||
{ config::GameControl(1, config::GameKey::Right), {}},
|
||||
{ config::GameControl(1, config::GameKey::A), {}},
|
||||
{ config::GameControl(1, config::GameKey::B), {}},
|
||||
{ config::GameControl(1, config::GameKey::L), {}},
|
||||
{ config::GameControl(1, config::GameKey::R), {}},
|
||||
{ config::GameControl(1, config::GameKey::Select), {}},
|
||||
{ config::GameControl(1, config::GameKey::Start), {}},
|
||||
{ config::GameControl(1, config::GameKey::MotionUp), {}},
|
||||
{ config::GameControl(1, config::GameKey::MotionDown), {}},
|
||||
{ config::GameControl(1, config::GameKey::MotionLeft), {}},
|
||||
{ config::GameControl(1, config::GameKey::MotionRight), {}},
|
||||
{ config::GameControl(1, config::GameKey::MotionIn), {}},
|
||||
{ config::GameControl(1, config::GameKey::MotionOut), {}},
|
||||
{ config::GameControl(1, config::GameKey::AutoA), {}},
|
||||
{ config::GameControl(1, config::GameKey::AutoB), {}},
|
||||
{ config::GameControl(1, config::GameKey::Speed), {}},
|
||||
{ config::GameControl(1, config::GameKey::Capture), {}},
|
||||
{ config::GameControl(1, config::GameKey::Gameshark), {}},
|
||||
|
||||
{ wxGameControl(2, wxGameKey::Up), {}},
|
||||
{ wxGameControl(2, wxGameKey::Down), {}},
|
||||
{ wxGameControl(2, wxGameKey::Left), {}},
|
||||
{ wxGameControl(2, wxGameKey::Right), {}},
|
||||
{ wxGameControl(2, wxGameKey::A), {}},
|
||||
{ wxGameControl(2, wxGameKey::B), {}},
|
||||
{ wxGameControl(2, wxGameKey::L), {}},
|
||||
{ wxGameControl(2, wxGameKey::R), {}},
|
||||
{ wxGameControl(2, wxGameKey::Select), {}},
|
||||
{ wxGameControl(2, wxGameKey::Start), {}},
|
||||
{ wxGameControl(2, wxGameKey::MotionUp), {}},
|
||||
{ wxGameControl(2, wxGameKey::MotionDown), {}},
|
||||
{ wxGameControl(2, wxGameKey::MotionLeft), {}},
|
||||
{ wxGameControl(2, wxGameKey::MotionRight), {}},
|
||||
{ wxGameControl(2, wxGameKey::MotionIn), {}},
|
||||
{ wxGameControl(2, wxGameKey::MotionOut), {}},
|
||||
{ wxGameControl(2, wxGameKey::AutoA), {}},
|
||||
{ wxGameControl(2, wxGameKey::AutoB), {}},
|
||||
{ wxGameControl(2, wxGameKey::Speed), {}},
|
||||
{ wxGameControl(2, wxGameKey::Capture), {}},
|
||||
{ wxGameControl(2, wxGameKey::Gameshark), {}},
|
||||
{ config::GameControl(2, config::GameKey::Up), {}},
|
||||
{ config::GameControl(2, config::GameKey::Down), {}},
|
||||
{ config::GameControl(2, config::GameKey::Left), {}},
|
||||
{ config::GameControl(2, config::GameKey::Right), {}},
|
||||
{ config::GameControl(2, config::GameKey::A), {}},
|
||||
{ config::GameControl(2, config::GameKey::B), {}},
|
||||
{ config::GameControl(2, config::GameKey::L), {}},
|
||||
{ config::GameControl(2, config::GameKey::R), {}},
|
||||
{ config::GameControl(2, config::GameKey::Select), {}},
|
||||
{ config::GameControl(2, config::GameKey::Start), {}},
|
||||
{ config::GameControl(2, config::GameKey::MotionUp), {}},
|
||||
{ config::GameControl(2, config::GameKey::MotionDown), {}},
|
||||
{ config::GameControl(2, config::GameKey::MotionLeft), {}},
|
||||
{ config::GameControl(2, config::GameKey::MotionRight), {}},
|
||||
{ config::GameControl(2, config::GameKey::MotionIn), {}},
|
||||
{ config::GameControl(2, config::GameKey::MotionOut), {}},
|
||||
{ config::GameControl(2, config::GameKey::AutoA), {}},
|
||||
{ config::GameControl(2, config::GameKey::AutoB), {}},
|
||||
{ config::GameControl(2, config::GameKey::Speed), {}},
|
||||
{ config::GameControl(2, config::GameKey::Capture), {}},
|
||||
{ config::GameControl(2, config::GameKey::Gameshark), {}},
|
||||
|
||||
{ wxGameControl(3, wxGameKey::Up), {}},
|
||||
{ wxGameControl(3, wxGameKey::Down), {}},
|
||||
{ wxGameControl(3, wxGameKey::Left), {}},
|
||||
{ wxGameControl(3, wxGameKey::Right), {}},
|
||||
{ wxGameControl(3, wxGameKey::A), {}},
|
||||
{ wxGameControl(3, wxGameKey::B), {}},
|
||||
{ wxGameControl(3, wxGameKey::L), {}},
|
||||
{ wxGameControl(3, wxGameKey::R), {}},
|
||||
{ wxGameControl(3, wxGameKey::Select), {}},
|
||||
{ wxGameControl(3, wxGameKey::Start), {}},
|
||||
{ wxGameControl(3, wxGameKey::MotionUp), {}},
|
||||
{ wxGameControl(3, wxGameKey::MotionDown), {}},
|
||||
{ wxGameControl(3, wxGameKey::MotionLeft), {}},
|
||||
{ wxGameControl(3, wxGameKey::MotionRight), {}},
|
||||
{ wxGameControl(3, wxGameKey::MotionIn), {}},
|
||||
{ wxGameControl(3, wxGameKey::MotionOut), {}},
|
||||
{ wxGameControl(3, wxGameKey::AutoA), {}},
|
||||
{ wxGameControl(3, wxGameKey::AutoB), {}},
|
||||
{ wxGameControl(3, wxGameKey::Speed), {}},
|
||||
{ wxGameControl(3, wxGameKey::Capture), {}},
|
||||
{ wxGameControl(3, wxGameKey::Gameshark), {}},
|
||||
{ config::GameControl(3, config::GameKey::Up), {}},
|
||||
{ config::GameControl(3, config::GameKey::Down), {}},
|
||||
{ config::GameControl(3, config::GameKey::Left), {}},
|
||||
{ config::GameControl(3, config::GameKey::Right), {}},
|
||||
{ config::GameControl(3, config::GameKey::A), {}},
|
||||
{ config::GameControl(3, config::GameKey::B), {}},
|
||||
{ config::GameControl(3, config::GameKey::L), {}},
|
||||
{ config::GameControl(3, config::GameKey::R), {}},
|
||||
{ config::GameControl(3, config::GameKey::Select), {}},
|
||||
{ config::GameControl(3, config::GameKey::Start), {}},
|
||||
{ config::GameControl(3, config::GameKey::MotionUp), {}},
|
||||
{ config::GameControl(3, config::GameKey::MotionDown), {}},
|
||||
{ config::GameControl(3, config::GameKey::MotionLeft), {}},
|
||||
{ config::GameControl(3, config::GameKey::MotionRight), {}},
|
||||
{ config::GameControl(3, config::GameKey::MotionIn), {}},
|
||||
{ config::GameControl(3, config::GameKey::MotionOut), {}},
|
||||
{ config::GameControl(3, config::GameKey::AutoA), {}},
|
||||
{ config::GameControl(3, config::GameKey::AutoB), {}},
|
||||
{ config::GameControl(3, config::GameKey::Speed), {}},
|
||||
{ config::GameControl(3, config::GameKey::Capture), {}},
|
||||
{ config::GameControl(3, config::GameKey::Gameshark), {}},
|
||||
};
|
||||
|
||||
wxAcceleratorEntry_v sys_accels;
|
||||
|
@ -367,7 +367,7 @@ void load_opts()
|
|||
|
||||
for (cont = cfg->GetFirstEntry(e, key_idx); cont;
|
||||
cont = cfg->GetNextEntry(e, key_idx)) {
|
||||
if (!StringToGameKey(e)) {
|
||||
if (!config::StringToGameKey(e)) {
|
||||
s.append(e);
|
||||
//wxLogWarning(_("Invalid option %s present; removing if possible"), s.c_str());
|
||||
item_del.push_back(s);
|
||||
|
@ -403,7 +403,7 @@ void load_opts()
|
|||
} else {
|
||||
s.append(wxT('/'));
|
||||
s.append(e);
|
||||
if (!VbamOption::FindOptionByName(s) && s != wxT("General/LastUpdated") && s != wxT("General/LastUpdatedFileName")) {
|
||||
if (!config::Option::FindByName(s) && s != wxT("General/LastUpdated") && s != wxT("General/LastUpdatedFileName")) {
|
||||
//wxLogWarning(_("Invalid option %s present; removing if possible"), s.c_str());
|
||||
item_del.push_back(s);
|
||||
}
|
||||
|
@ -425,46 +425,46 @@ void load_opts()
|
|||
cfg->SetRecordDefaults();
|
||||
|
||||
// First access here will also initialize translations.
|
||||
for (const VbamOption& opt : VbamOption::AllOptions()) {
|
||||
for (const config::Option& opt : config::Option::AllOptions()) {
|
||||
switch (opt.type()) {
|
||||
case VbamOption::Type::kNone:
|
||||
case config::Option::Type::kNone:
|
||||
// Keyboard or Joystick. Handled separately for now.
|
||||
break;
|
||||
case VbamOption::Type::kBool: {
|
||||
case config::Option::Type::kBool: {
|
||||
bool temp;
|
||||
cfg->Read(opt.config_name(), &temp, opt.GetBool());
|
||||
opt.SetBool(temp);
|
||||
break;
|
||||
}
|
||||
case VbamOption::Type::kDouble: {
|
||||
case config::Option::Type::kDouble: {
|
||||
double temp;
|
||||
cfg->Read(opt.config_name(), &temp, opt.GetDouble());
|
||||
opt.SetDouble(temp);
|
||||
break;
|
||||
}
|
||||
case VbamOption::Type::kInt: {
|
||||
case config::Option::Type::kInt: {
|
||||
int32_t temp;
|
||||
cfg->Read(opt.config_name(), &temp, opt.GetInt());
|
||||
opt.SetInt(temp);
|
||||
break;
|
||||
}
|
||||
case VbamOption::Type::kUnsigned: {
|
||||
case config::Option::Type::kUnsigned: {
|
||||
int temp;
|
||||
cfg->Read(opt.config_name(), &temp, opt.GetUnsigned());
|
||||
opt.SetUnsigned(temp);
|
||||
break;
|
||||
}
|
||||
case VbamOption::Type::kString: {
|
||||
case config::Option::Type::kString: {
|
||||
wxString temp;
|
||||
cfg->Read(opt.config_name(), &temp, opt.GetString());
|
||||
opt.SetString(temp);
|
||||
break;
|
||||
}
|
||||
case VbamOption::Type::kFilter:
|
||||
case VbamOption::Type::kInterframe:
|
||||
case VbamOption::Type::kRenderMethod:
|
||||
case VbamOption::Type::kAudioApi:
|
||||
case VbamOption::Type::kSoundQuality: {
|
||||
case config::Option::Type::kFilter:
|
||||
case config::Option::Type::kInterframe:
|
||||
case config::Option::Type::kRenderMethod:
|
||||
case config::Option::Type::kAudioApi:
|
||||
case config::Option::Type::kSoundQuality: {
|
||||
wxString temp;
|
||||
if (cfg->Read(opt.config_name(), &temp) && !temp.empty()) {
|
||||
opt.SetEnumString(temp.MakeLower());
|
||||
|
@ -473,7 +473,7 @@ void load_opts()
|
|||
cfg->Write(opt.config_name(), opt.GetEnumString());
|
||||
break;
|
||||
}
|
||||
case VbamOption::Type::kGbPalette: {
|
||||
case config::Option::Type::kGbPalette: {
|
||||
wxString temp;
|
||||
cfg->Read(opt.config_name(), &temp, opt.GetGbPaletteString());
|
||||
opt.SetGbPalette(temp);
|
||||
|
@ -539,34 +539,34 @@ void update_opts()
|
|||
{
|
||||
wxFileConfig* cfg = wxGetApp().cfg;
|
||||
|
||||
for (const VbamOption& opt : VbamOption::AllOptions()) {
|
||||
for (const config::Option& opt : config::Option::AllOptions()) {
|
||||
switch (opt.type()) {
|
||||
case VbamOption::Type::kNone:
|
||||
case config::Option::Type::kNone:
|
||||
// Keyboard and Joypad are handled separately.
|
||||
break;
|
||||
case VbamOption::Type::kBool:
|
||||
case config::Option::Type::kBool:
|
||||
cfg->Write(opt.config_name(), opt.GetBool());
|
||||
break;
|
||||
case VbamOption::Type::kDouble:
|
||||
case config::Option::Type::kDouble:
|
||||
cfg->Write(opt.config_name(), opt.GetDouble());
|
||||
break;
|
||||
case VbamOption::Type::kInt:
|
||||
case config::Option::Type::kInt:
|
||||
cfg->Write(opt.config_name(), opt.GetInt());
|
||||
break;
|
||||
case VbamOption::Type::kUnsigned:
|
||||
case config::Option::Type::kUnsigned:
|
||||
cfg->Write(opt.config_name(), opt.GetUnsigned());
|
||||
break;
|
||||
case VbamOption::Type::kString:
|
||||
case config::Option::Type::kString:
|
||||
cfg->Write(opt.config_name(), opt.GetString());
|
||||
break;
|
||||
case VbamOption::Type::kFilter:
|
||||
case VbamOption::Type::kInterframe:
|
||||
case VbamOption::Type::kRenderMethod:
|
||||
case VbamOption::Type::kAudioApi:
|
||||
case VbamOption::Type::kSoundQuality:
|
||||
case config::Option::Type::kFilter:
|
||||
case config::Option::Type::kInterframe:
|
||||
case config::Option::Type::kRenderMethod:
|
||||
case config::Option::Type::kAudioApi:
|
||||
case config::Option::Type::kSoundQuality:
|
||||
cfg->Write(opt.config_name(), opt.GetEnumString());
|
||||
break;
|
||||
case VbamOption::Type::kGbPalette:
|
||||
case config::Option::Type::kGbPalette:
|
||||
cfg->Write(opt.config_name(), opt.GetGbPaletteString());
|
||||
break;
|
||||
}
|
||||
|
@ -587,7 +587,7 @@ void update_opts()
|
|||
}
|
||||
}
|
||||
if (game_bindings_changed) {
|
||||
wxGameControlState::Instance().OnGameBindingsChanged();
|
||||
config::GameControlState::Instance().OnGameBindingsChanged();
|
||||
}
|
||||
|
||||
// for keyboard, first remove any commands that aren't bound at all
|
||||
|
@ -656,16 +656,16 @@ void update_opts()
|
|||
}
|
||||
|
||||
void opt_set(const wxString& name, const wxString& val) {
|
||||
VbamOption const* opt = VbamOption::FindOptionByName(name);
|
||||
config::Option const* opt = config::Option::FindByName(name);
|
||||
|
||||
// opt->is_none() means it is Keyboard or Joypad.
|
||||
if (opt && !opt->is_none()) {
|
||||
switch (opt->type()) {
|
||||
case VbamOption::Type::kNone:
|
||||
case config::Option::Type::kNone:
|
||||
// This should never happen.
|
||||
assert(false);
|
||||
return;
|
||||
case VbamOption::Type::kBool:
|
||||
case config::Option::Type::kBool:
|
||||
if (val != '0' && val != '1') {
|
||||
wxLogWarning(_("Invalid value %s for option %s"),
|
||||
name.c_str(), val.c_str());
|
||||
|
@ -673,7 +673,7 @@ void opt_set(const wxString& name, const wxString& val) {
|
|||
}
|
||||
opt->SetBool(val == '1');
|
||||
return;
|
||||
case VbamOption::Type::kDouble: {
|
||||
case config::Option::Type::kDouble: {
|
||||
double value;
|
||||
if (!val.ToDouble(&value)) {
|
||||
wxLogWarning(_("Invalid value %s for option %s"), val, name.c_str());
|
||||
|
@ -682,7 +682,7 @@ void opt_set(const wxString& name, const wxString& val) {
|
|||
opt->SetDouble(value);
|
||||
return;
|
||||
}
|
||||
case VbamOption::Type::kInt: {
|
||||
case config::Option::Type::kInt: {
|
||||
long value;
|
||||
if (!val.ToLong(&value)) {
|
||||
wxLogWarning(_("Invalid value %s for option %s"), val, name.c_str());
|
||||
|
@ -691,7 +691,7 @@ void opt_set(const wxString& name, const wxString& val) {
|
|||
opt->SetInt(static_cast<int32_t>(value));
|
||||
return;
|
||||
}
|
||||
case VbamOption::Type::kUnsigned: {
|
||||
case config::Option::Type::kUnsigned: {
|
||||
unsigned long value;
|
||||
if (!val.ToULong(&value)) {
|
||||
wxLogWarning(_("Invalid value %s for option %s"), val, name.c_str());
|
||||
|
@ -700,17 +700,17 @@ void opt_set(const wxString& name, const wxString& val) {
|
|||
opt->SetUnsigned(static_cast<uint32_t>(value));
|
||||
return;
|
||||
}
|
||||
case VbamOption::Type::kString:
|
||||
case config::Option::Type::kString:
|
||||
opt->SetString(val);
|
||||
return;
|
||||
case VbamOption::Type::kFilter:
|
||||
case VbamOption::Type::kInterframe:
|
||||
case VbamOption::Type::kRenderMethod:
|
||||
case VbamOption::Type::kAudioApi:
|
||||
case VbamOption::Type::kSoundQuality:
|
||||
case config::Option::Type::kFilter:
|
||||
case config::Option::Type::kInterframe:
|
||||
case config::Option::Type::kRenderMethod:
|
||||
case config::Option::Type::kAudioApi:
|
||||
case config::Option::Type::kSoundQuality:
|
||||
opt->SetEnumString(val);
|
||||
return;
|
||||
case VbamOption::Type::kGbPalette:
|
||||
case config::Option::Type::kGbPalette:
|
||||
opt->SetGbPalette(val);
|
||||
return;
|
||||
}
|
||||
|
@ -754,8 +754,8 @@ void opt_set(const wxString& name, const wxString& val) {
|
|||
return;
|
||||
}
|
||||
|
||||
const nonstd::optional<wxGameControl> game_control =
|
||||
wxGameControl::FromString(name);
|
||||
const nonstd::optional<config::GameControl> game_control =
|
||||
config::GameControl::FromString(name);
|
||||
if (game_control) {
|
||||
if (val.empty()) {
|
||||
gopts.game_control_bindings[game_control.value()].clear();
|
||||
|
|
|
@ -6,15 +6,16 @@
|
|||
#include <wx/string.h>
|
||||
#include <wx/vidmode.h>
|
||||
|
||||
#include "wx/gamecontrol.h"
|
||||
#include "wx/keyedit.h"
|
||||
#include "config/game-control.h"
|
||||
#include "config/user-input.h"
|
||||
#include "wx/keyedit.h"
|
||||
|
||||
// Forward declaration.
|
||||
class wxFileHistory;
|
||||
|
||||
// Default joystick bindings.
|
||||
extern const std::map<wxGameControl, std::set<config::UserInput>> kDefaultBindings;
|
||||
extern const std::map<config::GameControl, std::set<config::UserInput>>
|
||||
kDefaultBindings;
|
||||
|
||||
extern struct opts_t {
|
||||
opts_t();
|
||||
|
@ -64,7 +65,8 @@ extern struct opts_t {
|
|||
int statusbar;
|
||||
|
||||
/// Joypad
|
||||
std::map<wxGameControl, std::set<config::UserInput>> game_control_bindings;
|
||||
std::map<config::GameControl, std::set<config::UserInput>>
|
||||
game_control_bindings;
|
||||
int autofire_rate;
|
||||
int default_stick;
|
||||
|
||||
|
|
|
@ -17,21 +17,21 @@
|
|||
#include <wx/menu.h>
|
||||
#include <SDL_joystick.h>
|
||||
|
||||
#include "../common/version_cpp.h"
|
||||
#include "../common/Patch.h"
|
||||
#include "../common/version_cpp.h"
|
||||
#include "../gb/gbPrinter.h"
|
||||
#include "../gba/RTC.h"
|
||||
#include "../gba/agbprint.h"
|
||||
#include "../sdl/text.h"
|
||||
#include "background-input.h"
|
||||
#include "config/game-control.h"
|
||||
#include "config/user-input.h"
|
||||
#include "drawing.h"
|
||||
#include "filters.h"
|
||||
#include "wx/joyedit.h"
|
||||
#include "wx/gamecontrol.h"
|
||||
#include "wxvbam.h"
|
||||
#include "wxutil.h"
|
||||
#include "wayland.h"
|
||||
#include "background-input.h"
|
||||
#include "wx/joyedit.h"
|
||||
#include "wxutil.h"
|
||||
#include "wxvbam.h"
|
||||
|
||||
#ifdef __WXMSW__
|
||||
#include <windows.h>
|
||||
|
@ -958,7 +958,7 @@ GameArea::~GameArea()
|
|||
|
||||
void GameArea::OnKillFocus(wxFocusEvent& ev)
|
||||
{
|
||||
wxGameControlState::Instance().Reset();
|
||||
config::GameControlState::Instance().Reset();
|
||||
ev.Skip();
|
||||
}
|
||||
|
||||
|
@ -978,7 +978,7 @@ void GameArea::Pause()
|
|||
// when the game is paused like this, we should not allow any
|
||||
// input to remain pressed, because they could be released
|
||||
// outside of the game zone and we would not know about it.
|
||||
wxGameControlState::Instance().Reset();
|
||||
config::GameControlState::Instance().Reset();
|
||||
|
||||
if (loaded != IMAGE_UNKNOWN)
|
||||
soundPause();
|
||||
|
@ -1212,9 +1212,9 @@ void GameArea::OnIdle(wxIdleEvent& event)
|
|||
static bool process_user_input(bool down, const config::UserInput& user_input)
|
||||
{
|
||||
if (down)
|
||||
return wxGameControlState::Instance().OnInputPressed(user_input);
|
||||
return config::GameControlState::Instance().OnInputPressed(user_input);
|
||||
else
|
||||
return wxGameControlState::Instance().OnInputReleased(user_input);
|
||||
return config::GameControlState::Instance().OnInputReleased(user_input);
|
||||
}
|
||||
|
||||
static void draw_black_background(wxWindow* win) {
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#include "../common/SoundSDL.h"
|
||||
#include "wx/gamecontrol.h"
|
||||
#include "config/game-control.h"
|
||||
#include "wxvbam.h"
|
||||
#include "SDL.h"
|
||||
#include <wx/ffile.h>
|
||||
|
@ -331,7 +331,7 @@ uint32_t systemReadJoypad(int joy)
|
|||
if (joy < 0 || joy > 3)
|
||||
joy = gopts.default_stick - 1;
|
||||
|
||||
uint32_t ret = wxGameControlState::Instance().GetJoypad(joy);
|
||||
uint32_t ret = config::GameControlState::Instance().GetJoypad(joy);
|
||||
|
||||
if (turbo)
|
||||
ret |= KEYM_SPEED;
|
||||
|
@ -641,7 +641,9 @@ void systemUpdateSolarSensor()
|
|||
void systemUpdateMotionSensor()
|
||||
{
|
||||
for (int i = 0; i < 4; i++) {
|
||||
const uint32_t joy_value = wxGameControlState::Instance().GetJoypad(i);
|
||||
const uint32_t joy_value =
|
||||
config::GameControlState::Instance().GetJoypad(i);
|
||||
|
||||
if (!sensorx[i])
|
||||
sensorx[i] = 2047;
|
||||
|
||||
|
|
|
@ -1,698 +0,0 @@
|
|||
#include "vbam-options.h"
|
||||
|
||||
// Helper implementation file to define and compile all of these huge constants
|
||||
// separately. These should not be updated very often, so having these in a
|
||||
// separate file improves incremental build time.
|
||||
|
||||
#include <algorithm>
|
||||
#include <wx/log.h>
|
||||
|
||||
#include "../common/ConfigManager.h"
|
||||
#include "../gb/gbGlobals.h"
|
||||
#include "opts.h"
|
||||
|
||||
#define VBAM_OPTIONS_INTERNAL_INCLUDE
|
||||
#include "vbam-options-internal.h"
|
||||
#undef VBAM_OPTIONS_INTERNAL_INCLUDE
|
||||
|
||||
namespace {
|
||||
|
||||
// This enum must be kept in sync with the one in wxvbam.h
|
||||
// TODO: These 2 enums should be unified and a validator created for this enum.
|
||||
enum class FilterFunction {
|
||||
kNone,
|
||||
k2xsai,
|
||||
kSuper2xsai,
|
||||
kSupereagle,
|
||||
kPixelate,
|
||||
kAdvmame,
|
||||
kBilinear,
|
||||
kBilinearplus,
|
||||
kScanlines,
|
||||
kTvmode,
|
||||
kHQ2x,
|
||||
kLQ2x,
|
||||
kSimple2x,
|
||||
kSimple3x,
|
||||
kHQ3x,
|
||||
kSimple4x,
|
||||
kHQ4x,
|
||||
kXbrz2x,
|
||||
kXbrz3x,
|
||||
kXbrz4x,
|
||||
kXbrz5x,
|
||||
kXbrz6x,
|
||||
kPlugin, // This must always be last.
|
||||
|
||||
// Do not add anything under here.
|
||||
kLast,
|
||||
};
|
||||
constexpr size_t kNbFilterFunctions = static_cast<size_t>(FilterFunction::kLast);
|
||||
|
||||
// These MUST follow the same order as the definitions of the enum above.
|
||||
// Adding an option without adding to this array will result in a compiler
|
||||
// error since kNbFilterFunctions is automatically updated.
|
||||
static const std::array<wxString, kNbFilterFunctions> kFilterStrings = {
|
||||
"none",
|
||||
"2xsai",
|
||||
"super2xsai",
|
||||
"supereagle",
|
||||
"pixelate",
|
||||
"advmame",
|
||||
"bilinear",
|
||||
"bilinearplus",
|
||||
"scanlines",
|
||||
"tvmode",
|
||||
"hq2x",
|
||||
"lq2x",
|
||||
"simple2x",
|
||||
"simple3x",
|
||||
"hq3x",
|
||||
"simple4x",
|
||||
"hq4x",
|
||||
"xbrz2x",
|
||||
"xbrz3x",
|
||||
"xbrz4x",
|
||||
"xbrz5x",
|
||||
"xbrz6x",
|
||||
"plugin",
|
||||
};
|
||||
|
||||
// This enum must be kept in sync with the one in wxvbam.h
|
||||
// TODO: These 2 enums should be unified and a validator created for this enum.
|
||||
enum class Interframe {
|
||||
kNone = 0,
|
||||
kSmart,
|
||||
kMotionBlur,
|
||||
|
||||
// Do not add anything under here.
|
||||
kLast,
|
||||
};
|
||||
constexpr size_t kNbInterframes = static_cast<size_t>(Interframe::kLast);
|
||||
|
||||
// These MUST follow the same order as the definitions of the enum above.
|
||||
// Adding an option without adding to this array will result in a compiler
|
||||
// error since kNbInterframes is automatically updated.
|
||||
static const std::array<wxString, kNbInterframes> kInterframeStrings = {
|
||||
"none",
|
||||
"smart",
|
||||
"motionblur",
|
||||
};
|
||||
|
||||
// This enum must be kept in sync with the one in wxvbam.h
|
||||
// TODO: These 2 enums should be unified and a validator created for this enum.
|
||||
enum class RenderMethod {
|
||||
kSimple = 0,
|
||||
kOpenGL,
|
||||
#ifdef __WXMSW__
|
||||
kDirect3d,
|
||||
#elif defined(__WXMAC__)
|
||||
kQuartz2d,
|
||||
#endif
|
||||
|
||||
// Do not add anything under here.
|
||||
kLast,
|
||||
};
|
||||
constexpr size_t kNbRenderMethods = static_cast<size_t>(RenderMethod::kLast);
|
||||
|
||||
// These MUST follow the same order as the definitions of the enum above.
|
||||
// Adding an option without adding to this array will result in a compiler
|
||||
// error since kNbRenderMethods is automatically updated.
|
||||
static const std::array<wxString, kNbRenderMethods> kRenderMethodStrings = {
|
||||
"simple",
|
||||
"opengl",
|
||||
#ifdef __WXMSW__
|
||||
"direct3d",
|
||||
#elif defined(__WXMAC__)
|
||||
"quartz2d",
|
||||
#endif
|
||||
};
|
||||
|
||||
// This enum must be kept in sync with the one in wxvbam.h
|
||||
// TODO: These 2 enums should be unified and a validator created for this enum.
|
||||
// TODO: DirectSound and XAudio2 should only be used on Windows.
|
||||
enum class AudioApi {
|
||||
kSdl = 0,
|
||||
kOpenAL,
|
||||
kDirectSound,
|
||||
kXAudio2,
|
||||
kFaudio,
|
||||
|
||||
// Do not add anything under here.
|
||||
kLast,
|
||||
};
|
||||
constexpr size_t kNbAudioApis = static_cast<size_t>(AudioApi::kLast);
|
||||
|
||||
// These MUST follow the same order as the definitions of the enum above.
|
||||
// Adding an option without adding to this array will result in a compiler
|
||||
// error since kNbAudioApis is automatically updated.
|
||||
static const std::array<wxString, kNbAudioApis> kAudioApiStrings = {
|
||||
"sdl",
|
||||
"openal",
|
||||
"directsound",
|
||||
"xaudio2",
|
||||
"faudio",
|
||||
};
|
||||
|
||||
enum class SoundQuality {
|
||||
k48kHz = 0,
|
||||
k44kHz,
|
||||
k22kHz,
|
||||
k11kHz,
|
||||
|
||||
// Do not add anything under here.
|
||||
kLast,
|
||||
};
|
||||
constexpr size_t kNbSoundQualities = static_cast<size_t>(SoundQuality::kLast);
|
||||
|
||||
// These MUST follow the same order as the definitions of the enum above.
|
||||
// Adding an option without adding to this array will result in a compiler
|
||||
// error since kNbSoundQualities is automatically updated.
|
||||
static const std::array<wxString, kNbSoundQualities> kSoundQualityStrings = {
|
||||
"48",
|
||||
"44",
|
||||
"22",
|
||||
"11",
|
||||
};
|
||||
|
||||
// Builds the "all enum values" string for a given array defined above.
|
||||
template<std::size_t SIZE>
|
||||
wxString AllEnumValuesForArray(const std::array<wxString, SIZE>& input) {
|
||||
// 15 characters per option is a reasonable higher bound. Probably.
|
||||
static constexpr size_t kMaxOptionLength = 15u;
|
||||
|
||||
wxString all_options;
|
||||
all_options.reserve(kMaxOptionLength * SIZE);
|
||||
|
||||
std::for_each(input.cbegin(), input.cend(), [&all_options](const auto& elt) {
|
||||
all_options.append(elt);
|
||||
all_options.append('|');
|
||||
});
|
||||
// Remove last value
|
||||
all_options.RemoveLast(1u);
|
||||
return all_options;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
// static
|
||||
std::array<VbamOption, kNbOptions>& VbamOption::AllOptions() {
|
||||
// These MUST follow the same order as the definitions in VbamOptionID.
|
||||
// Adding an option without adding to this array will result in a compiler
|
||||
// error since kNbOptions is automatically updated.
|
||||
// This will be initialized on the first call, in load_opts(), ensuring the
|
||||
// translation initialization has already happened.
|
||||
static std::array<VbamOption, kNbOptions> g_all_opts = {
|
||||
/// Display
|
||||
VbamOption(VbamOptionID::kDisplayBilinear, &gopts.bilinear),
|
||||
VbamOption(VbamOptionID::kDisplayFilter, &gopts.filter),
|
||||
VbamOption(VbamOptionID::kDisplayFilterPlugin, &gopts.filter_plugin),
|
||||
VbamOption(VbamOptionID::kDisplayIFB, &gopts.ifb),
|
||||
VbamOption(VbamOptionID::kDisplayKeepOnTop, &gopts.keep_on_top),
|
||||
VbamOption(VbamOptionID::kDisplayMaxThreads, &gopts.max_threads, 1, 256),
|
||||
VbamOption(VbamOptionID::kDisplayRenderMethod, &gopts.render_method),
|
||||
VbamOption(VbamOptionID::kDisplayScale, &gopts.video_scale, 1, 6),
|
||||
VbamOption(VbamOptionID::kDisplayStretch, &gopts.retain_aspect),
|
||||
|
||||
/// GB
|
||||
VbamOption(VbamOptionID::kGBBiosFile, &gopts.gb_bios),
|
||||
VbamOption(VbamOptionID::kGBColorOption, &gbColorOption, 0, 1),
|
||||
VbamOption(VbamOptionID::kGBColorizerHack, &colorizerHack, 0, 1),
|
||||
VbamOption(VbamOptionID::kGBLCDFilter, &gbLcdFilter),
|
||||
VbamOption(VbamOptionID::kGBGBCBiosFile, &gopts.gbc_bios),
|
||||
VbamOption(VbamOptionID::kGBPalette0, systemGbPalette),
|
||||
VbamOption(VbamOptionID::kGBPalette1, systemGbPalette + 8),
|
||||
VbamOption(VbamOptionID::kGBPalette2, systemGbPalette + 16),
|
||||
VbamOption(VbamOptionID::kGBPrintAutoPage, &gopts.print_auto_page),
|
||||
VbamOption(VbamOptionID::kGBPrintScreenCap, &gopts.print_screen_cap),
|
||||
VbamOption(VbamOptionID::kGBROMDir, &gopts.gb_rom_dir),
|
||||
VbamOption(VbamOptionID::kGBGBCROMDir, &gopts.gbc_rom_dir),
|
||||
|
||||
/// GBA
|
||||
VbamOption(VbamOptionID::kGBABiosFile, &gopts.gba_bios),
|
||||
VbamOption(VbamOptionID::kGBALCDFilter, &gbaLcdFilter),
|
||||
#ifndef NO_LINK
|
||||
VbamOption(VbamOptionID::kGBALinkAuto, &gopts.link_auto),
|
||||
VbamOption(VbamOptionID::kGBALinkFast, &linkHacks, 0, 1),
|
||||
VbamOption(VbamOptionID::kGBALinkHost, &gopts.link_host),
|
||||
VbamOption(VbamOptionID::kGBAServerIP, &gopts.server_ip),
|
||||
VbamOption(VbamOptionID::kGBALinkPort, &gopts.link_port, 0, 65535),
|
||||
VbamOption(VbamOptionID::kGBALinkProto, &gopts.link_proto, 0, 1),
|
||||
VbamOption(VbamOptionID::kGBALinkTimeout, &linkTimeout, 0, 9999999),
|
||||
VbamOption(VbamOptionID::kGBALinkType, &gopts.gba_link_type, 0, 5),
|
||||
#endif
|
||||
VbamOption(VbamOptionID::kGBAROMDir, &gopts.gba_rom_dir),
|
||||
|
||||
/// General
|
||||
VbamOption(VbamOptionID::kGeneralAutoLoadLastState, &gopts.autoload_state),
|
||||
VbamOption(VbamOptionID::kGeneralBatteryDir, &gopts.battery_dir),
|
||||
VbamOption(VbamOptionID::kGeneralFreezeRecent, &gopts.recent_freeze),
|
||||
VbamOption(VbamOptionID::kGeneralRecordingDir, &gopts.recording_dir),
|
||||
VbamOption(VbamOptionID::kGeneralRewindInterval, &gopts.rewind_interval, 0, 600),
|
||||
VbamOption(VbamOptionID::kGeneralScreenshotDir, &gopts.scrshot_dir),
|
||||
VbamOption(VbamOptionID::kGeneralStateDir, &gopts.state_dir),
|
||||
VbamOption(VbamOptionID::kGeneralStatusBar, &gopts.statusbar, 0, 1),
|
||||
|
||||
/// Joypad
|
||||
VbamOption(VbamOptionID::kJoypad),
|
||||
VbamOption(VbamOptionID::kJoypadAutofireThrottle, &gopts.autofire_rate, 1, 1000),
|
||||
VbamOption(VbamOptionID::kJoypadDefault, &gopts.default_stick, 1, 4),
|
||||
|
||||
/// Keyboard
|
||||
VbamOption(VbamOptionID::kKeyboard),
|
||||
|
||||
// Core
|
||||
VbamOption(VbamOptionID::kpreferencesagbPrint, &agbPrint, 0, 1),
|
||||
VbamOption(VbamOptionID::kpreferencesautoFrameSkip, &autoFrameSkip, 0, 1),
|
||||
VbamOption(VbamOptionID::kpreferencesautoPatch, &autoPatch, 0, 1),
|
||||
VbamOption(VbamOptionID::kpreferencesautoSaveLoadCheatList, &gopts.autoload_cheats),
|
||||
VbamOption(VbamOptionID::kpreferencesborderAutomatic, &gbBorderAutomatic, 0, 1),
|
||||
VbamOption(VbamOptionID::kpreferencesborderOn, &gbBorderOn, 0, 1),
|
||||
VbamOption(VbamOptionID::kpreferencescaptureFormat, &captureFormat, 0, 1),
|
||||
VbamOption(VbamOptionID::kpreferencescheatsEnabled, &cheatsEnabled, 0, 1),
|
||||
#ifdef MMX
|
||||
VbamOption(VbamOptionID::kpreferencesenableMMX, &enableMMX, 0, 1),
|
||||
#endif
|
||||
VbamOption(VbamOptionID::kpreferencesdisableStatus, &disableStatusMessages, 0, 1),
|
||||
VbamOption(VbamOptionID::kpreferencesemulatorType, &gbEmulatorType, 0, 5),
|
||||
VbamOption(VbamOptionID::kpreferencesflashSize, &optFlashSize, 0, 1),
|
||||
VbamOption(VbamOptionID::kpreferencesframeSkip, &frameSkip, -1, 9),
|
||||
VbamOption(VbamOptionID::kpreferencesfsColorDepth, &fsColorDepth, 0, 999),
|
||||
VbamOption(VbamOptionID::kpreferencesfsFrequency, &fsFrequency, 0, 999),
|
||||
VbamOption(VbamOptionID::kpreferencesfsHeight, &fsHeight, 0, 99999),
|
||||
VbamOption(VbamOptionID::kpreferencesfsWidth, &fsWidth, 0, 99999),
|
||||
VbamOption(VbamOptionID::kpreferencesgbPaletteOption, &gbPaletteOption, 0, 2),
|
||||
VbamOption(VbamOptionID::kpreferencesgbPrinter, &winGbPrinterEnabled, 0, 1),
|
||||
VbamOption(VbamOptionID::kpreferencesgdbBreakOnLoad, &gdbBreakOnLoad, 0, 1),
|
||||
VbamOption(VbamOptionID::kpreferencesgdbPort, &gdbPort, 0, 65535),
|
||||
#ifndef NO_LINK
|
||||
VbamOption(VbamOptionID::kpreferencesLinkNumPlayers, &linkNumPlayers, 2, 4),
|
||||
#endif
|
||||
VbamOption(VbamOptionID::kpreferencesmaxScale, &maxScale, 0, 100),
|
||||
VbamOption(VbamOptionID::kpreferencespauseWhenInactive, &pauseWhenInactive, 0, 1),
|
||||
VbamOption(VbamOptionID::kpreferencesrtcEnabled, &rtcEnabled, 0, 1),
|
||||
VbamOption(VbamOptionID::kpreferencessaveType, &cpuSaveType, 0, 5),
|
||||
VbamOption(VbamOptionID::kpreferencesshowSpeed, &showSpeed, 0, 2),
|
||||
VbamOption(VbamOptionID::kpreferencesshowSpeedTransparent, &showSpeedTransparent, 0, 1),
|
||||
VbamOption(VbamOptionID::kpreferencesskipBios, &skipBios, 0, 1),
|
||||
VbamOption(VbamOptionID::kpreferencesskipSaveGameCheats, &skipSaveGameCheats, 0, 1),
|
||||
VbamOption(VbamOptionID::kpreferencesskipSaveGameBattery, &skipSaveGameBattery, 0, 1),
|
||||
VbamOption(VbamOptionID::kpreferencesthrottle, &throttle, 0, 450),
|
||||
VbamOption(VbamOptionID::kpreferencesspeedupThrottle, &speedup_throttle, 0, 3000),
|
||||
VbamOption(VbamOptionID::kpreferencesspeedupFrameSkip, &speedup_frame_skip, 0, 300),
|
||||
VbamOption(VbamOptionID::kpreferencesspeedupThrottleFrameSkip, &speedup_throttle_frame_skip),
|
||||
VbamOption(VbamOptionID::kpreferencesuseBiosGB, &useBiosFileGB, 0, 1),
|
||||
VbamOption(VbamOptionID::kpreferencesuseBiosGBA, &useBiosFileGBA, 0, 1),
|
||||
VbamOption(VbamOptionID::kpreferencesuseBiosGBC, &useBiosFileGBC, 0, 1),
|
||||
VbamOption(VbamOptionID::kpreferencesvsync, &vsync, 0, 1),
|
||||
|
||||
/// Geometry
|
||||
VbamOption(VbamOptionID::kgeometryfullScreen, &fullScreen, 0, 1),
|
||||
VbamOption(VbamOptionID::kgeometryisMaximized, &windowMaximized, 0, 1),
|
||||
VbamOption(VbamOptionID::kgeometrywindowHeight, &windowHeight, 0, 99999),
|
||||
VbamOption(VbamOptionID::kgeometrywindowWidth, &windowWidth, 0, 99999),
|
||||
VbamOption(VbamOptionID::kgeometrywindowX, &windowPositionX, -1, 99999),
|
||||
VbamOption(VbamOptionID::kgeometrywindowY, &windowPositionY, -1, 99999),
|
||||
|
||||
/// UI
|
||||
VbamOption(VbamOptionID::kuiallowKeyboardBackgroundInput, &allowKeyboardBackgroundInput),
|
||||
VbamOption(VbamOptionID::kuiallowJoystickBackgroundInput, &allowJoystickBackgroundInput),
|
||||
VbamOption(VbamOptionID::kuihideMenuBar, &gopts.hide_menu_bar),
|
||||
|
||||
/// Sound
|
||||
VbamOption(VbamOptionID::kSoundAudioAPI, &gopts.audio_api),
|
||||
VbamOption(VbamOptionID::kSoundAudioDevice, &gopts.audio_dev),
|
||||
VbamOption(VbamOptionID::kSoundBuffers, &gopts.audio_buffers, 2, 10),
|
||||
VbamOption(VbamOptionID::kSoundEnable, &gopts.sound_en, 0, 0x30f),
|
||||
VbamOption(VbamOptionID::kSoundGBAFiltering, &gopts.gba_sound_filter, 0, 100),
|
||||
VbamOption(VbamOptionID::kSoundGBAInterpolation, &gopts.soundInterpolation),
|
||||
VbamOption(VbamOptionID::kSoundGBDeclicking, &gopts.gb_declick),
|
||||
VbamOption(VbamOptionID::kSoundGBEcho, &gopts.gb_echo, 0, 100),
|
||||
VbamOption(VbamOptionID::kSoundGBEnableEffects, &gopts.gb_effects_config_enabled),
|
||||
VbamOption(VbamOptionID::kSoundGBStereo, &gopts.gb_stereo, 0, 100),
|
||||
VbamOption(VbamOptionID::kSoundGBSurround, &gopts.gb_effects_config_surround),
|
||||
VbamOption(VbamOptionID::kSoundQuality, &gopts.sound_qual),
|
||||
VbamOption(VbamOptionID::kSoundVolume, &gopts.sound_vol, 0, 200),
|
||||
};
|
||||
return g_all_opts;
|
||||
}
|
||||
|
||||
namespace internal {
|
||||
|
||||
// These MUST follow the same order as the definitions in VbamOptionID.
|
||||
// Adding an option without adding to this array will result in a compiler
|
||||
// error since kNbOptions is automatically updated.
|
||||
const std::array<VbamOptionData, kNbOptions + 1> kAllOptionsData = {
|
||||
/// Display
|
||||
VbamOptionData { "Display/Bilinear", "Bilinear", _("Use bilinear filter with 3d renderer"), VbamOption::Type::kBool },
|
||||
VbamOptionData { "Display/Filter", "", _("Full-screen filter to apply"), VbamOption::Type::kFilter },
|
||||
VbamOptionData { "Display/FilterPlugin", "", _("Filter plugin library"), VbamOption::Type::kString },
|
||||
VbamOptionData { "Display/IFB", "", _("Interframe blending function"), VbamOption::Type::kInterframe },
|
||||
VbamOptionData { "Display/KeepOnTop", "KeepOnTop", _("Keep window on top"), VbamOption::Type::kBool },
|
||||
VbamOptionData { "Display/MaxThreads", "Multithread", _("Maximum number of threads to run filters in"), VbamOption::Type::kInt },
|
||||
VbamOptionData { "Display/RenderMethod", "", _("Render method; if unsupported, simple method will be used"), VbamOption::Type::kRenderMethod },
|
||||
VbamOptionData { "Display/Scale", "", _("Default scale factor"), VbamOption::Type::kDouble },
|
||||
VbamOptionData { "Display/Stretch", "RetainAspect", _("Retain aspect ratio when resizing"), VbamOption::Type::kBool },
|
||||
|
||||
/// GB
|
||||
VbamOptionData { "GB/BiosFile", "", _("BIOS file to use for GB, if enabled"), VbamOption::Type::kString },
|
||||
VbamOptionData { "GB/ColorOption", "GBColorOption", _("GB color enhancement, if enabled"), VbamOption::Type::kInt },
|
||||
VbamOptionData { "GB/ColorizerHack", "ColorizerHack", _("Enable DX Colorization Hacks"), VbamOption::Type::kInt },
|
||||
VbamOptionData { "GB/LCDFilter", "GBLcdFilter", _("Apply LCD filter, if enabled"), VbamOption::Type::kBool },
|
||||
VbamOptionData { "GB/GBCBiosFile", "", _("BIOS file to use for GBC, if enabled"), VbamOption::Type::kString },
|
||||
VbamOptionData { "GB/Palette0", "", _("The default palette, as 8 comma-separated 4-digit hex integers (rgb555)."), VbamOption::Type::kGbPalette },
|
||||
VbamOptionData { "GB/Palette1", "", _("The first user palette, as 8 comma-separated 4-digit hex integers (rgb555)."), VbamOption::Type::kGbPalette },
|
||||
VbamOptionData { "GB/Palette2", "", _("The second user palette, as 8 comma-separated 4-digit hex integers (rgb555)."), VbamOption::Type::kGbPalette },
|
||||
VbamOptionData { "GB/PrintAutoPage", "PrintGather", _("Automatically gather a full page before printing"), VbamOption::Type::kBool },
|
||||
VbamOptionData { "GB/PrintScreenCap", "PrintSnap", _("Automatically save printouts as screen captures with -print suffix"), VbamOption::Type::kBool },
|
||||
VbamOptionData { "GB/ROMDir", "", _("Directory to look for ROM files"), VbamOption::Type::kString },
|
||||
VbamOptionData { "GB/GBCROMDir", "", _("Directory to look for GBC ROM files"), VbamOption::Type::kString },
|
||||
|
||||
/// GBA
|
||||
VbamOptionData { "GBA/BiosFile", "", _("BIOS file to use, if enabled"), VbamOption::Type::kString },
|
||||
VbamOptionData { "GBA/LCDFilter", "GBALcdFilter", _("Apply LCD filter, if enabled"), VbamOption::Type::kBool },
|
||||
#ifndef NO_LINK
|
||||
VbamOptionData { "GBA/LinkAuto", "LinkAuto", _("Enable link at boot"), VbamOption::Type::kBool },
|
||||
VbamOptionData { "GBA/LinkFast", "SpeedOn", _("Enable faster network protocol by default"), VbamOption::Type::kInt },
|
||||
VbamOptionData { "GBA/LinkHost", "", _("Default network link client host"), VbamOption::Type::kString },
|
||||
VbamOptionData { "GBA/ServerIP", "", _("Default network link server IP to bind"), VbamOption::Type::kString },
|
||||
VbamOptionData { "GBA/LinkPort", "", _("Default network link port (server and client)"), VbamOption::Type::kUnsigned },
|
||||
VbamOptionData { "GBA/LinkProto", "LinkProto", _("Default network protocol"), VbamOption::Type::kInt },
|
||||
VbamOptionData { "GBA/LinkTimeout", "LinkTimeout", _("Link timeout (ms)"), VbamOption::Type::kInt },
|
||||
VbamOptionData { "GBA/LinkType", "LinkType", _("Link cable type"), VbamOption::Type::kInt },
|
||||
#endif
|
||||
VbamOptionData { "GBA/ROMDir", "", _("Directory to look for ROM files"), VbamOption::Type::kString },
|
||||
|
||||
/// General
|
||||
VbamOptionData { "General/AutoLoadLastState", "", _("Automatically load last saved state"), VbamOption::Type::kBool },
|
||||
VbamOptionData { "General/BatteryDir", "", _("Directory to store game save files (relative paths are relative to ROM; blank is config dir)"), VbamOption::Type::kString },
|
||||
VbamOptionData { "General/FreezeRecent", "", _("Freeze recent load list"), VbamOption::Type::kBool },
|
||||
VbamOptionData { "General/RecordingDir", "", _("Directory to store A/V and game recordings (relative paths are relative to ROM)"), VbamOption::Type::kString },
|
||||
VbamOptionData { "General/RewindInterval", "", _("Number of seconds between rewind snapshots (0 to disable)"), VbamOption::Type::kInt },
|
||||
VbamOptionData { "General/ScreenshotDir", "", _("Directory to store screenshots (relative paths are relative to ROM)"), VbamOption::Type::kString },
|
||||
VbamOptionData { "General/StateDir", "", _("Directory to store saved state files (relative paths are relative to BatteryDir)"), VbamOption::Type::kString },
|
||||
VbamOptionData { "General/StatusBar", "StatusBar", _("Enable status bar"), VbamOption::Type::kInt },
|
||||
|
||||
/// Joypad
|
||||
VbamOptionData { "Joypad/*/*", "", _("The parameter Joypad/<n>/<button> contains a comma-separated list of key names which map to joypad #<n> button <button>. Button is one of Up, Down, Left, Right, A, B, L, R, Select, Start, MotionUp, MotionDown, MotionLeft, MotionRight, AutoA, AutoB, Speed, Capture, GS"), VbamOption::Type::kNone },
|
||||
VbamOptionData { "Joypad/AutofireThrottle", "", _("The autofire toggle period, in frames (1/60 s)"), VbamOption::Type::kInt },
|
||||
VbamOptionData { "Joypad/Default", "", _("The number of the stick to use in single-player mode"), VbamOption::Type::kInt },
|
||||
|
||||
/// Keyboard
|
||||
VbamOptionData { "Keyboard/*", "", _("The parameter Keyboard/<cmd> contains a comma-separated list of key names (e.g. Alt-Shift-F1). When the named key is pressed, the command <cmd> is executed."), VbamOption::Type::kNone },
|
||||
|
||||
// Core
|
||||
VbamOptionData { "preferences/agbPrint", "AGBPrinter", _("Enable AGB debug print"), VbamOption::Type::kInt },
|
||||
VbamOptionData { "preferences/autoFrameSkip", "FrameSkipAuto", _("Auto skip frames."), VbamOption::Type::kInt },
|
||||
VbamOptionData { "preferences/autoPatch", "ApplyPatches", _("Apply IPS/UPS/IPF patches if found"), VbamOption::Type::kInt },
|
||||
VbamOptionData { "preferences/autoSaveLoadCheatList", "", _("Automatically save and load cheat list"), VbamOption::Type::kBool },
|
||||
VbamOptionData { "preferences/borderAutomatic", "", _("Automatically enable border for Super GameBoy games"), VbamOption::Type::kInt },
|
||||
VbamOptionData { "preferences/borderOn", "", _("Always enable border"), VbamOption::Type::kInt },
|
||||
VbamOptionData { "preferences/captureFormat", "", _("Screen capture file format"), VbamOption::Type::kInt },
|
||||
VbamOptionData { "preferences/cheatsEnabled", "", _("Enable cheats"), VbamOption::Type::kInt },
|
||||
#ifdef MMX
|
||||
VbamOptionData { "preferences/enableMMX", "MMX", _("Enable MMX"), VbamOption::Type::kInt },
|
||||
#endif
|
||||
VbamOptionData { "preferences/disableStatus", "NoStatusMsg", _("Disable on-screen status messages"), VbamOption::Type::kInt },
|
||||
VbamOptionData { "preferences/emulatorType", "", _("Type of system to emulate"), VbamOption::Type::kInt },
|
||||
VbamOptionData { "preferences/flashSize", "", _("Flash size 0 = 64KB 1 = 128KB"), VbamOption::Type::kInt },
|
||||
VbamOptionData { "preferences/frameSkip", "FrameSkip", _("Skip frames. Values are 0-9 or -1 to skip automatically based on time."), VbamOption::Type::kInt },
|
||||
VbamOptionData { "preferences/fsColorDepth", "", _("Fullscreen mode color depth (0 = any)"), VbamOption::Type::kInt },
|
||||
VbamOptionData { "preferences/fsFrequency", "", _("Fullscreen mode frequency (0 = any)"), VbamOption::Type::kInt },
|
||||
VbamOptionData { "preferences/fsHeight", "", _("Fullscreen mode height (0 = desktop)"), VbamOption::Type::kInt },
|
||||
VbamOptionData { "preferences/fsWidth", "", _("Fullscreen mode width (0 = desktop)"), VbamOption::Type::kInt },
|
||||
VbamOptionData { "preferences/gbPaletteOption", "", _("The palette to use"), VbamOption::Type::kInt },
|
||||
VbamOptionData { "preferences/gbPrinter", "Printer", _("Enable printer emulation"), VbamOption::Type::kInt },
|
||||
VbamOptionData { "preferences/gdbBreakOnLoad", "DebugGDBBreakOnLoad", _("Break into GDB after loading the game."), VbamOption::Type::kInt },
|
||||
VbamOptionData { "preferences/gdbPort", "DebugGDBPort", _("Port to connect GDB to."), VbamOption::Type::kInt },
|
||||
#ifndef NO_LINK
|
||||
VbamOptionData { "preferences/LinkNumPlayers", "", _("Number of players in network"), VbamOption::Type::kInt },
|
||||
#endif
|
||||
VbamOptionData { "preferences/maxScale", "", _("Maximum scale factor (0 = no limit)"), VbamOption::Type::kInt },
|
||||
VbamOptionData { "preferences/pauseWhenInactive", "PauseWhenInactive", _("Pause game when main window loses focus"), VbamOption::Type::kInt },
|
||||
VbamOptionData { "preferences/rtcEnabled", "RTC", _("Enable RTC (vba-over.ini override is rtcEnabled"), VbamOption::Type::kInt },
|
||||
VbamOptionData { "preferences/saveType", "", _("Native save (\"battery\") hardware type"), VbamOption::Type::kInt },
|
||||
VbamOptionData { "preferences/showSpeed", "", _("Show speed indicator"), VbamOption::Type::kInt },
|
||||
VbamOptionData { "preferences/showSpeedTransparent", "Transparent", _("Draw on-screen messages transparently"), VbamOption::Type::kInt },
|
||||
VbamOptionData { "preferences/skipBios", "SkipIntro", _("Skip BIOS initialization"), VbamOption::Type::kInt },
|
||||
VbamOptionData { "preferences/skipSaveGameCheats", "", _("Do not overwrite cheat list when loading state"), VbamOption::Type::kInt },
|
||||
VbamOptionData { "preferences/skipSaveGameBattery", "", _("Do not overwrite native (battery) save when loading state"), VbamOption::Type::kInt },
|
||||
VbamOptionData { "preferences/throttle", "", _("Throttle game speed, even when accelerated (0-450%, 0 = no throttle)"), VbamOption::Type::kUnsigned },
|
||||
VbamOptionData { "preferences/speedupThrottle", "", _("Set throttle for speedup key (0-3000%, 0 = no throttle)"), VbamOption::Type::kUnsigned },
|
||||
VbamOptionData { "preferences/speedupFrameSkip", "", _("Number of frames to skip with speedup (instead of speedup throttle)"), VbamOption::Type::kUnsigned },
|
||||
VbamOptionData { "preferences/speedupThrottleFrameSkip", "", _("Use frame skip for speedup throttle"), VbamOption::Type::kBool },
|
||||
VbamOptionData { "preferences/useBiosGB", "BootRomGB", _("Use the specified BIOS file for GB"), VbamOption::Type::kInt },
|
||||
VbamOptionData { "preferences/useBiosGBA", "BootRomEn", _("Use the specified BIOS file"), VbamOption::Type::kInt },
|
||||
VbamOptionData { "preferences/useBiosGBC", "BootRomGBC", _("Use the specified BIOS file for GBC"), VbamOption::Type::kInt },
|
||||
VbamOptionData { "preferences/vsync", "VSync", _("Wait for vertical sync"), VbamOption::Type::kInt },
|
||||
|
||||
/// Geometry
|
||||
VbamOptionData { "geometry/fullScreen", "Fullscreen", _("Enter fullscreen mode at startup"), VbamOption::Type::kInt },
|
||||
VbamOptionData { "geometry/isMaximized", "Maximized", _("Window maximized"), VbamOption::Type::kInt },
|
||||
VbamOptionData { "geometry/windowHeight", "Height", _("Window height at startup"), VbamOption::Type::kUnsigned },
|
||||
VbamOptionData { "geometry/windowWidth", "Width", _("Window width at startup"), VbamOption::Type::kUnsigned },
|
||||
VbamOptionData { "geometry/windowX", "X", _("Window axis X position at startup"), VbamOption::Type::kInt },
|
||||
VbamOptionData { "geometry/windowY", "Y", _("Window axis Y position at startup"), VbamOption::Type::kInt },
|
||||
|
||||
/// UI
|
||||
VbamOptionData { "ui/allowKeyboardBackgroundInput", "AllowKeyboardBackgroundInput", _("Capture key events while on background"), VbamOption::Type::kBool },
|
||||
VbamOptionData { "ui/allowJoystickBackgroundInput", "AllowJoystickBackgroundInput", _("Capture joy events while on background"), VbamOption::Type::kBool },
|
||||
VbamOptionData { "ui/hideMenuBar", "", _("Hide menu bar when mouse is inactive"), VbamOption::Type::kBool },
|
||||
|
||||
/// Sound
|
||||
VbamOptionData { "Sound/AudioAPI", "", _("Sound API; if unsupported, default API will be used"), VbamOption::Type::kAudioApi },
|
||||
VbamOptionData { "Sound/AudioDevice", "", _("Device ID of chosen audio device for chosen driver"), VbamOption::Type::kString },
|
||||
VbamOptionData { "Sound/Buffers", "", _("Number of sound buffers"), VbamOption::Type::kInt },
|
||||
VbamOptionData { "Sound/Enable", "", _("Bit mask of sound channels to enable"), VbamOption::Type::kInt },
|
||||
VbamOptionData { "Sound/GBAFiltering", "", _("GBA sound filtering (%)"), VbamOption::Type::kInt },
|
||||
VbamOptionData { "Sound/GBAInterpolation", "GBASoundInterpolation", _("GBA sound interpolation"), VbamOption::Type::kBool },
|
||||
VbamOptionData { "Sound/GBDeclicking", "GBDeclicking", _("GB sound declicking"), VbamOption::Type::kBool },
|
||||
VbamOptionData { "Sound/GBEcho", "", _("GB echo effect (%)"), VbamOption::Type::kInt },
|
||||
VbamOptionData { "Sound/GBEnableEffects", "GBEnhanceSound", _("Enable GB sound effects"), VbamOption::Type::kBool },
|
||||
VbamOptionData { "Sound/GBStereo", "", _("GB stereo effect (%)"), VbamOption::Type::kInt },
|
||||
VbamOptionData { "Sound/GBSurround", "GBSurround", _("GB surround sound effect (%)"), VbamOption::Type::kBool },
|
||||
VbamOptionData { "Sound/Quality", "", _("Sound sample rate (kHz)"), VbamOption::Type::kSoundQuality },
|
||||
VbamOptionData { "Sound/Volume", "", _("Sound volume (%)"), VbamOption::Type::kInt },
|
||||
|
||||
// Last. This should never be used, it actually maps to VbamOptionID::kLast.
|
||||
// This is to prevent a memory access violation error in case something
|
||||
// attempts to instantiate a VbamOptionID::kLast. It will trigger a check
|
||||
// in the VbamOption constructor, but that is after the constructor has
|
||||
// accessed this entry.
|
||||
VbamOptionData { "", "", "", VbamOption::Type::kNone },
|
||||
};
|
||||
|
||||
nonstd::optional<VbamOptionID> StringToOptionId(const wxString& input) {
|
||||
static std::map<wxString, VbamOptionID> kStringToOptionId;
|
||||
if (kStringToOptionId.empty()) {
|
||||
for (size_t i = 0; i < kNbOptions; i++) {
|
||||
kStringToOptionId.emplace(
|
||||
kAllOptionsData[i].config_name, static_cast<VbamOptionID>(i));
|
||||
}
|
||||
assert(kStringToOptionId.size() == kNbOptions);
|
||||
}
|
||||
|
||||
const auto iter = kStringToOptionId.find(input);
|
||||
if (iter == kStringToOptionId.end()) {
|
||||
return nonstd::nullopt;
|
||||
}
|
||||
return iter->second;
|
||||
}
|
||||
|
||||
wxString FilterToString(int value) {
|
||||
assert(value >= 0 && static_cast<size_t>(value) < kNbFilterFunctions);
|
||||
return kFilterStrings[value];
|
||||
}
|
||||
|
||||
wxString InterframeToString(int value) {
|
||||
assert(value >= 0 && static_cast<size_t>(value) < kNbInterframes);
|
||||
return kInterframeStrings[value];
|
||||
}
|
||||
|
||||
wxString RenderMethodToString(int value) {
|
||||
assert(value >= 0 && static_cast<size_t>(value) < kNbRenderMethods);
|
||||
return kRenderMethodStrings[value];
|
||||
}
|
||||
|
||||
wxString AudioApiToString(int value) {
|
||||
assert(value >= 0 && static_cast<size_t>(value) < kNbAudioApis);
|
||||
return kAudioApiStrings[value];
|
||||
}
|
||||
|
||||
wxString SoundQualityToString(int value) {
|
||||
assert(value >= 0 && static_cast<size_t>(value) < kNbSoundQualities);
|
||||
return kSoundQualityStrings[value];
|
||||
}
|
||||
|
||||
int StringToFilter(const wxString& config_name, const wxString& input) {
|
||||
static std::map<wxString, FilterFunction> kStringToFilter;
|
||||
if (kStringToFilter.empty()) {
|
||||
for (size_t i = 0; i < kNbFilterFunctions; i++) {
|
||||
kStringToFilter.emplace(
|
||||
kFilterStrings[i], static_cast<FilterFunction>(i));
|
||||
}
|
||||
assert(kStringToFilter.size() == kNbFilterFunctions);
|
||||
}
|
||||
|
||||
const auto iter = kStringToFilter.find(input);
|
||||
if (iter == kStringToFilter.end()) {
|
||||
wxLogWarning(_("Invalid value %s for option %s; valid values are %s"),
|
||||
input,
|
||||
config_name,
|
||||
AllEnumValuesForType(VbamOption::Type::kFilter));
|
||||
return 0;
|
||||
}
|
||||
return static_cast<int>(iter->second);
|
||||
}
|
||||
|
||||
int StringToInterframe(const wxString& config_name, const wxString& input) {
|
||||
static std::map<wxString, Interframe> kStringToInterframe;
|
||||
if (kStringToInterframe.empty()) {
|
||||
for (size_t i = 0; i < kNbInterframes; i++) {
|
||||
kStringToInterframe.emplace(
|
||||
kInterframeStrings[i], static_cast<Interframe>(i));
|
||||
}
|
||||
assert(kStringToInterframe.size() == kNbInterframes);
|
||||
}
|
||||
|
||||
const auto iter = kStringToInterframe.find(input);
|
||||
if (iter == kStringToInterframe.end()) {
|
||||
wxLogWarning(_("Invalid value %s for option %s; valid values are %s"),
|
||||
input,
|
||||
config_name,
|
||||
AllEnumValuesForType(VbamOption::Type::kInterframe));
|
||||
return 0;
|
||||
}
|
||||
return static_cast<int>(iter->second);
|
||||
}
|
||||
|
||||
int StringToRenderMethod(const wxString& config_name, const wxString& input) {
|
||||
static std::map<wxString, RenderMethod> kStringToRenderMethod;
|
||||
if (kStringToRenderMethod.empty()) {
|
||||
for (size_t i = 0; i < kNbRenderMethods; i++) {
|
||||
kStringToRenderMethod.emplace(kRenderMethodStrings[i], static_cast<RenderMethod>(i));
|
||||
}
|
||||
assert(kStringToRenderMethod.size() == kNbRenderMethods);
|
||||
}
|
||||
|
||||
const auto iter = kStringToRenderMethod.find(input);
|
||||
if (iter == kStringToRenderMethod.end()) {
|
||||
wxLogWarning(_("Invalid value %s for option %s; valid values are %s"),
|
||||
input,
|
||||
config_name,
|
||||
AllEnumValuesForType(VbamOption::Type::kRenderMethod));
|
||||
return 0;
|
||||
}
|
||||
return static_cast<int>(iter->second);
|
||||
}
|
||||
|
||||
int StringToAudioApi(const wxString& config_name, const wxString& input) {
|
||||
static std::map<wxString, AudioApi> kStringToAudioApi;
|
||||
if (kStringToAudioApi.empty()) {
|
||||
for (size_t i = 0; i < kNbAudioApis; i++) {
|
||||
kStringToAudioApi.emplace(kAudioApiStrings[i], static_cast<AudioApi>(i));
|
||||
}
|
||||
assert(kStringToAudioApi.size() == kNbAudioApis);
|
||||
}
|
||||
|
||||
const auto iter = kStringToAudioApi.find(input);
|
||||
if (iter == kStringToAudioApi.end()) {
|
||||
wxLogWarning(_("Invalid value %s for option %s; valid values are %s"),
|
||||
input,
|
||||
config_name,
|
||||
AllEnumValuesForType(VbamOption::Type::kAudioApi));
|
||||
return 0;
|
||||
}
|
||||
return static_cast<int>(iter->second);
|
||||
}
|
||||
|
||||
int StringToSoundQuality(const wxString& config_name, const wxString& input) {
|
||||
static std::map<wxString, SoundQuality> kStringToSoundQuality;
|
||||
if (kStringToSoundQuality.empty()) {
|
||||
for (size_t i = 0; i < kNbSoundQualities; i++) {
|
||||
kStringToSoundQuality.emplace(kSoundQualityStrings[i], static_cast<SoundQuality>(i));
|
||||
}
|
||||
assert(kStringToSoundQuality.size() == kNbSoundQualities);
|
||||
}
|
||||
|
||||
const auto iter = kStringToSoundQuality.find(input);
|
||||
if (iter == kStringToSoundQuality.end()) {
|
||||
wxLogWarning(_("Invalid value %s for option %s; valid values are %s"),
|
||||
input,
|
||||
config_name,
|
||||
AllEnumValuesForType(VbamOption::Type::kSoundQuality));
|
||||
return 0;
|
||||
}
|
||||
return static_cast<int>(iter->second);
|
||||
|
||||
}
|
||||
|
||||
wxString AllEnumValuesForType(VbamOption::Type type) {
|
||||
switch (type) {
|
||||
case VbamOption::Type::kFilter: {
|
||||
static const wxString kAllFilterValues = AllEnumValuesForArray(kFilterStrings);
|
||||
return kAllFilterValues;
|
||||
}
|
||||
case VbamOption::Type::kInterframe: {
|
||||
static const wxString kAllInterframeValues = AllEnumValuesForArray(kInterframeStrings);
|
||||
return kAllInterframeValues;
|
||||
}
|
||||
case VbamOption::Type::kRenderMethod: {
|
||||
static const wxString kAllRenderValues = AllEnumValuesForArray(kRenderMethodStrings);
|
||||
return kAllRenderValues;
|
||||
}
|
||||
case VbamOption::Type::kAudioApi: {
|
||||
static const wxString kAllAudioApiValues = AllEnumValuesForArray(kAudioApiStrings);
|
||||
return kAllAudioApiValues;
|
||||
}
|
||||
case VbamOption::Type::kSoundQuality: {
|
||||
static const wxString kAllSoundQualityValues = AllEnumValuesForArray(kSoundQualityStrings);
|
||||
return kAllSoundQualityValues;
|
||||
}
|
||||
|
||||
// We don't use default here to explicitly trigger a compiler warning when
|
||||
// adding a new value.
|
||||
case VbamOption::Type::kNone:
|
||||
case VbamOption::Type::kBool:
|
||||
case VbamOption::Type::kDouble:
|
||||
case VbamOption::Type::kInt:
|
||||
case VbamOption::Type::kUnsigned:
|
||||
case VbamOption::Type::kString:
|
||||
case VbamOption::Type::kGbPalette:
|
||||
assert(false);
|
||||
return wxEmptyString;
|
||||
}
|
||||
assert(false);
|
||||
return wxEmptyString;
|
||||
}
|
||||
|
||||
int MaxForType(VbamOption::Type type) {
|
||||
switch (type) {
|
||||
case VbamOption::Type::kFilter:
|
||||
return kNbFilterFunctions;
|
||||
case VbamOption::Type::kInterframe:
|
||||
return kNbInterframes;
|
||||
case VbamOption::Type::kRenderMethod:
|
||||
return kNbRenderMethods;
|
||||
case VbamOption::Type::kAudioApi:
|
||||
return kNbAudioApis;
|
||||
case VbamOption::Type::kSoundQuality:
|
||||
return kNbSoundQualities;
|
||||
|
||||
// We don't use default here to explicitly trigger a compiler warning when
|
||||
// adding a new value.
|
||||
case VbamOption::Type::kNone:
|
||||
case VbamOption::Type::kBool:
|
||||
case VbamOption::Type::kDouble:
|
||||
case VbamOption::Type::kInt:
|
||||
case VbamOption::Type::kUnsigned:
|
||||
case VbamOption::Type::kString:
|
||||
case VbamOption::Type::kGbPalette:
|
||||
assert(false);
|
||||
return 0;
|
||||
}
|
||||
assert(false);
|
||||
return 0;
|
||||
}
|
||||
|
||||
} // namespace internal
|
|
@ -1,369 +0,0 @@
|
|||
#include "vbam-options.h"
|
||||
|
||||
#include "nonstd/variant.hpp"
|
||||
|
||||
#include <wx/log.h>
|
||||
#include <wx/translation.h>
|
||||
|
||||
#define VBAM_OPTIONS_INTERNAL_INCLUDE
|
||||
#include "vbam-options-internal.h"
|
||||
#undef VBAM_OPTIONS_INTERNAL_INCLUDE
|
||||
|
||||
// static
|
||||
VbamOption const* VbamOption::FindOptionByName(const wxString &config_name) {
|
||||
nonstd::optional<VbamOptionID> option_id = internal::StringToOptionId(config_name);
|
||||
if (!option_id) {
|
||||
return nullptr;
|
||||
}
|
||||
return &FindOptionByID(option_id.value());
|
||||
}
|
||||
|
||||
// static
|
||||
VbamOption& VbamOption::FindOptionByID(VbamOptionID id) {
|
||||
assert (id != VbamOptionID::Last);
|
||||
return AllOptions()[static_cast<size_t>(id)];
|
||||
}
|
||||
|
||||
VbamOption::~VbamOption() = default;
|
||||
|
||||
VbamOption::VbamOption(VbamOptionID id) :
|
||||
id_(id),
|
||||
config_name_(internal::kAllOptionsData[static_cast<size_t>(id)].config_name),
|
||||
command_(internal::kAllOptionsData[static_cast<size_t>(id)].command),
|
||||
ux_helper_(wxGetTranslation(internal::kAllOptionsData[static_cast<size_t>(id)].ux_helper)),
|
||||
type_(internal::kAllOptionsData[static_cast<size_t>(id)].type),
|
||||
value_(),
|
||||
min_(),
|
||||
max_() {
|
||||
assert(id != VbamOptionID::Last);
|
||||
assert(is_none());
|
||||
}
|
||||
|
||||
VbamOption::VbamOption(VbamOptionID id, bool* option) :
|
||||
id_(id),
|
||||
config_name_(internal::kAllOptionsData[static_cast<size_t>(id)].config_name),
|
||||
command_(internal::kAllOptionsData[static_cast<size_t>(id)].command),
|
||||
ux_helper_(wxGetTranslation(internal::kAllOptionsData[static_cast<size_t>(id)].ux_helper)),
|
||||
type_(internal::kAllOptionsData[static_cast<size_t>(id)].type),
|
||||
value_(option),
|
||||
min_(),
|
||||
max_() {
|
||||
assert(id != VbamOptionID::Last);
|
||||
assert(is_bool());
|
||||
}
|
||||
|
||||
VbamOption::VbamOption(VbamOptionID id, double* option, double min, double max) :
|
||||
id_(id),
|
||||
config_name_(internal::kAllOptionsData[static_cast<size_t>(id)].config_name),
|
||||
command_(internal::kAllOptionsData[static_cast<size_t>(id)].command),
|
||||
ux_helper_(wxGetTranslation(internal::kAllOptionsData[static_cast<size_t>(id)].ux_helper)),
|
||||
type_(internal::kAllOptionsData[static_cast<size_t>(id)].type),
|
||||
value_(option),
|
||||
min_(min),
|
||||
max_(max) {
|
||||
assert(id != VbamOptionID::Last);
|
||||
assert(is_double());
|
||||
|
||||
// Validate the initial value.
|
||||
SetDouble(*option);
|
||||
}
|
||||
|
||||
VbamOption::VbamOption(VbamOptionID id, int32_t* option, int32_t min, int32_t max) :
|
||||
id_(id),
|
||||
config_name_(internal::kAllOptionsData[static_cast<size_t>(id)].config_name),
|
||||
command_(internal::kAllOptionsData[static_cast<size_t>(id)].command),
|
||||
ux_helper_(wxGetTranslation(internal::kAllOptionsData[static_cast<size_t>(id)].ux_helper)),
|
||||
type_(internal::kAllOptionsData[static_cast<size_t>(id)].type),
|
||||
value_(option),
|
||||
min_(min),
|
||||
max_(max) {
|
||||
assert(id != VbamOptionID::Last);
|
||||
assert(is_int());
|
||||
|
||||
// Validate the initial value.
|
||||
SetInt(*option);
|
||||
}
|
||||
|
||||
VbamOption::VbamOption(VbamOptionID id, uint32_t* option, uint32_t min, uint32_t max) :
|
||||
id_(id),
|
||||
config_name_(internal::kAllOptionsData[static_cast<size_t>(id)].config_name),
|
||||
command_(internal::kAllOptionsData[static_cast<size_t>(id)].command),
|
||||
ux_helper_(wxGetTranslation(internal::kAllOptionsData[static_cast<size_t>(id)].ux_helper)),
|
||||
type_(internal::kAllOptionsData[static_cast<size_t>(id)].type),
|
||||
value_(option),
|
||||
min_(min),
|
||||
max_(max) {
|
||||
assert(id != VbamOptionID::Last);
|
||||
assert(is_unsigned());
|
||||
|
||||
// Validate the initial value.
|
||||
SetUnsigned(*option);
|
||||
}
|
||||
|
||||
VbamOption::VbamOption(VbamOptionID id, wxString* option) :
|
||||
id_(id),
|
||||
config_name_(internal::kAllOptionsData[static_cast<size_t>(id)].config_name),
|
||||
command_(internal::kAllOptionsData[static_cast<size_t>(id)].command),
|
||||
ux_helper_(wxGetTranslation(internal::kAllOptionsData[static_cast<size_t>(id)].ux_helper)),
|
||||
type_(internal::kAllOptionsData[static_cast<size_t>(id)].type),
|
||||
value_(option),
|
||||
min_(),
|
||||
max_() {
|
||||
assert(id != VbamOptionID::Last);
|
||||
assert(is_string());
|
||||
}
|
||||
|
||||
VbamOption::VbamOption(VbamOptionID id, int* option) :
|
||||
id_(id),
|
||||
config_name_(internal::kAllOptionsData[static_cast<size_t>(id)].config_name),
|
||||
command_(internal::kAllOptionsData[static_cast<size_t>(id)].command),
|
||||
ux_helper_(wxGetTranslation(internal::kAllOptionsData[static_cast<size_t>(id)].ux_helper)),
|
||||
type_(internal::kAllOptionsData[static_cast<size_t>(id)].type),
|
||||
value_(option),
|
||||
min_(0),
|
||||
max_(internal::MaxForType(type_)) {
|
||||
assert(id != VbamOptionID::Last);
|
||||
assert(is_filter() || is_interframe() || is_render_method() || is_audio_api() || is_sound_quality());
|
||||
|
||||
// Validate the initial value.
|
||||
SetEnumInt(*option);
|
||||
}
|
||||
|
||||
VbamOption::VbamOption(VbamOptionID id, uint16_t* option) :
|
||||
id_(id),
|
||||
config_name_(internal::kAllOptionsData[static_cast<size_t>(id)].config_name),
|
||||
command_(internal::kAllOptionsData[static_cast<size_t>(id)].command),
|
||||
ux_helper_(wxGetTranslation(internal::kAllOptionsData[static_cast<size_t>(id)].ux_helper)),
|
||||
type_(internal::kAllOptionsData[static_cast<size_t>(id)].type),
|
||||
value_(option),
|
||||
min_(),
|
||||
max_() {
|
||||
assert(id != VbamOptionID::Last);
|
||||
assert(is_gb_palette());
|
||||
}
|
||||
|
||||
bool VbamOption::GetBool() const {
|
||||
assert(is_bool());
|
||||
return *(nonstd::get<bool*>(value_));
|
||||
}
|
||||
|
||||
double VbamOption::GetDouble() const {
|
||||
assert(is_double());
|
||||
return *(nonstd::get<double*>(value_));
|
||||
}
|
||||
|
||||
int32_t VbamOption::GetInt() const {
|
||||
assert(is_int());
|
||||
return *(nonstd::get<int32_t*>(value_));
|
||||
}
|
||||
|
||||
uint32_t VbamOption::GetUnsigned() const {
|
||||
assert(is_unsigned());
|
||||
return *(nonstd::get<uint32_t*>(value_));
|
||||
}
|
||||
|
||||
const wxString VbamOption::GetString() const {
|
||||
assert(is_string());
|
||||
return *(nonstd::get<wxString*>(value_));
|
||||
}
|
||||
|
||||
wxString VbamOption::GetEnumString() const {
|
||||
switch (type_) {
|
||||
case VbamOption::Type::kFilter:
|
||||
return internal::FilterToString(*(nonstd::get<int32_t*>(value_)));
|
||||
case VbamOption::Type::kInterframe:
|
||||
return internal::InterframeToString(*(nonstd::get<int32_t*>(value_)));
|
||||
case VbamOption::Type::kRenderMethod:
|
||||
return internal::RenderMethodToString(*(nonstd::get<int32_t*>(value_)));
|
||||
case VbamOption::Type::kAudioApi:
|
||||
return internal::AudioApiToString(*(nonstd::get<int32_t*>(value_)));
|
||||
case VbamOption::Type::kSoundQuality:
|
||||
return internal::SoundQualityToString(*(nonstd::get<int32_t*>(value_)));
|
||||
|
||||
// We don't use default here to explicitly trigger a compiler warning when
|
||||
// adding a new value.
|
||||
case VbamOption::Type::kNone:
|
||||
case VbamOption::Type::kBool:
|
||||
case VbamOption::Type::kDouble:
|
||||
case VbamOption::Type::kInt:
|
||||
case VbamOption::Type::kUnsigned:
|
||||
case VbamOption::Type::kString:
|
||||
case VbamOption::Type::kGbPalette:
|
||||
assert(false);
|
||||
return wxEmptyString;
|
||||
}
|
||||
assert(false);
|
||||
return wxEmptyString;
|
||||
}
|
||||
|
||||
wxString VbamOption::GetGbPaletteString() const {
|
||||
assert(is_gb_palette());
|
||||
|
||||
wxString palette_string;
|
||||
uint16_t const* value = nonstd::get<uint16_t*>(value_);
|
||||
palette_string.Printf("%04X,%04X,%04X,%04X,%04X,%04X,%04X,%04X",
|
||||
value[0], value[1], value[2], value[3],
|
||||
value[4], value[5], value[6], value[7]);
|
||||
return palette_string;
|
||||
}
|
||||
|
||||
void VbamOption::SetBool(bool value) const {
|
||||
assert(is_bool());
|
||||
*nonstd::get<bool*>(value_) = value;
|
||||
}
|
||||
|
||||
void VbamOption::SetDouble(double value) const {
|
||||
assert(is_double());
|
||||
if (value < nonstd::get<double>(min_) || value > nonstd::get<double>(max_)) {
|
||||
wxLogWarning(
|
||||
_("Invalid value %f for option %s; valid values are %f - %f"),
|
||||
value,
|
||||
config_name_,
|
||||
nonstd::get<double>(min_),
|
||||
nonstd::get<double>(max_));
|
||||
return;
|
||||
}
|
||||
*nonstd::get<double*>(value_) = value;
|
||||
}
|
||||
|
||||
void VbamOption::SetInt(int32_t value) const {
|
||||
assert(is_int());
|
||||
if (value < nonstd::get<int32_t>(min_) || value > nonstd::get<int32_t>(max_)) {
|
||||
wxLogWarning(
|
||||
_("Invalid value %d for option %s; valid values are %d - %d"),
|
||||
value,
|
||||
config_name_,
|
||||
nonstd::get<int32_t>(min_),
|
||||
nonstd::get<int32_t>(max_));
|
||||
return;
|
||||
}
|
||||
*nonstd::get<int32_t*>(value_) = value;
|
||||
}
|
||||
|
||||
void VbamOption::SetUnsigned(uint32_t value) const {
|
||||
assert(is_unsigned());
|
||||
if (value < nonstd::get<uint32_t>(min_) || value > nonstd::get<uint32_t>(max_)) {
|
||||
wxLogWarning(
|
||||
_("Invalid value %d for option %s; valid values are %d - %d"),
|
||||
value,
|
||||
config_name_,
|
||||
nonstd::get<uint32_t>(min_),
|
||||
nonstd::get<uint32_t>(max_));
|
||||
return;
|
||||
}
|
||||
*nonstd::get<uint32_t*>(value_) = value;
|
||||
}
|
||||
|
||||
void VbamOption::SetString(const wxString& value) const {
|
||||
assert(is_string());
|
||||
*nonstd::get<wxString*>(value_) = value;
|
||||
}
|
||||
|
||||
void VbamOption::SetEnumString(const wxString& value) const {
|
||||
switch (type_) {
|
||||
case VbamOption::Type::kFilter:
|
||||
SetEnumInt(internal::StringToFilter(config_name_, value));
|
||||
return;
|
||||
case VbamOption::Type::kInterframe:
|
||||
SetEnumInt(internal::StringToInterframe(config_name_, value));
|
||||
return;
|
||||
case VbamOption::Type::kRenderMethod:
|
||||
SetEnumInt(internal::StringToRenderMethod(config_name_, value));
|
||||
return;
|
||||
case VbamOption::Type::kAudioApi:
|
||||
SetEnumInt(internal::StringToAudioApi(config_name_, value));
|
||||
return;
|
||||
case VbamOption::Type::kSoundQuality:
|
||||
SetEnumInt(internal::StringToSoundQuality(config_name_, value));
|
||||
return;
|
||||
|
||||
// We don't use default here to explicitly trigger a compiler warning when
|
||||
// adding a new value.
|
||||
case VbamOption::Type::kNone:
|
||||
case VbamOption::Type::kBool:
|
||||
case VbamOption::Type::kDouble:
|
||||
case VbamOption::Type::kInt:
|
||||
case VbamOption::Type::kUnsigned:
|
||||
case VbamOption::Type::kString:
|
||||
case VbamOption::Type::kGbPalette:
|
||||
assert(false);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void VbamOption::SetEnumInt(int value) const {
|
||||
assert(is_filter() || is_interframe() || is_render_method() || is_audio_api() || is_sound_quality());
|
||||
if (value < nonstd::get<int32_t>(min_) || value > nonstd::get<int32_t>(max_)) {
|
||||
wxLogWarning(
|
||||
_("Invalid value %d for option %s; valid values are %s"),
|
||||
value,
|
||||
config_name_,
|
||||
internal::AllEnumValuesForType(type_));
|
||||
return;
|
||||
}
|
||||
*nonstd::get<int32_t*>(value_) = value;
|
||||
}
|
||||
|
||||
void VbamOption::SetGbPalette(const wxString& value) const {
|
||||
assert(is_gb_palette());
|
||||
|
||||
// 8 values of 4 chars and 7 commas.
|
||||
static constexpr size_t kPaletteStringSize = 8 * 4 + 7;
|
||||
|
||||
if (value.size() != kPaletteStringSize) {
|
||||
wxLogWarning(_("Invalid value %s for option %s"),
|
||||
value,
|
||||
config_name_);
|
||||
return;
|
||||
}
|
||||
uint16_t* dest = nonstd::get<uint16_t*>(value_);
|
||||
|
||||
for (size_t i = 0; i < 8; i++) {
|
||||
wxString number = value.substr(i * 5, 4);
|
||||
long temp = 0;
|
||||
if (number.ToLong(&temp, 16)) {
|
||||
dest[i] = temp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
wxString VbamOption::ToHelperString() const {
|
||||
wxString helper_string = config_name_;
|
||||
|
||||
switch (type_) {
|
||||
case VbamOption::Type::kNone:
|
||||
break;
|
||||
case VbamOption::Type::kBool:
|
||||
helper_string.Append(" (flag)");
|
||||
break;
|
||||
case VbamOption::Type::kDouble:
|
||||
helper_string.Append(" (decimal)");
|
||||
break;
|
||||
case VbamOption::Type::kInt:
|
||||
helper_string.Append(" (int)");
|
||||
break;
|
||||
case VbamOption::Type::kUnsigned:
|
||||
helper_string.Append(" (unsigned)");
|
||||
break;
|
||||
case VbamOption::Type::kString:
|
||||
helper_string.Append(" (string)");
|
||||
break;
|
||||
case VbamOption::Type::kFilter:
|
||||
case VbamOption::Type::kInterframe:
|
||||
case VbamOption::Type::kRenderMethod:
|
||||
case VbamOption::Type::kAudioApi:
|
||||
case VbamOption::Type::kSoundQuality:
|
||||
helper_string.Append(" (");
|
||||
helper_string.Append(internal::AllEnumValuesForType(type_));
|
||||
helper_string.Append(")");
|
||||
break;
|
||||
case VbamOption::Type::kGbPalette:
|
||||
helper_string.Append(" (XXXX,XXXX,XXXX,XXXX,XXXX,XXXX,XXXX,XXXX)");
|
||||
break;
|
||||
}
|
||||
helper_string.Append("\n\t");
|
||||
helper_string.Append(ux_helper_);
|
||||
helper_string.Append("\n");
|
||||
|
||||
return helper_string;
|
||||
}
|
|
@ -1,291 +0,0 @@
|
|||
#include "wx/gamecontrol.h"
|
||||
|
||||
#include "../strutils.h"
|
||||
#include "opts.h"
|
||||
#include "wx/log.h"
|
||||
#include "wxlogdebug.h"
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr uint32_t kBitKeyA = (1 << 0);
|
||||
constexpr uint32_t kBitKeyB = (1 << 1);
|
||||
constexpr uint32_t kBitKeySelect = (1 << 2);
|
||||
constexpr uint32_t kBitKeyStart = (1 << 3);
|
||||
constexpr uint32_t kBitKeyRight = (1 << 4);
|
||||
constexpr uint32_t kBitKeyLeft = (1 << 5);
|
||||
constexpr uint32_t kBitKeyUp = (1 << 6);
|
||||
constexpr uint32_t kBitKeyDown = (1 << 7);
|
||||
constexpr uint32_t kBitKeyR = (1 << 8);
|
||||
constexpr uint32_t kBitKeyL = (1 << 9);
|
||||
constexpr uint32_t kBitKeySpeed = (1 << 10);
|
||||
constexpr uint32_t kBitKeyCapture = (1 << 11);
|
||||
constexpr uint32_t kBitKeyGameShark = (1 << 12);
|
||||
constexpr uint32_t kBitKeyAutoA = (1 << 13);
|
||||
constexpr uint32_t kBitKeyAutoB = (1 << 14);
|
||||
constexpr uint32_t kBitKeyMotionUp = (1 << 15);
|
||||
constexpr uint32_t kBitKeyMotionDown = (1 << 16);
|
||||
constexpr uint32_t kBitKeyMotionLeft = (1 << 17);
|
||||
constexpr uint32_t kBitKeyMotionRight = (1 << 18);
|
||||
constexpr uint32_t kBitKeyMotionIn = (1 << 19);
|
||||
constexpr uint32_t kBitKeyMotionOut = (1 << 20);
|
||||
|
||||
constexpr std::array<uint32_t, kNbGameKeys> kBitMask = {
|
||||
kBitKeyUp,
|
||||
kBitKeyDown,
|
||||
kBitKeyLeft,
|
||||
kBitKeyRight,
|
||||
kBitKeyA,
|
||||
kBitKeyB,
|
||||
kBitKeyL,
|
||||
kBitKeyR,
|
||||
kBitKeySelect,
|
||||
kBitKeyStart,
|
||||
kBitKeyMotionUp,
|
||||
kBitKeyMotionDown,
|
||||
kBitKeyMotionLeft,
|
||||
kBitKeyMotionRight,
|
||||
kBitKeyMotionIn,
|
||||
kBitKeyMotionOut,
|
||||
kBitKeyAutoA,
|
||||
kBitKeyAutoB,
|
||||
kBitKeySpeed,
|
||||
kBitKeyCapture,
|
||||
kBitKeyGameShark,
|
||||
};
|
||||
|
||||
inline int GameKeyToInt(const wxGameKey& game_key) {
|
||||
return static_cast<std::underlying_type<wxGameKey>::type>(
|
||||
game_key);
|
||||
}
|
||||
|
||||
// Returns true if `joypad` is in a valid joypad range.
|
||||
inline bool JoypadInRange(const int& joypad) {
|
||||
constexpr int kMinJoypadIndex = 0;
|
||||
return joypad >= kMinJoypadIndex && joypad < kNbJoypads;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
wxString GameKeyToString(const wxGameKey& game_key) {
|
||||
// Note: this must match GUI widget names or GUI won't work
|
||||
// This array's order determines tab order as well
|
||||
static const std::array<wxString, kNbGameKeys> kGameKeyStrings = {
|
||||
wxT("Up"),
|
||||
wxT("Down"),
|
||||
wxT("Left"),
|
||||
wxT("Right"),
|
||||
wxT("A"),
|
||||
wxT("B"),
|
||||
wxT("L"),
|
||||
wxT("R"),
|
||||
wxT("Select"),
|
||||
wxT("Start"),
|
||||
wxT("MotionUp"),
|
||||
wxT("MotionDown"),
|
||||
wxT("MotionLeft"),
|
||||
wxT("MotionRight"),
|
||||
wxT("MotionIn"),
|
||||
wxT("MotionOut"),
|
||||
wxT("AutoA"),
|
||||
wxT("AutoB"),
|
||||
wxT("Speed"),
|
||||
wxT("Capture"),
|
||||
wxT("GS"),
|
||||
};
|
||||
return kGameKeyStrings[GameKeyToInt(game_key)];
|
||||
}
|
||||
|
||||
nonstd::optional<wxGameKey> StringToGameKey(const wxString& input) {
|
||||
static const std::map<wxString, wxGameKey> kStringToGameKey = {
|
||||
{ wxT("Up"), wxGameKey::Up },
|
||||
{ wxT("Down"), wxGameKey::Down },
|
||||
{ wxT("Left"), wxGameKey::Left },
|
||||
{ wxT("Right"), wxGameKey::Right },
|
||||
{ wxT("A"), wxGameKey::A },
|
||||
{ wxT("B"), wxGameKey::B },
|
||||
{ wxT("L"), wxGameKey::L },
|
||||
{ wxT("R"), wxGameKey::R },
|
||||
{ wxT("Select"), wxGameKey::Select },
|
||||
{ wxT("Start"), wxGameKey::Start },
|
||||
{ wxT("MotionUp"), wxGameKey::MotionUp },
|
||||
{ wxT("MotionDown"), wxGameKey::MotionDown },
|
||||
{ wxT("MotionLeft"), wxGameKey::MotionLeft },
|
||||
{ wxT("MotionRight"), wxGameKey::MotionRight },
|
||||
{ wxT("MotionIn"), wxGameKey::MotionIn },
|
||||
{ wxT("MotionOut"), wxGameKey::MotionOut },
|
||||
{ wxT("AutoA"), wxGameKey::AutoA },
|
||||
{ wxT("AutoB"), wxGameKey::AutoB },
|
||||
{ wxT("Speed"), wxGameKey::Speed },
|
||||
{ wxT("Capture"), wxGameKey::Capture },
|
||||
{ wxT("GS"), wxGameKey::Gameshark },
|
||||
};
|
||||
|
||||
const auto iter = kStringToGameKey.find(input);
|
||||
if (iter == kStringToGameKey.end()) {
|
||||
return nonstd::nullopt;
|
||||
}
|
||||
return iter->second;
|
||||
}
|
||||
|
||||
// static
|
||||
nonstd::optional<wxGameControl> wxGameControl::FromString(const wxString &name) {
|
||||
static const wxString kJoypad(wxT("Joypad"));
|
||||
if (!wxStrncmp(name, kJoypad, kJoypad.size())) {
|
||||
wxLogDebug("Doesn't start with joypad");
|
||||
return nonstd::nullopt;
|
||||
}
|
||||
|
||||
auto parts = strutils::split(name, wxT("/"));
|
||||
if (parts.size() != 3) {
|
||||
wxLogDebug("Wrong split size: %d", parts.size());
|
||||
return nonstd::nullopt;
|
||||
}
|
||||
|
||||
const int joypad = parts[1][0] - wxT('1');
|
||||
if (!JoypadInRange(joypad)) {
|
||||
wxLogDebug("Wrong joypad index: %d", joypad);
|
||||
return nonstd::nullopt;
|
||||
}
|
||||
|
||||
nonstd::optional<wxGameKey> game_key = StringToGameKey(parts[2]);
|
||||
if (!game_key) {
|
||||
wxLogDebug("Failed to parse game_key: %s", parts[2]);
|
||||
return nonstd::nullopt;
|
||||
}
|
||||
|
||||
return wxGameControl(joypad, game_key.value());
|
||||
}
|
||||
|
||||
wxGameControl::wxGameControl(int joypad, wxGameKey game_key) :
|
||||
joypad_(joypad),
|
||||
game_key_(game_key),
|
||||
config_string_(wxString::Format(
|
||||
wxT("Joypad/%d/%s"), joypad_ + 1, GameKeyToString(game_key_))) {
|
||||
assert(JoypadInRange(joypad_));
|
||||
}
|
||||
wxGameControl::~wxGameControl() = default;
|
||||
|
||||
bool wxGameControl::operator==(const wxGameControl& other) const {
|
||||
return joypad_ == other.joypad_ && game_key_ == other.game_key_;
|
||||
}
|
||||
bool wxGameControl::operator!=(const wxGameControl& other) const {
|
||||
return !(*this == other);
|
||||
}
|
||||
bool wxGameControl::operator<(const wxGameControl& other) const {
|
||||
if (joypad_ != other.joypad_) {
|
||||
return joypad_ < other.joypad_;
|
||||
}
|
||||
if (game_key_ != other.game_key_) {
|
||||
return game_key_ < other.game_key_;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
bool wxGameControl::operator<=(const wxGameControl& other) const {
|
||||
return !(*this > other);
|
||||
}
|
||||
bool wxGameControl::operator>(const wxGameControl& other) const {
|
||||
return other < *this;
|
||||
}
|
||||
bool wxGameControl::operator>=(const wxGameControl& other) const {
|
||||
return !(*this < other);
|
||||
}
|
||||
|
||||
wxGameControlState& wxGameControlState::Instance() {
|
||||
static wxGameControlState g_game_control_state;
|
||||
return g_game_control_state;
|
||||
}
|
||||
|
||||
wxGameControlState::wxGameControlState() : joypads_({0, 0, 0, 0}) {}
|
||||
wxGameControlState::~wxGameControlState() = default;
|
||||
|
||||
bool wxGameControlState::OnInputPressed(const config::UserInput& user_input) {
|
||||
assert(user_input);
|
||||
|
||||
const auto& game_keys = input_bindings_.find(user_input);
|
||||
if (game_keys == input_bindings_.end()) {
|
||||
// No associated game control for `user_input`.
|
||||
return false;
|
||||
}
|
||||
|
||||
auto iter = keys_pressed_.find(user_input);
|
||||
if (iter != keys_pressed_.end()) {
|
||||
// Double press is noop.
|
||||
return true;
|
||||
}
|
||||
|
||||
// Remember the key pressed.
|
||||
keys_pressed_.emplace(user_input);
|
||||
|
||||
// Update all corresponding controls.
|
||||
for (const wxGameControl& game_control : game_keys->second) {
|
||||
active_controls_[game_control].emplace(user_input);
|
||||
joypads_[game_control.joypad_] |=
|
||||
kBitMask[GameKeyToInt(game_control.game_key_)];
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool wxGameControlState::OnInputReleased(const config::UserInput& user_input) {
|
||||
assert(user_input);
|
||||
|
||||
const auto& game_keys = input_bindings_.find(user_input);
|
||||
if (game_keys == input_bindings_.end()) {
|
||||
// No associated game control for `user_input`.
|
||||
return false;
|
||||
}
|
||||
|
||||
auto iter = keys_pressed_.find(user_input);
|
||||
if (iter == keys_pressed_.end()) {
|
||||
// Double release is noop.
|
||||
return true;
|
||||
}
|
||||
|
||||
// Release the key pressed.
|
||||
keys_pressed_.erase(iter);
|
||||
|
||||
// Update all corresponding controls.
|
||||
for (const wxGameControl& game_control : game_keys->second) {
|
||||
auto active_controls = active_controls_.find(game_control);
|
||||
if (active_controls == active_controls_.end()) {
|
||||
// This should never happen.
|
||||
assert(false);
|
||||
return true;
|
||||
}
|
||||
|
||||
active_controls->second.erase(user_input);
|
||||
if (active_controls->second.empty()) {
|
||||
// Actually release control.
|
||||
active_controls_.erase(active_controls);
|
||||
joypads_[game_control.joypad_] &=
|
||||
~kBitMask[GameKeyToInt(game_control.game_key_)];
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void wxGameControlState::Reset() {
|
||||
active_controls_.clear();
|
||||
keys_pressed_.clear();
|
||||
joypads_.fill(0);
|
||||
}
|
||||
|
||||
void wxGameControlState::OnGameBindingsChanged() {
|
||||
// We should reset to ensure no key remains accidentally pressed following a
|
||||
// configuration change.
|
||||
Reset();
|
||||
|
||||
input_bindings_.clear();
|
||||
for (const auto& iter : gopts.game_control_bindings) {
|
||||
for (const auto& user_input : iter.second) {
|
||||
input_bindings_[user_input].emplace(iter.first);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t wxGameControlState::GetJoypad(int joypad) const {
|
||||
assert(JoypadInRange(joypad));
|
||||
return joypads_[joypad];
|
||||
}
|
||||
|
|
@ -1,139 +0,0 @@
|
|||
#ifndef _WX_GAME_CONTROL_H_
|
||||
#define _WX_GAME_CONTROL_H_
|
||||
|
||||
#include <array>
|
||||
#include <map>
|
||||
#include "nonstd/optional.hpp"
|
||||
#include <set>
|
||||
#include <wx/string.h>
|
||||
|
||||
#include "config/user-input.h"
|
||||
|
||||
// Forward declaration.
|
||||
class wxGameControlState;
|
||||
|
||||
// Represents an in-game input.
|
||||
enum class wxGameKey {
|
||||
Up = 0,
|
||||
Down,
|
||||
Left,
|
||||
Right,
|
||||
A,
|
||||
B,
|
||||
L,
|
||||
R,
|
||||
Select,
|
||||
Start,
|
||||
MotionUp,
|
||||
MotionDown,
|
||||
MotionLeft,
|
||||
MotionRight,
|
||||
MotionIn,
|
||||
MotionOut,
|
||||
AutoA,
|
||||
AutoB,
|
||||
Speed,
|
||||
Capture,
|
||||
Gameshark,
|
||||
Last = Gameshark
|
||||
};
|
||||
|
||||
inline constexpr int kNbGameKeys =
|
||||
static_cast<std::underlying_type<wxGameKey>::type>(wxGameKey::Last) + 1;
|
||||
inline constexpr int kNbJoypads = 4;
|
||||
|
||||
inline constexpr std::array<wxGameKey, kNbGameKeys> kAllGameKeys = {
|
||||
wxGameKey::Up,
|
||||
wxGameKey::Down,
|
||||
wxGameKey::Left,
|
||||
wxGameKey::Right,
|
||||
wxGameKey::A,
|
||||
wxGameKey::B,
|
||||
wxGameKey::L,
|
||||
wxGameKey::R,
|
||||
wxGameKey::Select,
|
||||
wxGameKey::Start,
|
||||
wxGameKey::MotionUp,
|
||||
wxGameKey::MotionDown,
|
||||
wxGameKey::MotionLeft,
|
||||
wxGameKey::MotionRight,
|
||||
wxGameKey::MotionIn,
|
||||
wxGameKey::MotionOut,
|
||||
wxGameKey::AutoA,
|
||||
wxGameKey::AutoB,
|
||||
wxGameKey::Speed,
|
||||
wxGameKey::Capture,
|
||||
wxGameKey::Gameshark,
|
||||
};
|
||||
|
||||
// Conversion utility method. Returns empty string on failure.
|
||||
// This is O(1).
|
||||
wxString GameKeyToString(const wxGameKey& game_key);
|
||||
|
||||
// Conversion utility method. Returns std::nullopt on failure.
|
||||
// This is O(log(kNbGameKeys)).
|
||||
nonstd::optional<wxGameKey> StringToGameKey(const wxString& input);
|
||||
|
||||
// Abstraction for an in-game control, wich is made of a player index (from 0
|
||||
// to 3), and a wxGameKey.
|
||||
class wxGameControl {
|
||||
public:
|
||||
// Converts a string to a wxGameControl. Returns std::nullopt on failure.
|
||||
static nonstd::optional<wxGameControl> FromString(const wxString& name);
|
||||
|
||||
wxGameControl(int joypad, wxGameKey game_key);
|
||||
~wxGameControl();
|
||||
|
||||
wxString ToString() const { return config_string_; };
|
||||
|
||||
bool operator==(const wxGameControl& other) const;
|
||||
bool operator!=(const wxGameControl& other) const;
|
||||
bool operator<(const wxGameControl& other) const;
|
||||
bool operator<=(const wxGameControl& other) const;
|
||||
bool operator>(const wxGameControl& other) const;
|
||||
bool operator>=(const wxGameControl& other) const;
|
||||
|
||||
private:
|
||||
const int joypad_;
|
||||
const wxGameKey game_key_;
|
||||
const wxString config_string_;
|
||||
|
||||
friend class wxGameControlState;
|
||||
};
|
||||
|
||||
// Tracks in-game input and computes the joypad value used to send control input
|
||||
// data to the emulator.
|
||||
class wxGameControlState {
|
||||
public:
|
||||
// This is a global singleton.
|
||||
static wxGameControlState& Instance();
|
||||
|
||||
// Disable copy constructor and assignment operator.
|
||||
wxGameControlState(const wxGameControlState&) = delete;
|
||||
wxGameControlState& operator=(const wxGameControlState&) = delete;
|
||||
|
||||
// Processes `user_input` and updates the internal tracking state.
|
||||
// Returns true if `user_input` corresponds to a game input.
|
||||
bool OnInputPressed(const config::UserInput& user_input);
|
||||
bool OnInputReleased(const config::UserInput& user_input);
|
||||
|
||||
// Clears all input.
|
||||
void Reset();
|
||||
|
||||
// Recomputes internal bindinds. This is a potentially slow operation and
|
||||
// should only be called when the game input configuration has been changed.
|
||||
void OnGameBindingsChanged();
|
||||
|
||||
uint32_t GetJoypad(int joypad) const;
|
||||
|
||||
private:
|
||||
wxGameControlState();
|
||||
~wxGameControlState();
|
||||
|
||||
std::map<config::UserInput, std::set<wxGameControl>> input_bindings_;
|
||||
std::map<wxGameControl, std::set<config::UserInput>> active_controls_;
|
||||
std::set<config::UserInput> keys_pressed_;
|
||||
std::array<uint32_t, kNbJoypads> joypads_;
|
||||
};
|
||||
|
||||
#endif // _WX_GAME_CONTROL_H_
|
|
@ -5,7 +5,7 @@
|
|||
// The value is the symbolic name of the key pressed
|
||||
// Supports manual clearing (bs), multiple keys in widget, automatic tab on key
|
||||
|
||||
#include "wx/gamecontrol.h"
|
||||
#include "config/game-control.h"
|
||||
#include "wx/keyedit.h"
|
||||
#include "wx/sdljoy.h"
|
||||
|
||||
|
@ -41,7 +41,7 @@ protected:
|
|||
// A simple copy-only validator
|
||||
class wxJoyKeyValidator : public wxValidator {
|
||||
public:
|
||||
wxJoyKeyValidator(const wxGameControl v)
|
||||
wxJoyKeyValidator(const config::GameControl v)
|
||||
: wxValidator()
|
||||
, val_(v)
|
||||
{
|
||||
|
@ -64,7 +64,7 @@ public:
|
|||
}
|
||||
|
||||
protected:
|
||||
const wxGameControl val_;
|
||||
const config::GameControl val_;
|
||||
|
||||
DECLARE_CLASS(wxJoyKeyValidator)
|
||||
};
|
||||
|
|
|
@ -32,9 +32,9 @@
|
|||
#include "builtin-over.h"
|
||||
#include "config/user-input.h"
|
||||
#include "strutils.h"
|
||||
#include "vbam-options.h"
|
||||
#include "config/game-control.h"
|
||||
#include "config/option.h"
|
||||
#include "wayland.h"
|
||||
#include "wx/gamecontrol.h"
|
||||
|
||||
#ifdef __WXMSW__
|
||||
|
||||
|
@ -465,7 +465,7 @@ bool wxvbamApp::OnInit() {
|
|||
|
||||
// Initialize game bindings here, after defaults bindings, vbam.ini bindings
|
||||
// and command line overrides have been applied.
|
||||
wxGameControlState::Instance().OnGameBindingsChanged();
|
||||
config::GameControlState::Instance().OnGameBindingsChanged();
|
||||
|
||||
// create the main window
|
||||
int x = windowPositionX;
|
||||
|
@ -669,7 +669,7 @@ bool wxvbamApp::OnCmdLineParsed(wxCmdLineParser& cl)
|
|||
" configuration changes are made in the user interface.\n\n"
|
||||
"For flag options, true and false are specified as 1 and 0, respectively.\n\n"));
|
||||
|
||||
for (const VbamOption& opt : VbamOption::AllOptions()) {
|
||||
for (const config::Option& opt : config::Option::AllOptions()) {
|
||||
wxPrintf("%s\n", opt.ToHelperString());
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue