emu/ioport.cpp: Preserve configuration for slot cards when not selected.
Have you carefully tuned the sensitivity for you Atari 2600 paddles, then realised you have to do it again after you play a joystick game and switch back to paddles? Or are you sick of having to reconfigure your virtual RS232 peripherals every time you switch devices? This will make your life a little easier.
This commit is contained in:
parent
b915e69902
commit
44e550af74
@ -53,7 +53,7 @@ class chd_file;
|
|||||||
namespace util { class archive_file; }
|
namespace util { class archive_file; }
|
||||||
|
|
||||||
// declared in xmlfile.h
|
// declared in xmlfile.h
|
||||||
namespace util::xml { class data_node; }
|
namespace util::xml { class data_node; class file; }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -1646,17 +1646,18 @@ ioport_port_live::ioport_port_live(ioport_port &port)
|
|||||||
//-------------------------------------------------
|
//-------------------------------------------------
|
||||||
|
|
||||||
ioport_manager::ioport_manager(running_machine &machine)
|
ioport_manager::ioport_manager(running_machine &machine)
|
||||||
: m_machine(machine),
|
: m_machine(machine)
|
||||||
m_safe_to_read(false),
|
, m_safe_to_read(false)
|
||||||
m_last_frame_time(attotime::zero),
|
, m_last_frame_time(attotime::zero)
|
||||||
m_last_delta_nsec(0),
|
, m_last_delta_nsec(0)
|
||||||
m_record_file(machine.options().input_directory(), OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS),
|
, m_record_file(machine.options().input_directory(), OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS)
|
||||||
m_playback_file(machine.options().input_directory(), OPEN_FLAG_READ),
|
, m_playback_file(machine.options().input_directory(), OPEN_FLAG_READ)
|
||||||
m_playback_accumulated_speed(0),
|
, m_playback_accumulated_speed(0)
|
||||||
m_playback_accumulated_frames(0),
|
, m_playback_accumulated_frames(0)
|
||||||
m_timecode_file(machine.options().input_directory(), OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS),
|
, m_timecode_file(machine.options().input_directory(), OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS)
|
||||||
m_timecode_count(0),
|
, m_timecode_count(0)
|
||||||
m_timecode_last_time(attotime::zero)
|
, m_timecode_last_time(attotime::zero)
|
||||||
|
, m_deselected_card_config(nullptr)
|
||||||
{
|
{
|
||||||
memset(m_type_to_entry, 0, sizeof(m_type_to_entry));
|
memset(m_type_to_entry, 0, sizeof(m_type_to_entry));
|
||||||
}
|
}
|
||||||
@ -1831,6 +1832,7 @@ void ioport_manager::exit()
|
|||||||
|
|
||||||
ioport_manager::~ioport_manager()
|
ioport_manager::~ioport_manager()
|
||||||
{
|
{
|
||||||
|
delete m_deselected_card_config;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -2053,16 +2055,15 @@ void ioport_manager::load_config(config_type cfg_type, util::xml::data_node cons
|
|||||||
}
|
}
|
||||||
|
|
||||||
// early exit if no data to parse
|
// early exit if no data to parse
|
||||||
if (parentnode == nullptr)
|
if (!parentnode)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// iterate over all the remap nodes for controller configs only
|
|
||||||
if (cfg_type == config_type::CONTROLLER)
|
|
||||||
load_remap_table(parentnode);
|
|
||||||
|
|
||||||
// load device map table for controller configs only
|
// load device map table for controller configs only
|
||||||
if (cfg_type == config_type::CONTROLLER)
|
if (cfg_type == config_type::CONTROLLER)
|
||||||
{
|
{
|
||||||
|
// iterate over all the remap nodes
|
||||||
|
load_remap_table(parentnode);
|
||||||
|
|
||||||
std::unique_ptr<devicemap_table_type> devicemap_table = std::make_unique<devicemap_table_type>();
|
std::unique_ptr<devicemap_table_type> devicemap_table = std::make_unique<devicemap_table_type>();
|
||||||
for (util::xml::data_node const *mapdevice_node = parentnode->get_child("mapdevice"); mapdevice_node != nullptr; mapdevice_node = mapdevice_node->get_next_sibling("mapdevice"))
|
for (util::xml::data_node const *mapdevice_node = parentnode->get_child("mapdevice"); mapdevice_node != nullptr; mapdevice_node = mapdevice_node->get_next_sibling("mapdevice"))
|
||||||
{
|
{
|
||||||
@ -2252,19 +2253,18 @@ bool ioport_manager::load_default_config(util::xml::data_node const *portnode, i
|
|||||||
// data to the current set of input ports
|
// data to the current set of input ports
|
||||||
//-------------------------------------------------
|
//-------------------------------------------------
|
||||||
|
|
||||||
bool ioport_manager::load_game_config(util::xml::data_node const *portnode, int type, int player, const input_seq *newseq)
|
void ioport_manager::load_game_config(util::xml::data_node const *portnode, int type, int player, const input_seq *newseq)
|
||||||
{
|
{
|
||||||
// read the mask, index, and defvalue attributes
|
// read the mask and defvalue attributes
|
||||||
const char *tag = portnode->get_attribute_string("tag", nullptr);
|
|
||||||
ioport_value mask = portnode->get_attribute_int("mask", 0);
|
ioport_value mask = portnode->get_attribute_int("mask", 0);
|
||||||
ioport_value defvalue = portnode->get_attribute_int("defvalue", 0);
|
ioport_value defvalue = portnode->get_attribute_int("defvalue", 0);
|
||||||
|
|
||||||
// find the port we want; if no tag, search them all
|
auto const apply =
|
||||||
for (auto &port : m_portlist)
|
[portnode, type, player, newseq, mask, defvalue] (ioport_port &port) -> bool
|
||||||
if (tag == nullptr || strcmp(port.second->tag(), tag) == 0)
|
{
|
||||||
for (ioport_field &field : port.second->fields())
|
for (ioport_field &field : port.fields())
|
||||||
|
{
|
||||||
// find the matching mask and defvalue
|
// find the matching mask and default value
|
||||||
if (field.type() == type && field.player() == player &&
|
if (field.type() == type && field.player() == player &&
|
||||||
field.mask() == mask && (field.defvalue() & mask) == (defvalue & mask))
|
field.mask() == mask && (field.defvalue() & mask) == (defvalue & mask))
|
||||||
{
|
{
|
||||||
@ -2274,21 +2274,22 @@ bool ioport_manager::load_game_config(util::xml::data_node const *portnode, int
|
|||||||
field.live().seq[seqtype] = newseq[seqtype];
|
field.live().seq[seqtype] = newseq[seqtype];
|
||||||
|
|
||||||
// fetch configurable attributes
|
// fetch configurable attributes
|
||||||
// for non-analog fields
|
if (!field.live().analog)
|
||||||
if (field.live().analog == nullptr)
|
|
||||||
{
|
{
|
||||||
|
// for non-analog fields
|
||||||
|
|
||||||
// fetch the value
|
// fetch the value
|
||||||
field.live().value = portnode->get_attribute_int("value", field.defvalue());
|
field.live().value = portnode->get_attribute_int("value", field.defvalue());
|
||||||
|
|
||||||
// fetch yes/no for toggle setting
|
// fetch yes/no for toggle setting
|
||||||
const char *togstring = portnode->get_attribute_string("toggle", nullptr);
|
char const *const togstring = portnode->get_attribute_string("toggle", nullptr);
|
||||||
if (togstring != nullptr)
|
if (togstring)
|
||||||
field.live().toggle = (strcmp(togstring, "yes") == 0);
|
field.live().toggle = !strcmp(togstring, "yes");
|
||||||
}
|
}
|
||||||
|
|
||||||
// for analog fields
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
// for analog fields
|
||||||
|
|
||||||
// get base attributes
|
// get base attributes
|
||||||
field.live().analog->m_delta = portnode->get_attribute_int("keydelta", field.delta());
|
field.live().analog->m_delta = portnode->get_attribute_int("keydelta", field.delta());
|
||||||
field.live().analog->m_centerdelta = portnode->get_attribute_int("centerdelta", field.centerdelta());
|
field.live().analog->m_centerdelta = portnode->get_attribute_int("centerdelta", field.centerdelta());
|
||||||
@ -2296,13 +2297,58 @@ bool ioport_manager::load_game_config(util::xml::data_node const *portnode, int
|
|||||||
|
|
||||||
// fetch yes/no for reverse setting
|
// fetch yes/no for reverse setting
|
||||||
const char *revstring = portnode->get_attribute_string("reverse", nullptr);
|
const char *revstring = portnode->get_attribute_string("reverse", nullptr);
|
||||||
if (revstring != nullptr)
|
if (revstring)
|
||||||
field.live().analog->m_reverse = (strcmp(revstring, "yes") == 0);
|
field.live().analog->m_reverse = !strcmp(revstring, "yes");
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return false;
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
// find the port we want
|
||||||
|
char const *const tag = portnode->get_attribute_string("tag", nullptr);
|
||||||
|
if (tag)
|
||||||
|
{
|
||||||
|
auto const port(m_portlist.find(tag));
|
||||||
|
if (m_portlist.end() != port)
|
||||||
|
{
|
||||||
|
apply(*port->second);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// see if this belongs to a slot card that isn't inserted
|
||||||
|
std::string_view parent_tag(tag);
|
||||||
|
auto pos(parent_tag.rfind(':'));
|
||||||
|
if (pos && (std::string_view::npos != pos))
|
||||||
|
{
|
||||||
|
parent_tag = parent_tag.substr(0, pos);
|
||||||
|
for (pos = parent_tag.rfind(':'); pos && (std::string_view::npos != pos); pos = parent_tag.rfind(':'))
|
||||||
|
{
|
||||||
|
parent_tag = parent_tag.substr(0, pos);
|
||||||
|
device_t const *const parent_device(machine().root_device().subdevice(parent_tag));
|
||||||
|
if (parent_device)
|
||||||
|
{
|
||||||
|
device_slot_interface const *slot;
|
||||||
|
if (parent_device->interface(slot))
|
||||||
|
{
|
||||||
|
if (!m_deselected_card_config)
|
||||||
|
m_deselected_card_config = util::xml::file::create().release();
|
||||||
|
portnode->copy_into(*m_deselected_card_config);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// if no tag, search them all
|
||||||
|
for (auto &port : m_portlist)
|
||||||
|
if (apply(*port.second))
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -2497,6 +2543,13 @@ void ioport_manager::save_game_inputs(util::xml::data_node &parentnode)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// preserve configuration for deselected slot cards
|
||||||
|
if (m_deselected_card_config)
|
||||||
|
{
|
||||||
|
for (util::xml::data_node const *node = m_deselected_card_config->get_first_child(); node; node = node->get_next_sibling())
|
||||||
|
node->copy_into(parentnode);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -2510,8 +2563,8 @@ void ioport_manager::save_game_inputs(util::xml::data_node &parentnode)
|
|||||||
// file
|
// file
|
||||||
//-------------------------------------------------
|
//-------------------------------------------------
|
||||||
|
|
||||||
template<typename _Type>
|
template<typename Type>
|
||||||
_Type ioport_manager::playback_read(_Type &result)
|
Type ioport_manager::playback_read(Type &result)
|
||||||
{
|
{
|
||||||
// protect against nullptr handles if previous reads fail
|
// protect against nullptr handles if previous reads fail
|
||||||
if (!m_playback_file.is_open())
|
if (!m_playback_file.is_open())
|
||||||
@ -2682,8 +2735,8 @@ void ioport_manager::playback_port(ioport_port &port)
|
|||||||
// record_write - write a value to the record file
|
// record_write - write a value to the record file
|
||||||
//-------------------------------------------------
|
//-------------------------------------------------
|
||||||
|
|
||||||
template<typename _Type>
|
template<typename Type>
|
||||||
void ioport_manager::record_write(_Type value)
|
void ioport_manager::record_write(Type value)
|
||||||
{
|
{
|
||||||
// protect against nullptr handles if previous reads fail
|
// protect against nullptr handles if previous reads fail
|
||||||
if (!m_record_file.is_open())
|
if (!m_record_file.is_open())
|
||||||
@ -2701,8 +2754,8 @@ void ioport_manager::record_write<bool>(bool value)
|
|||||||
record_write(byte);
|
record_write(byte);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename _Type>
|
template<typename Type>
|
||||||
void ioport_manager::timecode_write(_Type value)
|
void ioport_manager::timecode_write(Type value)
|
||||||
{
|
{
|
||||||
// protect against nullptr handles if previous reads fail
|
// protect against nullptr handles if previous reads fail
|
||||||
if (!m_timecode_file.is_open())
|
if (!m_timecode_file.is_open())
|
||||||
|
@ -1423,7 +1423,7 @@ private:
|
|||||||
void load_config(config_type cfg_type, util::xml::data_node const *parentnode);
|
void load_config(config_type cfg_type, util::xml::data_node const *parentnode);
|
||||||
void load_remap_table(util::xml::data_node const *parentnode);
|
void load_remap_table(util::xml::data_node const *parentnode);
|
||||||
bool load_default_config(util::xml::data_node const *portnode, int type, int player, const input_seq *newseq);
|
bool load_default_config(util::xml::data_node const *portnode, int type, int player, const input_seq *newseq);
|
||||||
bool load_game_config(util::xml::data_node const *portnode, int type, int player, const input_seq *newseq);
|
void load_game_config(util::xml::data_node const *portnode, int type, int player, const input_seq *newseq);
|
||||||
|
|
||||||
void save_config(config_type cfg_type, util::xml::data_node *parentnode);
|
void save_config(config_type cfg_type, util::xml::data_node *parentnode);
|
||||||
void save_sequence(util::xml::data_node &parentnode, input_seq_type type, ioport_type porttype, const input_seq &seq);
|
void save_sequence(util::xml::data_node &parentnode, input_seq_type type, ioport_type porttype, const input_seq &seq);
|
||||||
@ -1431,19 +1431,19 @@ private:
|
|||||||
void save_default_inputs(util::xml::data_node &parentnode);
|
void save_default_inputs(util::xml::data_node &parentnode);
|
||||||
void save_game_inputs(util::xml::data_node &parentnode);
|
void save_game_inputs(util::xml::data_node &parentnode);
|
||||||
|
|
||||||
template<typename _Type> _Type playback_read(_Type &result);
|
template<typename Type> Type playback_read(Type &result);
|
||||||
time_t playback_init();
|
time_t playback_init();
|
||||||
void playback_end(const char *message = nullptr);
|
void playback_end(const char *message = nullptr);
|
||||||
void playback_frame(const attotime &curtime);
|
void playback_frame(const attotime &curtime);
|
||||||
void playback_port(ioport_port &port);
|
void playback_port(ioport_port &port);
|
||||||
|
|
||||||
template<typename _Type> void record_write(_Type value);
|
template<typename Type> void record_write(Type value);
|
||||||
void record_init();
|
void record_init();
|
||||||
void record_end(const char *message = nullptr);
|
void record_end(const char *message = nullptr);
|
||||||
void record_frame(const attotime &curtime);
|
void record_frame(const attotime &curtime);
|
||||||
void record_port(ioport_port &port);
|
void record_port(ioport_port &port);
|
||||||
|
|
||||||
template<typename _Type> void timecode_write(_Type value);
|
template<typename Type> void timecode_write(Type value);
|
||||||
void timecode_init();
|
void timecode_init();
|
||||||
void timecode_end(const char *message = nullptr);
|
void timecode_end(const char *message = nullptr);
|
||||||
|
|
||||||
@ -1471,6 +1471,9 @@ private:
|
|||||||
emu_file m_timecode_file; // timecode/frames playback file (nullptr if not recording)
|
emu_file m_timecode_file; // timecode/frames playback file (nullptr if not recording)
|
||||||
int m_timecode_count;
|
int m_timecode_count;
|
||||||
attotime m_timecode_last_time;
|
attotime m_timecode_last_time;
|
||||||
|
|
||||||
|
// storage for inactive configuration
|
||||||
|
util::xml::file * m_deselected_card_config; // using smart pointer would pull xmlfile.h into emu.h
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user