Update to v106r51 release.

byuu says:

Changelog:

  - added `Emulator::Interface::connected(uint port) -> uint device;`
  - higan, bsnes: updated emulators to use the new
    Emulator::Interface::connected() function
  - hiro: fixed Object::cast<T> finally

So, Emulator::Interface::connected() solves two annoying problems at the
same time.

First, on first run of the emulator when the settings file is blank, it
will retrieve the default "sane" device ID, which is usually a gamepad
for a controller port, or nothing for an expansion/extension port.

Second, if you were to select a multi-port device, like the NES Four
Score, the core will set the other port to the Four Score device as
well, and the GUIs query connected() right after any call to connect(),
so it gets updated without needing a system for the emulation core to
send messages alerting the GUI of changes.
This commit is contained in:
Tim Allen 2018-07-21 21:49:48 +10:00
parent 35ff15f83e
commit 0aedb3430c
23 changed files with 181 additions and 110 deletions

View File

@ -13,7 +13,7 @@ using namespace nall;
namespace Emulator {
static const string Name = "higan";
static const string Version = "106.50";
static const string Version = "106.51";
static const string Author = "byuu";
static const string License = "GPLv3";
static const string Website = "https://byuu.org/";

View File

@ -58,6 +58,7 @@ struct Interface {
virtual auto unload() -> void {}
//system interface
virtual auto connected(uint port) -> uint { return 0; }
virtual auto connect(uint port, uint device) -> void {}
virtual auto power() -> void {}
virtual auto reset() -> void {}

View File

@ -132,6 +132,13 @@ auto Interface::unload() -> void {
system.unload();
}
auto Interface::connected(uint port) -> uint {
if(port == ID::Port::Controller1) return settings.controllerPort1;
if(port == ID::Port::Controller2) return settings.controllerPort2;
if(port == ID::Port::Expansion) return settings.expansionPort;
return 0;
}
auto Interface::connect(uint port, uint device) -> void {
if(port == ID::Port::Controller1) controllerPort1.connect(settings.controllerPort1 = device);
if(port == ID::Port::Controller2) controllerPort2.connect(settings.controllerPort2 = device);

View File

@ -36,6 +36,7 @@ struct Interface : Emulator::Interface {
auto save() -> void override;
auto unload() -> void override;
auto connected(uint port) -> uint override;
auto connect(uint port, uint device) -> void override;
auto power() -> void override;
auto reset() -> void override;
@ -55,9 +56,9 @@ struct Settings {
bool colorEmulation = true;
bool scanlineEmulation = true;
uint controllerPort1 = 0;
uint controllerPort2 = 0;
uint expansionPort = 0;
uint controllerPort1 = ID::Device::Gamepad;
uint controllerPort2 = ID::Device::Gamepad;
uint expansionPort = ID::Device::None;
};
extern Settings settings;

View File

@ -85,6 +85,7 @@ auto System::power() -> void {
Emulator::video.reset(interface);
Emulator::video.setPalette();
Emulator::video.setEffect(Emulator::Video::Effect::InterframeBlending, settings.blurEmulation);
Emulator::audio.reset(interface);
}

View File

@ -116,6 +116,13 @@ auto Interface::unload() -> void {
system.unload();
}
auto Interface::connected(uint port) -> uint {
if(port == ID::Port::Controller1) return settings.controllerPort1;
if(port == ID::Port::Controller2) return settings.controllerPort2;
if(port == ID::Port::Extension) return settings.extensionPort;
return 0;
}
auto Interface::connect(uint port, uint device) -> void {
if(port == ID::Port::Controller1) controllerPort1.connect(settings.controllerPort1 = device);
if(port == ID::Port::Controller2) controllerPort2.connect(settings.controllerPort2 = device);

View File

@ -36,6 +36,7 @@ struct Interface : Emulator::Interface {
auto save() -> void override;
auto unload() -> void override;
auto connected(uint port) -> uint override;
auto connect(uint port, uint device) -> void override;
auto power() -> void override;
auto reset() -> void override;
@ -52,9 +53,9 @@ struct Interface : Emulator::Interface {
};
struct Settings {
uint controllerPort1 = 0;
uint controllerPort2 = 0;
uint extensionPort = 0;
uint controllerPort1 = ID::Device::ControlPad;
uint controllerPort2 = ID::Device::ControlPad;
uint extensionPort = ID::Device::None;
};
extern Settings settings;

View File

@ -31,7 +31,6 @@ struct Interface : Emulator::Interface {
auto save() -> void override;
auto unload() -> void override;
auto connect(uint port, uint device) -> void override {}
auto power() -> void override;
auto run() -> void override;

View File

@ -83,6 +83,11 @@ auto Interface::unload() -> void {
system.unload();
}
auto Interface::connected(uint port) -> uint {
if(port == ID::Port::Controller) return settings.controllerPort;
return 0;
}
auto Interface::connect(uint port, uint device) -> void {
if(port == ID::Port::Controller) controllerPort.connect(settings.controllerPort = device);
}

View File

@ -32,6 +32,7 @@ struct Interface : Emulator::Interface {
auto save() -> void override;
auto unload() -> void override;
auto connected(uint port) -> uint override;
auto connect(uint port, uint device) -> void override;
auto power() -> void override;
auto run() -> void override;
@ -59,7 +60,7 @@ struct SuperGrafxInterface : Interface {
};
struct Settings {
uint controllerPort = 0;
uint controllerPort = ID::Device::Gamepad;
};
extern Settings settings;

View File

@ -186,6 +186,13 @@ auto Interface::unload() -> void {
system.unload();
}
auto Interface::connected(uint port) -> uint {
if(port == ID::Port::Controller1) return settings.controllerPort1;
if(port == ID::Port::Controller2) return settings.controllerPort2;
if(port == ID::Port::Expansion) return settings.expansionPort;
return 0;
}
auto Interface::connect(uint port, uint device) -> void {
if(port == ID::Port::Controller1) controllerPort1.connect(settings.controllerPort1 = device);
if(port == ID::Port::Controller2) controllerPort2.connect(settings.controllerPort2 = device);

View File

@ -48,6 +48,7 @@ struct Interface : Emulator::Interface {
auto save() -> void override;
auto unload() -> void override;
auto connected(uint port) -> uint override;
auto connect(uint port, uint device) -> void override;
auto power() -> void override;
auto reset() -> void override;
@ -76,9 +77,9 @@ struct Settings {
bool colorEmulation = true;
bool scanlineEmulation = true;
uint controllerPort1 = 0;
uint controllerPort2 = 0;
uint expansionPort = 0;
uint controllerPort1 = ID::Device::Gamepad;
uint controllerPort2 = ID::Device::Gamepad;
uint expansionPort = ID::Device::None;
bool random = true;
};

View File

@ -21,38 +21,7 @@ Presentation::Presentation() {
controllerPort1.setIcon(Icon::Device::Joypad).setText(tr("Controller Port 1"));
controllerPort2.setIcon(Icon::Device::Joypad).setText(tr("Controller Port 2"));
expansionPort.setIcon(Icon::Device::Storage).setText(tr("Expansion Port"));
for(auto& port : emulator->ports) {
Menu* menu = nullptr;
if(port.name == "Controller Port 1") menu = &controllerPort1;
if(port.name == "Controller Port 2") menu = &controllerPort2;
if(port.name == "Expansion Port") menu = &expansionPort;
if(!menu) continue;
Group devices;
for(auto& device : port.devices) {
if(port.name != "Expansion Port" && device.name == "None") continue;
if(port.name == "Expansion Port" && device.name == "21fx") continue;
MenuRadioItem item{menu};
item.setText(tr(device.name)).onActivate([=] {
auto path = string{"Emulator/", port.name}.replace(" ", "");
settings(path).setValue(device.name);
emulator->connect(port.id, device.id);
});
devices.append(item);
}
auto path = string{"Emulator/", port.name}.replace(" ", "");
auto device = settings(path).text();
bool found = false;
if(devices.objectCount() > 1) {
for(auto item : devices.objects<MenuRadioItem>()) {
if(item.text() == device) item.setChecked(), found = true;
}
}
//select the first device when a new settings file is being created
if(devices.objectCount() && !found) {
devices.objects<MenuRadioItem>()(0).doActivate();
}
}
updateDeviceMenu();
quit.setIcon(Icon::Action::Quit).setText(tr("Quit")).onActivate([&] { program->quit(); });
settingsMenu.setText(tr("Settings"));
@ -372,6 +341,64 @@ auto Presentation::toggleFullscreenMode() -> void {
}
}
auto Presentation::updateDeviceMenu() -> void {
controllerPort1.reset();
controllerPort2.reset();
expansionPort.reset();
for(auto& port : emulator->ports) {
Menu* menu = nullptr;
if(port.name == "Controller Port 1") menu = &controllerPort1;
if(port.name == "Controller Port 2") menu = &controllerPort2;
if(port.name == "Expansion Port") menu = &expansionPort;
if(!menu) continue;
auto path = string{"Emulator/", port.name}.replace(" ", "");
auto deviceName = settings(path).text();
auto deviceID = emulator->connected(port.id);
Group devices;
for(auto& device : port.devices) {
if(port.name == "Expansion Port" && device.name == "21fx") continue;
MenuRadioItem item{menu};
item.setProperty("deviceID", device.id);
item.setText(tr(device.name));
item.onActivate([=] {
settings(path).setValue(device.name);
emulator->connect(port.id, device.id);
updateDeviceSelections();
});
devices.append(item);
if(deviceName == device.name) item.doActivate();
if(!deviceName && deviceID == device.id) item.doActivate();
}
}
updateDeviceSelections();
}
auto Presentation::updateDeviceSelections() -> void {
for(auto& port : emulator->ports) {
Menu* menu = nullptr;
if(port.name == "Controller Port 1") menu = &controllerPort1;
if(port.name == "Controller Port 2") menu = &controllerPort2;
if(port.name == "Expansion Port") menu = &expansionPort;
if(!menu) continue;
auto deviceID = emulator->connected(port.id);
for(auto& action : menu->actions()) {
if(auto item = action.cast<MenuRadioItem>()) {
if(item.property("deviceID").natural() == deviceID) {
item.setChecked();
break;
}
}
}
}
}
//generate a list of size multipliers
auto Presentation::updateSizeMenu() -> void {
assert(sizeMenu.actions() == 0); //should only be called once

View File

@ -33,6 +33,8 @@ struct Presentation : Window {
auto resizeWindow() -> void;
auto updateStatus() -> void;
auto toggleFullscreenMode() -> void;
auto updateDeviceMenu() -> void;
auto updateDeviceSelections() -> void;
auto updateSizeMenu() -> void;
auto clearRecentGames() -> void;
auto updateRecentGames() -> void;

View File

@ -18,7 +18,6 @@ auto Program::load() -> void {
return showMessage("Game loading cancelled");
}
}
updateInputDevices();
hackCompatibility();
emulator->power();
if(settingsWindow->advanced.autoLoadStateOnLoad.checked()) {

View File

@ -15,16 +15,3 @@ auto Program::updateInputDriver() -> void {
return updateInputDriver();
}
}
auto Program::updateInputDevices() -> void {
for(auto& port : emulator->ports) {
auto path = string{"Emulator/", port.name}.replace(" ", "");
auto name = settings(path).text();
for(auto& device : port.devices) {
if(device.name == name) {
emulator->connect(port.id, device.id);
break;
}
}
}
}

View File

@ -74,7 +74,6 @@ struct Program : Emulator::Platform {
//input.cpp
auto updateInputDriver() -> void;
auto updateInputDevices() -> void;
//utility.cpp
auto showMessage(string text) -> void;

View File

@ -9,9 +9,6 @@ Presentation::Presentation() {
systemsMenu.setText("Systems");
systemMenu.setVisible(false);
resetSystem.setText("Soft Reset").onActivate([&] { program->softReset(); });
powerSystem.setText("Power Cycle").onActivate([&] { program->powerCycle(); });
unloadSystem.setText("Unload").onActivate([&] { program->unloadMedium(); });
settingsMenu.setText("Settings");
videoScaleMenu.setText("Video Scale");
@ -165,44 +162,86 @@ Presentation::Presentation() {
#endif
}
auto Presentation::updateEmulator() -> void {
auto Presentation::updateEmulatorMenu() -> void {
if(!emulator) return;
inputPort1.setVisible(false).reset();
inputPort2.setVisible(false).reset();
inputPort3.setVisible(false).reset();
for(auto n : range(emulator->ports.size())) {
if(n >= 3) break;
auto& port = emulator->ports[n];
auto& menu = (n == 0 ? inputPort1 : n == 1 ? inputPort2 : inputPort3);
systemMenu.reset();
for(auto& port : emulator->ports) {
Menu menu{&systemMenu};
menu.setProperty("portID", port.id);
menu.setText(port.name);
if(port.name.beginsWith("Expansion") || port.name.beginsWith("Extension")) {
menu.setIcon(Icon::Device::Storage);
} else {
menu.setIcon(Icon::Device::Joypad);
}
auto path = string{emulator->information.name, "/", port.name}.replace(" ", "");
auto deviceName = settings(path).text();
auto deviceID = emulator->connected(port.id);
Group devices;
for(auto& device : port.devices) {
MenuRadioItem item{&menu};
item.setText(device.name).onActivate([=] {
auto path = string{emulator->information.name, "/", port.name}.replace(" ", "");
settings[path].setValue(device.name);
item.setProperty("deviceID", device.id);
item.setText(device.name);
item.onActivate([=] {
settings(path).setValue(device.name);
emulator->connect(port.id, device.id);
updateEmulatorDeviceSelections();
});
devices.append(item);
if(deviceName == device.name) item.doActivate();
if(!deviceName && deviceID == device.id) item.doActivate();
}
if(devices.objectCount() > 1) {
auto path = string{emulator->information.name, "/", port.name}.replace(" ", "");
auto device = settings(path).text();
for(auto item : devices.objects<MenuRadioItem>()) {
if(item.text() == device) item.setChecked();
}
menu.setVisible();
if(devices.objectCount() == 0) {
menu.setVisible(false);
}
}
systemMenuSeparatorPorts.setVisible(inputPort1.visible() || inputPort2.visible() || inputPort3.visible());
resetSystem.setVisible(emulator->information.resettable);
if(systemMenu.actionCount()) {
systemMenu.append(MenuSeparator());
}
emulator->set("Blur Emulation", blurEmulation.checked());
emulator->set("Color Emulation", colorEmulation.checked());
emulator->set("Scanline Emulation", scanlineEmulation.checked());
if(emulator->information.resettable) {
systemMenu.append(MenuItem().setText("Soft Reset").setIcon(Icon::Action::Refresh).onActivate([&] {
program->softReset();
}));
}
systemMenu.append(MenuItem().setText("Power Cycle").setIcon(Icon::Action::Refresh).onActivate([&] {
program->powerCycle();
}));
systemMenu.append(MenuItem().setText("Unload").setIcon(Icon::Media::Eject).onActivate([&] {
program->unloadMedium();
}));
updateEmulatorDeviceSelections();
}
auto Presentation::updateEmulatorDeviceSelections() -> void {
if(!emulator) return;
for(auto& port : emulator->ports) {
for(auto& action : systemMenu->actions()) {
auto portID = action.property("portID");
if(portID && portID.natural() == port.id) {
if(auto menu = action.cast<Menu>()) {
auto deviceID = emulator->connected(port.id);
for(auto& action : menu.actions()) {
if(auto item = action.cast<MenuRadioItem>()) {
if(item.property("deviceID").natural() == deviceID) {
item.setChecked();
}
}
}
}
}
}
}
}
auto Presentation::drawIcon(uint32_t* output, uint length, uint width, uint height) -> void {

View File

@ -10,7 +10,8 @@ struct AboutWindow : Window {
struct Presentation : Window {
Presentation();
auto updateEmulator() -> void;
auto updateEmulatorMenu() -> void;
auto updateEmulatorDeviceSelections() -> void;
auto drawIcon(uint32_t* output, uint length, uint width, uint height) -> void;
auto clearViewport() -> void;
auto resizeViewport(bool resizeWindow = true) -> void;

View File

@ -20,13 +20,16 @@ auto Program::loadMedium(Emulator::Interface& interface, const Emulator::Interfa
mediumPaths.append(locate({"systems/", medium.name, ".sys/"}));
inputManager->bind(emulator = &interface);
presentation->updateEmulatorMenu();
if(!emulator->load(medium.id)) {
emulator = nullptr;
mediumPaths.reset();
return;
}
connectDevices();
emulator->power();
emulator->set("Blur Emulation", presentation->blurEmulation.checked());
emulator->set("Color Emulation", presentation->colorEmulation.checked());
emulator->set("Scanline Emulation", presentation->scanlineEmulation.checked());
updateAudioDriver();
updateAudioEffects();
@ -34,7 +37,6 @@ auto Program::loadMedium(Emulator::Interface& interface, const Emulator::Interfa
presentation->setTitle(emulator->title());
presentation->systemMenu.setText(medium.name).setVisible(true);
presentation->toolsMenu.setVisible(true);
presentation->updateEmulator();
toolsManager->cheatEditor.loadCheats();
toolsManager->stateManager.doRefresh();
toolsManager->manifestViewer.doRefresh();

View File

@ -34,7 +34,6 @@ struct Program : Emulator::Platform {
auto powerCycle() -> void;
auto togglePause() -> void;
auto rotateDisplay() -> void;
auto connectDevices() -> void;
auto showMessage(const string& text) -> void;
auto updateStatusText() -> void;
auto updateVideoPalette() -> void;

View File

@ -94,20 +94,6 @@ auto Program::rotateDisplay() -> void {
showMessage("Display rotated");
}
auto Program::connectDevices() -> void {
if(!emulator) return;
for(auto& port : emulator->ports) {
auto path = string{emulator->information.name, "/", port.name}.replace(" ", "");
auto name = settings(path).text();
for(auto& device : port.devices) {
if(device.name == name) {
emulator->connect(port.id, device.id);
break;
}
}
}
}
auto Program::showMessage(const string& text) -> void {
statusTime = time(nullptr);
statusMessage = text;

View File

@ -15,6 +15,12 @@
template<typename T, typename... P> Name(T* parent, P&&... p) : Name() { \
if(parent) (*parent)->append(*this, std::forward<P>(p)...); \
} \
template<typename T> auto cast() -> T { \
if(auto pointer = dynamic_cast<typename T::internalType*>(data())) { \
if(auto shared = pointer->instance.acquire()) return T(shared); \
} \
return T(); \
} \
auto enabled(bool recursive = false) const { return self().enabled(recursive); } \
auto focused() const { return self().focused(); } \
auto font(bool recursive = false) const { return self().font(recursive); } \
@ -52,13 +58,6 @@
struct Object : sObject {
DeclareSharedObject(Object)
using internalType = mObject;
template<typename T> auto cast() -> T {
if(auto pointer = dynamic_cast<typename T::internalType*>(data())) {
if(auto shared = pointer->instance.acquire()) return T(shared);
}
return T();
}
};
#endif