From ea43e9a3865f386213a05ff1a82ec1f751197755 Mon Sep 17 00:00:00 2001 From: AJR Date: Wed, 18 May 2016 19:23:54 -0400 Subject: [PATCH] Ioport refactoring and cleanups (nw) - Completely move mouse hit testing down into the UI input module. This reduces some dependencies. - Never return a null pointer from ioport_field::name() to prevent potential crashes. All anonymous inputs are classified as INPUT_CLASS_INTERNAL, so several frontend functions now check type_class instead. - Correct a couple of typos. --- src/emu/ioport.cpp | 96 ++++++++++--------------- src/emu/ioport.h | 7 +- src/emu/machine.cpp | 2 +- src/emu/uiinput.cpp | 46 +++++++++++- src/emu/uiinput.h | 8 ++- src/emu/validity.cpp | 14 +++- src/frontend/mame/luaengine.cpp | 6 +- src/frontend/mame/ui/cheatopt.cpp | 2 +- src/frontend/mame/ui/inputmap.cpp | 11 ++- src/osd/modules/debugger/debugimgui.cpp | 1 + src/osd/sdl/window.cpp | 1 + src/osd/sdl/window.h | 2 + 12 files changed, 116 insertions(+), 80 deletions(-) diff --git a/src/emu/ioport.cpp b/src/emu/ioport.cpp index 5a68a76a0ae..971aa51080f 100644 --- a/src/emu/ioport.cpp +++ b/src/emu/ioport.cpp @@ -96,7 +96,6 @@ #include "xmlfile.h" #include "profiler.h" #include "ui/uimain.h" -#include "uiinput.h" #include "osdepend.h" @@ -1516,7 +1515,7 @@ ioport_field::~ioport_field() //------------------------------------------------- // name - return the field name for a given input -// field +// field (this must never return nullptr) //------------------------------------------------- const char *ioport_field::name() const @@ -1583,22 +1582,28 @@ const input_seq &ioport_field::defseq(input_seq_type seqtype) const ioport_type_class ioport_field::type_class() const { + // inputs associated with specific players ioport_group group = manager().type_group(m_type, m_player); - if (group >= IPG_PLAYER1 && group <= IPG_PLAYER8) + if (group >= IPG_PLAYER1 && group <= IPG_PLAYER10) return INPUT_CLASS_CONTROLLER; + // keys (names derived from character codes) if (m_type == IPT_KEYPAD || m_type == IPT_KEYBOARD) return INPUT_CLASS_KEYBOARD; + // configuration settings (specific names required) if (m_type == IPT_CONFIG) return INPUT_CLASS_CONFIG; + // DIP switches (specific names required) if (m_type == IPT_DIPSWITCH) return INPUT_CLASS_DIPSWITCH; + // miscellaneous non-player inputs (named and user-mappable) if (group == IPG_OTHER || (group == IPG_INVALID && m_name != nullptr)) return INPUT_CLASS_MISC; + // internal inputs (these may be anonymous) return INPUT_CLASS_INTERNAL; } @@ -1843,7 +1848,7 @@ void ioport_field::select_next_setting() // digital field //------------------------------------------------- -void ioport_field::frame_update(ioport_value &result, bool mouse_down) +void ioport_field::frame_update(ioport_value &result) { // skip if not enabled if (!enabled()) @@ -1861,7 +1866,7 @@ void ioport_field::frame_update(ioport_value &result, bool mouse_down) return; // if the state changed, look for switch down/switch up - bool curstate = mouse_down || machine().input().seq_pressed(seq()) || m_digital_value; + bool curstate = m_digital_value || machine().input().seq_pressed(seq()); if (m_live->autofire && !machine().ioport().get_autofire_toggle()) { if (curstate) @@ -1928,7 +1933,7 @@ void ioport_field::frame_update(ioport_value &result, bool mouse_down) curstate = false; // additional logic to restrict digital joysticks - if (curstate && !m_digital_value && !mouse_down && m_live->joystick != nullptr && m_way != 16 && !machine().options().joystick_contradictory()) + if (curstate && !m_digital_value && m_live->joystick != nullptr && m_way != 16 && !machine().options().joystick_contradictory()) { UINT8 mask = (m_way == 4) ? m_live->joystick->current4way() : m_live->joystick->current(); if (!(mask & (1 << m_live->joydir))) @@ -2273,14 +2278,14 @@ void ioport_port::write(ioport_value data, ioport_value mem_mask) // frame_update - once/frame update //------------------------------------------------- -void ioport_port::frame_update(ioport_field *mouse_field) +void ioport_port::frame_update() { // start with 0 values for the digital bits m_live->digital = 0; // now loop back and modify based on the inputs for (ioport_field &field : fields()) - field.frame_update(m_live->digital, &field == mouse_field); + field.frame_update(m_live->digital); // hook for MESS's natural keyboard support manager().natkeyboard().frame_update(*this, m_live->digital); @@ -2372,6 +2377,24 @@ void ioport_port::init_live_state() } +//------------------------------------------------- +// update_defvalue - force an update to the input +// port values based on current conditions +//------------------------------------------------- + +void ioport_port::update_defvalue(bool flush_defaults) +{ + // only clear on the first pass + if (flush_defaults) + m_live->defvalue = 0; + + // recompute the default value for the entire port + for (ioport_field &field : m_fieldlist) + if (field.enabled()) + m_live->defvalue = (m_live->defvalue & ~field.mask()) | (field.live().value & field.mask()); +} + + //************************************************************************** // I/O PORT LIVE STATE @@ -2648,10 +2671,10 @@ const char *ioport_manager::type_name(ioport_type type, UINT8 player) { // if we have a machine, use the live state and quick lookup input_type_entry *entry = m_type_to_entry[type][player]; - if (entry != nullptr) + if (entry != nullptr && entry->name() != nullptr) return entry->name(); - // if we find nothing, return an invalid group + // if we find nothing, return a default string (not a null pointer) return "???"; } @@ -2795,32 +2818,6 @@ bool ioport_manager::crosshair_position(int player, float &x, float &y) } -//------------------------------------------------- -// update_defaults - force an update to the input -// port values based on current conditions -//------------------------------------------------- - -void ioport_manager::update_defaults() -{ - // two passes to catch conditionals properly - for (int loopnum = 0; loopnum < 2; loopnum++) - { - // loop over all input ports - for (ioport_port &port : m_portlist) - { - // only clear on the first pass - if (loopnum == 0) - port.live().defvalue = 0; - - // first compute the default value for the entire port - for (ioport_field &field : port.fields()) - if (field.enabled()) - port.live().defvalue = (port.live().defvalue & ~field.mask()) | (field.live().value & field.mask()); - } - } -} - - //------------------------------------------------- // frame_update - core logic for per-frame input // port updating @@ -2873,31 +2870,16 @@ g_profiler.start(PROFILER_INPUT); joystick.frame_update(); // compute default values for all the ports - update_defaults(); - - // perform mouse hit testing - INT32 mouse_target_x, mouse_target_y; - bool mouse_button; - render_target *mouse_target = machine().ui_input().find_mouse(&mouse_target_x, &mouse_target_y, &mouse_button); - - // if the button is pressed, map the point and determine what was hit - ioport_field *mouse_field = nullptr; - if (mouse_button && mouse_target != nullptr) - { - ioport_port *port = nullptr; - ioport_value mask; - float x, y; - if (mouse_target->map_point_input(mouse_target_x, mouse_target_y, port, mask, x, y)) - { - if (port != nullptr) - mouse_field = port->field(mask); - } - } + // two passes to catch conditionals properly + for (ioport_port &port : m_portlist) + port.update_defvalue(true); + for (ioport_port &port : m_portlist) + port.update_defvalue(false); // loop over all input ports for (ioport_port &port : m_portlist) { - port.frame_update(mouse_field); + port.frame_update(); // handle playback/record playback_port(port); diff --git a/src/emu/ioport.h b/src/emu/ioport.h index 3f6a0185337..808bdd3d580 100644 --- a/src/emu/ioport.h +++ b/src/emu/ioport.h @@ -1117,6 +1117,7 @@ public: ioport_condition &condition() { return m_condition; } ioport_type type() const { return m_type; } UINT8 player() const { return m_player; } + bool digital_value() const { return m_digital_value; } void set_value(ioport_value value); bool unused() const { return ((m_flags & FIELD_FLAG_UNUSED) != 0); } @@ -1171,7 +1172,7 @@ public: void select_next_setting(); void crosshair_position(float &x, float &y, bool &gotx, bool &goty); void init_live_state(analog_field *analog); - void frame_update(ioport_value &result, bool mouse_down); + void frame_update(ioport_value &result); void reduce_mask(ioport_value bits_to_remove) { m_mask &= ~bits_to_remove; } // user-controllable settings for a field @@ -1308,8 +1309,9 @@ public: // other operations ioport_field *field(ioport_value mask) const; void collapse_fields(std::string &errorbuf); - void frame_update(ioport_field *mouse_field); + void frame_update(); void init_live_state(); + void update_defvalue(bool flush_defaults); private: void insert_field(ioport_field &newfield, ioport_value &disallowedbits, std::string &errorbuf); @@ -1516,7 +1518,6 @@ private: ioport_port *port(const char *tag) const { return m_portlist.find(tag); } void exit(); input_seq_type token_to_seq_type(const char *string); - void update_defaults(); void load_config(config_type cfg_type, xml_data_node *parentnode); void load_remap_table(xml_data_node *parentnode); diff --git a/src/emu/machine.cpp b/src/emu/machine.cpp index 6b18f910425..12c127f0e03 100644 --- a/src/emu/machine.cpp +++ b/src/emu/machine.cpp @@ -203,7 +203,7 @@ void running_machine::start() // allocate a soft_reset timer m_soft_reset_timer = m_scheduler.timer_alloc(timer_expired_delegate(FUNC(running_machine::soft_reset), this)); - // intialize UI input + // initialize UI input m_ui_input = make_unique_clear(*this); // init the osd layer diff --git a/src/emu/uiinput.cpp b/src/emu/uiinput.cpp index 8d710ebcbfc..9707793b2a3 100644 --- a/src/emu/uiinput.cpp +++ b/src/emu/uiinput.cpp @@ -25,17 +25,18 @@ enum //************************************************************************** -// NETWORK MANAGER +// UI INPUT MANAGER //************************************************************************** //------------------------------------------------- -// network_manager - constructor +// ui_input_manager - constructor //------------------------------------------------- ui_input_manager::ui_input_manager(running_machine &machine) : m_machine(machine), m_current_mouse_target(nullptr), m_current_mouse_down(false), + m_current_mouse_field(nullptr), m_events_start(0), m_events_end(0) { @@ -68,6 +69,22 @@ void ui_input_manager::frame_update() if (!pressed || m_seqpressed[code] != SEQ_PRESSED_RESET) m_seqpressed[code] = pressed; } + + // perform mouse hit testing + ioport_field *mouse_field = m_current_mouse_down ? find_mouse_field() : nullptr; + if (m_current_mouse_field != mouse_field) + { + // clear the old field if there was one + if (m_current_mouse_field != nullptr) + m_current_mouse_field->set_value(0); + + // set the new field if it exists and isn't already being pressed + if (mouse_field != nullptr && !mouse_field->digital_value()) + mouse_field->set_value(1); + + // update internal state + m_current_mouse_field = mouse_field; + } } @@ -166,7 +183,7 @@ void ui_input_manager::reset() location of the mouse -------------------------------------------------*/ -render_target *ui_input_manager::find_mouse(INT32 *x, INT32 *y, bool *button) +render_target *ui_input_manager::find_mouse(INT32 *x, INT32 *y, bool *button) const { if (x != nullptr) *x = m_current_mouse_x; @@ -178,6 +195,29 @@ render_target *ui_input_manager::find_mouse(INT32 *x, INT32 *y, bool *button) } +/*------------------------------------------------- + find_mouse_field - retrieves the input field + the mouse is currently pointing at +-------------------------------------------------*/ + +ioport_field *ui_input_manager::find_mouse_field() const +{ + // map the point and determine what was hit + if (m_current_mouse_target != nullptr) + { + ioport_port *port = nullptr; + ioport_value mask; + float x, y; + if (m_current_mouse_target->map_point_input(m_current_mouse_x, m_current_mouse_y, port, mask, x, y)) + { + if (port != nullptr) + return port->field(mask); + } + } + return nullptr; +} + + /*************************************************************************** USER INTERFACE SEQUENCE READING diff --git a/src/emu/uiinput.h b/src/emu/uiinput.h index 2bd715e01aa..e1752f64b19 100644 --- a/src/emu/uiinput.h +++ b/src/emu/uiinput.h @@ -12,8 +12,6 @@ #ifndef __UIINPUT_H__ #define __UIINPUT_H__ -#include "render.h" - /*************************************************************************** CONSTANTS @@ -25,6 +23,8 @@ TYPE DEFINITIONS ***************************************************************************/ +class render_target; + enum ui_event_type { UI_EVENT_NONE, @@ -71,7 +71,8 @@ public: void reset(); /* retrieves the current location of the mouse */ - render_target *find_mouse(INT32 *x, INT32 *y, bool *button); + render_target *find_mouse(INT32 *x, INT32 *y, bool *button) const; + ioport_field *find_mouse_field() const; /* return TRUE if a key down for the given user interface sequence is detected */ bool pressed(int code); @@ -110,6 +111,7 @@ private: INT32 m_current_mouse_x; INT32 m_current_mouse_y; bool m_current_mouse_down; + ioport_field * m_current_mouse_field; /* popped states; ring buffer of ui_events */ ui_event m_events[EVENT_QUEUE_SIZE]; diff --git a/src/emu/validity.cpp b/src/emu/validity.cpp index 91f218b9470..f31cd20a8cd 100644 --- a/src/emu/validity.cpp +++ b/src/emu/validity.cpp @@ -872,14 +872,22 @@ void validity_checker::validate_inputs() // verify dip switches if (field.type() == IPT_DIPSWITCH) { - // dip switch fields must have a name - if (field.name() == nullptr) - osd_printf_error("DIP switch has a nullptr name\n"); + // dip switch fields must have a specific name + if (field.specific_name() == nullptr) + osd_printf_error("DIP switch has no specific name\n"); // verify the settings list validate_dip_settings(field); } + // verify config settings + if (field.type() == IPT_CONFIG) + { + // config fields must have a specific name + if (field.specific_name() == nullptr) + osd_printf_error("Config switch has no specific name\n"); + } + // verify names const char *name = field.specific_name(); if (name != nullptr) diff --git a/src/frontend/mame/luaengine.cpp b/src/frontend/mame/luaengine.cpp index 8a4c702b2a5..209795a53d9 100644 --- a/src/frontend/mame/luaengine.cpp +++ b/src/frontend/mame/luaengine.cpp @@ -664,7 +664,7 @@ luabridge::LuaRef lua_engine::l_ioports_port_get_fields(const ioport_port *i) luabridge::LuaRef f_table = luabridge::LuaRef::newTable(L); for (ioport_field &field : p->fields()) { - if(field.name()) + if (field.type_class() != INPUT_CLASS_INTERNAL) f_table[field.name()] = &field; } @@ -1985,7 +1985,7 @@ void lua_engine::update_machine() { for (ioport_field &field : port.fields()) { - if (field.name()) + if (field.type_class() != INPUT_CLASS_INTERNAL) { push(m_lua_state, &field, tname_ioport); lua_setfield(m_lua_state, -2, field.name()); @@ -2214,7 +2214,7 @@ void lua_engine::initialize() .addProperty ("sensitivity", &ioport_field::sensitivity) .addProperty ("way", &ioport_field::way) .addProperty ("is_analog", &ioport_field::is_analog) - .addProperty ("is_digitial_joystick", &ioport_field::is_digital_joystick) + .addProperty ("is_digital_joystick", &ioport_field::is_digital_joystick) .addProperty ("enabled", &ioport_field::enabled) .addProperty ("unused", &ioport_field::unused) .addProperty ("cocktail", &ioport_field::cocktail) diff --git a/src/frontend/mame/ui/cheatopt.cpp b/src/frontend/mame/ui/cheatopt.cpp index ae6a4e9c508..87b748fb3cc 100644 --- a/src/frontend/mame/ui/cheatopt.cpp +++ b/src/frontend/mame/ui/cheatopt.cpp @@ -263,7 +263,7 @@ void ui_menu_autofire::populate() bool is_first_button = true; for (ioport_field &field : port.fields()) { - if ((field.name()) && ((field.type() >= IPT_BUTTON1 && field.type() <= IPT_BUTTON16))) // IPT_BUTTON1 + 15))) + if (field.type() >= IPT_BUTTON1 && field.type() <= IPT_BUTTON16) { menu_items++; ioport_field::user_settings settings; diff --git a/src/frontend/mame/ui/inputmap.cpp b/src/frontend/mame/ui/inputmap.cpp index 919b21b4063..ed0778d9b29 100644 --- a/src/frontend/mame/ui/inputmap.cpp +++ b/src/frontend/mame/ui/inputmap.cpp @@ -167,20 +167,19 @@ void ui_menu_input_specific::populate() port_count++; for (ioport_field &field : port.fields()) { - const char *name = field.name(); + ioport_type_class type_class = field.type_class(); /* add if we match the group and we have a valid name */ - if (name != nullptr && field.enabled() && - ((field.type() == IPT_OTHER && field.name() != nullptr) || machine().ioport().type_group(field.type(), field.player()) != IPG_INVALID)) + if (field.enabled() && (type_class == INPUT_CLASS_CONTROLLER || type_class == INPUT_CLASS_MISC)) { input_seq_type seqtype; UINT32 sortorder; /* determine the sorting order */ - if (field.type() >= IPT_START1 && field.type() < IPT_ANALOG_LAST) + if (type_class == INPUT_CLASS_CONTROLLER) { sortorder = (field.type() << 2) | (field.player() << 12); - if (strcmp(field.device().tag(), ":")) + if (field.device().owner() != nullptr) sortorder |= (port_count & 0xfff) * 0x10000; } else @@ -200,7 +199,7 @@ void ui_menu_input_specific::populate() item->defseq = &field.defseq(seqtype); item->sortorder = sortorder + suborder[seqtype]; item->type = field.is_analog() ? (INPUT_TYPE_ANALOG + seqtype) : INPUT_TYPE_DIGITAL; - item->name = name; + item->name = field.name(); item->owner_name = field.device().tag(); item->next = itemlist; itemlist = item; diff --git a/src/osd/modules/debugger/debugimgui.cpp b/src/osd/modules/debugger/debugimgui.cpp index ee2038da1c6..44cff250869 100644 --- a/src/osd/modules/debugger/debugimgui.cpp +++ b/src/osd/modules/debugger/debugimgui.cpp @@ -4,6 +4,7 @@ #include "emu.h" #include "imgui/imgui.h" +#include "render.h" #include "uiinput.h" #include "debug/debugvw.h" diff --git a/src/osd/sdl/window.cpp b/src/osd/sdl/window.cpp index 7e24e4a634e..6072eb0ddd0 100644 --- a/src/osd/sdl/window.cpp +++ b/src/osd/sdl/window.cpp @@ -28,6 +28,7 @@ #include "emu.h" #include "emuopts.h" +#include "render.h" #include "ui/uimain.h" // OSD headers diff --git a/src/osd/sdl/window.h b/src/osd/sdl/window.h index 0a99870675f..ed03359d0ae 100644 --- a/src/osd/sdl/window.h +++ b/src/osd/sdl/window.h @@ -25,6 +25,8 @@ // TYPE DEFINITIONS //============================================================ +class render_target; + // forward of SDL_DisplayMode not possible (typedef struct) - define wrapper class SDL_DM_Wrapper;