diff options
Diffstat (limited to 'src/emu/inputdev.cpp')
-rw-r--r-- | src/emu/inputdev.cpp | 947 |
1 files changed, 947 insertions, 0 deletions
diff --git a/src/emu/inputdev.cpp b/src/emu/inputdev.cpp new file mode 100644 index 00000000000..cf56387578f --- /dev/null +++ b/src/emu/inputdev.cpp @@ -0,0 +1,947 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles +/*************************************************************************** + + inputdev.cpp + + Input devices, items and device classes. + +***************************************************************************/ + +#include "emu.h" +#include "emuopts.h" +#include "inputdev.h" + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> input_device_switch_item + +// derived input item representing a switch input +class input_device_switch_item : public input_device_item +{ +public: + // construction/destruction + input_device_switch_item(input_device &device, const char *name, void *internal, input_item_id itemid, item_get_state_func getstate); + + // readers + virtual int32_t read_as_switch(input_item_modifier modifier) override; + virtual int32_t read_as_relative(input_item_modifier modifier) override; + virtual int32_t read_as_absolute(input_item_modifier modifier) override; + + // steadykey helper + bool steadykey_changed(); + void steadykey_update_to_current() { m_steadykey = m_current; } + +private: + // internal state + int32_t m_steadykey; // the live steadykey state + int32_t m_oldkey; // old live state +}; + + +// ======================> input_device_switch_item + +// derived input item representing a relative axis input +class input_device_relative_item : public input_device_item +{ +public: + // construction/destruction + input_device_relative_item(input_device &device, const char *name, void *internal, input_item_id itemid, item_get_state_func getstate); + + // readers + virtual int32_t read_as_switch(input_item_modifier modifier) override; + virtual int32_t read_as_relative(input_item_modifier modifier) override; + virtual int32_t read_as_absolute(input_item_modifier modifier) override; +}; + + +// ======================> input_device_switch_item + +// derived input item representing an absolute axis input +class input_device_absolute_item : public input_device_item +{ +public: + // construction/destruction + input_device_absolute_item(input_device &device, const char *name, void *internal, input_item_id itemid, item_get_state_func getstate); + + // readers + virtual int32_t read_as_switch(input_item_modifier modifier) override; + virtual int32_t read_as_relative(input_item_modifier modifier) override; + virtual int32_t read_as_absolute(input_item_modifier modifier) override; +}; + + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +// standard joystick mappings +const char input_class_joystick::map_8way[] = "7778...4445"; +const char input_class_joystick::map_4way_diagonal[] = "4444s8888..444458888.444555888.ss5.222555666.222256666.2222s6666.2222s6666"; +// const char input_class_joystick::map_4way_sticky[] = "s8.4s8.44s8.4445"; + + +//************************************************************************** +// JOYSTICK MAP +//************************************************************************** + +//------------------------------------------------- +// joystick_map - constructor +//------------------------------------------------- + +joystick_map::joystick_map() + : m_lastmap(JOYSTICK_MAP_NEUTRAL) +{ + // parse the standard 8-way map as default + parse(input_class_joystick::map_8way); +} + + +//------------------------------------------------- +// parse - parse a string into a joystick map +//------------------------------------------------- + +bool joystick_map::parse(const char *mapstring) +{ + // save a copy of the original string + m_origstring = mapstring; + + // iterate over rows + for (int rownum = 0; rownum < 9; rownum++) + { + // if we're done, copy from another row + if (*mapstring == 0 || *mapstring == '.') + { + bool symmetric = (rownum >= 5 && *mapstring == 0); + const uint8_t *srcrow = &m_map[symmetric ? (8 - rownum) : (rownum - 1)][0]; + + // if this is row 0, we don't have a source row -- invalid + if (rownum == 0) + return false; + + // copy from the srcrow, applying up/down symmetry if in the bottom half + for (int colnum = 0; colnum < 9; colnum++) + { + uint8_t val = srcrow[colnum]; + if (symmetric) + val = (val & (JOYSTICK_MAP_LEFT | JOYSTICK_MAP_RIGHT)) | ((val & JOYSTICK_MAP_UP) << 1) | ((val & JOYSTICK_MAP_DOWN) >> 1); + m_map[rownum][colnum] = val; + } + } + + // otherwise, parse this column + else + { + for (int colnum = 0; colnum < 9; colnum++) + { + // if we're at the end of row, copy previous to the middle, then apply left/right symmetry + if (colnum > 0 && (*mapstring == 0 || *mapstring == '.')) + { + bool symmetric = (colnum >= 5); + uint8_t val = m_map[rownum][symmetric ? (8 - colnum) : (colnum - 1)]; + if (symmetric) + val = (val & (JOYSTICK_MAP_UP | JOYSTICK_MAP_DOWN)) | ((val & JOYSTICK_MAP_LEFT) << 1) | ((val & JOYSTICK_MAP_RIGHT) >> 1); + m_map[rownum][colnum] = val; + } + + // otherwise, convert the character to its value + else + { + static const uint8_t charmap[] = + { + JOYSTICK_MAP_UP | JOYSTICK_MAP_LEFT, + JOYSTICK_MAP_UP, + JOYSTICK_MAP_UP | JOYSTICK_MAP_RIGHT, + JOYSTICK_MAP_LEFT, + JOYSTICK_MAP_NEUTRAL, + JOYSTICK_MAP_RIGHT, + JOYSTICK_MAP_DOWN | JOYSTICK_MAP_LEFT, + JOYSTICK_MAP_DOWN, + JOYSTICK_MAP_DOWN | JOYSTICK_MAP_RIGHT, + JOYSTICK_MAP_STICKY + }; + static const char validchars[] = "789456123s"; + const char *ptr = strchr(validchars, *mapstring++); + + // invalid characters exit immediately + if (ptr == nullptr) + return false; + m_map[rownum][colnum] = charmap[ptr - validchars]; + } + } + } + + // if we ended with a period, advance to the next row + if (*mapstring == '.') + mapstring++; + } + return true; +} + + +//------------------------------------------------- +// to_string - output the map as a string for +// friendly display +//------------------------------------------------- + +std::string joystick_map::to_string() const +{ + std::string str(m_origstring); + str.append("\n"); + for (auto & elem : m_map) + { + str.append(" "); + for (auto & elem_colnum : elem) + switch (elem_colnum) + { + case JOYSTICK_MAP_UP | JOYSTICK_MAP_LEFT: str.append("7"); break; + case JOYSTICK_MAP_UP: str.append("8"); break; + case JOYSTICK_MAP_UP | JOYSTICK_MAP_RIGHT: str.append("9"); break; + case JOYSTICK_MAP_LEFT: str.append("4"); break; + case JOYSTICK_MAP_NEUTRAL: str.append("5"); break; + case JOYSTICK_MAP_RIGHT: str.append("6"); break; + case JOYSTICK_MAP_DOWN | JOYSTICK_MAP_LEFT: str.append("1"); break; + case JOYSTICK_MAP_DOWN: str.append("2"); break; + case JOYSTICK_MAP_DOWN | JOYSTICK_MAP_RIGHT:str.append("3"); break; + case JOYSTICK_MAP_STICKY: str.append("s"); break; + default: str.append("?"); break; + } + + str.append("\n"); + } + return str; +} + + +//------------------------------------------------- +// update - update the state of the joystick +// map based on the given X/Y axis values +//------------------------------------------------- + +uint8_t joystick_map::update(int32_t xaxisval, int32_t yaxisval) +{ + // now map the X and Y axes to a 9x9 grid using the raw values + xaxisval = ((xaxisval - INPUT_ABSOLUTE_MIN) * 9) / (INPUT_ABSOLUTE_MAX - INPUT_ABSOLUTE_MIN + 1); + yaxisval = ((yaxisval - INPUT_ABSOLUTE_MIN) * 9) / (INPUT_ABSOLUTE_MAX - INPUT_ABSOLUTE_MIN + 1); + uint8_t mapval = m_map[yaxisval][xaxisval]; + + // handle stickiness + if (mapval == JOYSTICK_MAP_STICKY) + mapval = m_lastmap; + else + m_lastmap = mapval; + + // return based on whether the appropriate bit is set + return mapval; +} + + + +//************************************************************************** +// INPUT DEVICE +//************************************************************************** + +//------------------------------------------------- +// input_device - constructor +//------------------------------------------------- + +input_device::input_device(input_manager &manager, const char *name, const char *id, void *internal) + : m_manager(manager), + m_name(name), + m_id(id), + m_devindex(-1), + m_maxitem(input_item_id(0)), + m_internal(internal), + m_steadykey_enabled(manager.machine().options().steadykey()), + m_lightgun_reload_button(manager.machine().options().offscreen_reload()) +{ +} + + +//------------------------------------------------- +// input_device - destructor +//------------------------------------------------- + +input_device::~input_device() +{ +} + + +//------------------------------------------------- +// add_item - add a new item to an input device +//------------------------------------------------- + +input_item_id input_device::add_item(const char *name, input_item_id itemid, item_get_state_func getstate, void *internal) +{ + assert_always(machine().phase() == MACHINE_PHASE_INIT, "Can only call input_device::add_item at init time!"); + assert(name != nullptr); + assert(itemid > ITEM_ID_INVALID && itemid < ITEM_ID_MAXIMUM); + assert(getstate != nullptr); + + // if we have a generic ID, pick a new internal one + input_item_id originalid = itemid; + if (itemid >= ITEM_ID_OTHER_SWITCH && itemid <= ITEM_ID_OTHER_AXIS_RELATIVE) + for (itemid = (input_item_id)(ITEM_ID_MAXIMUM + 1); itemid <= ITEM_ID_ABSOLUTE_MAXIMUM; ++itemid) + if (m_item[itemid] == nullptr) + break; + assert(itemid <= ITEM_ID_ABSOLUTE_MAXIMUM); + + // make sure we don't have any overlap + assert(m_item[itemid] == nullptr); + + // determine the class and create the appropriate item class + switch (m_manager.device_class(devclass()).standard_item_class(originalid)) + { + case ITEM_CLASS_SWITCH: + m_item[itemid] = std::make_unique<input_device_switch_item>(*this, name, internal, itemid, getstate); + break; + + case ITEM_CLASS_RELATIVE: + m_item[itemid] = std::make_unique<input_device_relative_item>(*this, name, internal, itemid, getstate); + break; + + case ITEM_CLASS_ABSOLUTE: + m_item[itemid] = std::make_unique<input_device_absolute_item>(*this, name, internal, itemid, getstate); + break; + + default: + m_item[itemid] = nullptr; + assert(false); + } + + // assign the new slot and update the maximum + m_maxitem = std::max(m_maxitem, itemid); + return itemid; +} + + +//------------------------------------------------- +// match_device_id - match device id via +// substring search +//------------------------------------------------- + +bool input_device::match_device_id(const char *deviceid) +{ + std::string deviceidupper(deviceid); + std::string idupper(m_id); + + strmakeupper(deviceidupper); + strmakeupper(idupper); + + return std::string::npos == idupper.find(deviceidupper) ? false : true; +} + + +//************************************************************************** +// SPECIFIC INPUT DEVICES +//************************************************************************** + +//------------------------------------------------- +// input_device_keyboard - constructor +//------------------------------------------------- + +input_device_keyboard::input_device_keyboard(input_manager &manager, const char *_name, const char *_id, void *_internal) + : input_device(manager, _name, _id, _internal) +{ +} + + +//------------------------------------------------- +// apply_steadykey - apply steadykey option +//------------------------------------------------- + +void input_device_keyboard::apply_steadykey() const +{ + // ignore if not enabled + if (!steadykey_enabled()) + return; + + // update the state of all the keys and see if any changed state + bool anything_changed = false; + for (input_item_id itemid = ITEM_ID_FIRST_VALID; itemid <= maxitem(); ++itemid) + { + input_device_item *itm = item(itemid); + if (itm != nullptr && itm->itemclass() == ITEM_CLASS_SWITCH) + if (downcast<input_device_switch_item &>(*itm).steadykey_changed()) + anything_changed = true; + } + + // if the keyboard state is stable, flush the current state + if (!anything_changed) + for (input_item_id itemid = ITEM_ID_FIRST_VALID; itemid <= maxitem(); ++itemid) + { + input_device_item *itm = item(itemid); + if (itm != nullptr && itm->itemclass() == ITEM_CLASS_SWITCH) + downcast<input_device_switch_item &>(*itm).steadykey_update_to_current(); + } +} + + +//------------------------------------------------- +// input_device_mouse - constructor +//------------------------------------------------- + +input_device_mouse::input_device_mouse(input_manager &manager, const char *_name, const char *_id, void *_internal) + : input_device(manager, _name, _id, _internal) +{ +} + + +//------------------------------------------------- +// input_device_lightgun - constructor +//------------------------------------------------- + +input_device_lightgun::input_device_lightgun(input_manager &manager, const char *_name, const char *_id, void *_internal) + : input_device(manager, _name, _id, _internal) +{ +} + + +//------------------------------------------------- +// input_device_joystick - constructor +//------------------------------------------------- + +input_device_joystick::input_device_joystick(input_manager &manager, const char *_name, const char *_id, void *_internal) + : input_device(manager, _name, _id, _internal), + m_joystick_deadzone((int32_t)(manager.machine().options().joystick_deadzone() * INPUT_ABSOLUTE_MAX)), + m_joystick_saturation((int32_t)(manager.machine().options().joystick_saturation() * INPUT_ABSOLUTE_MAX)) +{ + // get the default joystick map + const char *mapstring = machine().options().joystick_map(); + if (mapstring[0] == 0 || strcmp(mapstring, "auto") == 0) + mapstring = input_class_joystick::map_8way; + + // parse it + if (!m_joymap.parse(mapstring)) + { + osd_printf_error("Invalid joystick map: %s\n", mapstring); + m_joymap.parse(input_class_joystick::map_8way); + } + else if (mapstring != input_class_joystick::map_8way) + osd_printf_verbose("Input: Default joystick map = %s\n", m_joymap.to_string().c_str()); +} + + +//------------------------------------------------- +// adjust_absolute_value - apply joystick device +// deadzone and saturation parameters to an +// absolute value +//------------------------------------------------- + +int32_t input_device_joystick::adjust_absolute_value(int32_t result) const +{ + // properties are symmetric + bool negative = false; + if (result < 0) + { + negative = true; + result = -result; + } + + // if in the deadzone, return 0 + if (result < m_joystick_deadzone) + result = 0; + + // if saturated, return the max + else if (result > m_joystick_saturation) + result = INPUT_ABSOLUTE_MAX; + + // otherwise, scale + else + result = (int64_t)(result - m_joystick_deadzone) * (int64_t)INPUT_ABSOLUTE_MAX / (int64_t)(m_joystick_saturation - m_joystick_deadzone); + + // re-apply sign and return + return negative ? -result : result; +} + + +//************************************************************************** +// INPUT CLASS +//************************************************************************** + +//------------------------------------------------- +// input_class - constructor +//------------------------------------------------- + +input_class::input_class(input_manager &manager, input_device_class devclass, const char *name, bool enabled, bool multi) + : m_manager(manager), + m_devclass(devclass), + m_name(name), + m_maxindex(0), + m_enabled(enabled), + m_multi(multi) +{ + assert(m_name != nullptr); +} + + +//------------------------------------------------- +// input_class - destructor +//------------------------------------------------- + +input_class::~input_class() +{ +} + + +//------------------------------------------------- +// add_device - add a new input device +//------------------------------------------------- + +input_device *input_class::add_device(const char *name, const char *id, void *internal) +{ + assert_always(machine().phase() == MACHINE_PHASE_INIT, "Can only call input_class::add_device at init time!"); + assert(name != nullptr); + assert(id != nullptr); + + // allocate a new device and add it to the index + return add_device(make_device(name, id, internal)); +} + +input_device *input_class::add_device(std::unique_ptr<input_device> &&new_device) +{ + assert(new_device->devclass() == m_devclass); + + // find the next empty index + for (int devindex = 0; devindex < DEVICE_INDEX_MAXIMUM; devindex++) + if (m_device[devindex] == nullptr) + { + // update the device and maximum index found + new_device->set_devindex(devindex); + m_maxindex = std::max(m_maxindex, devindex); + + if (new_device->id()[0] == 0) + osd_printf_verbose("Input: Adding %s #%d: %s\n", m_name, devindex, new_device->name()); + else + osd_printf_verbose("Input: Adding %s #%d: %s (device id: %s)\n", m_name, devindex, new_device->name(), new_device->id()); + + m_device[devindex] = std::move(new_device); + return m_device[devindex].get(); + } + + throw emu_fatalerror("Input: Too many %s devices\n", m_name); +} + + +//------------------------------------------------- +// standard_item_class - return the class of a +// standard item +//------------------------------------------------- + +input_item_class input_class::standard_item_class(input_item_id itemid) const +{ + // most everything standard is a switch, apart from the axes + if (itemid == ITEM_ID_OTHER_SWITCH || itemid < ITEM_ID_XAXIS || (itemid > ITEM_ID_SLIDER2 && itemid < ITEM_ID_ADD_ABSOLUTE1)) + return ITEM_CLASS_SWITCH; + + // standard mouse axes are relative + else if (m_devclass == DEVICE_CLASS_MOUSE || itemid == ITEM_ID_OTHER_AXIS_RELATIVE || (itemid >= ITEM_ID_ADD_RELATIVE1 && itemid <= ITEM_ID_ADD_RELATIVE16)) + return ITEM_CLASS_RELATIVE; + + // all other standard axes are absolute + else + return ITEM_CLASS_ABSOLUTE; +} + + +//------------------------------------------------- +// remap_device_index - remaps device index by +// mapping oldindex to newindex +//------------------------------------------------- + +void input_class::remap_device_index(int oldindex, int newindex) +{ + assert(oldindex >= 0 && oldindex < DEVICE_INDEX_MAXIMUM); + assert(newindex >= 0 && newindex < DEVICE_INDEX_MAXIMUM); + + // swap indexes in m_device array + m_device[oldindex].swap(m_device[newindex]); + + // update device indexes + if (nullptr != m_device[oldindex].get()) + m_device[oldindex]->set_devindex(oldindex); + + if (nullptr != m_device[newindex].get()) + m_device[newindex]->set_devindex(newindex); + + // update the maximum index found, since newindex may + // exceed current m_maxindex + m_maxindex = std::max(m_maxindex, newindex); +} + + +//************************************************************************** +// SPECIFIC INPUT CLASSES +//************************************************************************** + +//------------------------------------------------- +// input_class_keyboard - constructor +//------------------------------------------------- + +input_class_keyboard::input_class_keyboard(input_manager &manager) + : input_class(manager, DEVICE_CLASS_KEYBOARD, "keyboard", true, manager.machine().options().multi_keyboard()) +{ + // request a per-frame callback for the keyboard class + machine().add_notifier(MACHINE_NOTIFY_FRAME, machine_notify_delegate(FUNC(input_class_keyboard::frame_callback), this)); +} + + +//------------------------------------------------- +// frame_callback - per-frame callback for various +// bookkeeping +//------------------------------------------------- + +void input_class_keyboard::frame_callback() +{ + // iterate over all devices in our class + for (int devnum = 0; devnum <= maxindex(); devnum++) + if (device(devnum) != nullptr) + downcast<input_device_keyboard &>(*device(devnum)).apply_steadykey(); +} + + +//------------------------------------------------- +// input_class_mouse - constructor +//------------------------------------------------- + +input_class_mouse::input_class_mouse(input_manager &manager) + : input_class(manager, DEVICE_CLASS_MOUSE, "mouse", manager.machine().options().mouse(), manager.machine().options().multi_mouse()) +{ +} + + +//------------------------------------------------- +// input_class_lightgun - constructor +//------------------------------------------------- + +input_class_lightgun::input_class_lightgun(input_manager &manager) + : input_class(manager, DEVICE_CLASS_LIGHTGUN, "lightgun", manager.machine().options().lightgun(), true) +{ +} + + +//------------------------------------------------- +// input_class_joystick - constructor +//------------------------------------------------- + +input_class_joystick::input_class_joystick(input_manager &manager) + : input_class(manager, DEVICE_CLASS_JOYSTICK, "joystick", manager.machine().options().joystick(), true) +{ +} + + +//------------------------------------------------- +// set_global_joystick_map - set the map for all +// joysticks +//------------------------------------------------- + +bool input_class_joystick::set_global_joystick_map(const char *mapstring) +{ + // parse the map + joystick_map map; + if (!map.parse(mapstring)) + return false; + + osd_printf_verbose("Input: Changing default joystick map = %s\n", map.to_string().c_str()); + + // iterate over joysticks and set the map + for (int joynum = 0; joynum <= maxindex(); joynum++) + if (device(joynum) != nullptr) + downcast<input_device_joystick &>(*device(joynum)).set_joystick_map(map); + return true; +} + + +//************************************************************************** +// INPUT DEVICE ITEM +//************************************************************************** + +//------------------------------------------------- +// input_device_item - constructor +//------------------------------------------------- + +input_device_item::input_device_item(input_device &device, const char *name, void *internal, input_item_id itemid, item_get_state_func getstate, input_item_class itemclass) + : m_device(device), + m_name(name), + m_internal(internal), + m_itemid(itemid), + m_itemclass(itemclass), + m_getstate(getstate), + m_current(0), + m_memory(0) +{ + // use a standard token name for know item IDs + const char *standard_token = manager().standard_token(itemid); + if (standard_token != nullptr) + m_token.assign(standard_token); + + // otherwise, create a tokenized name + else { + m_token.assign(name); + strmakeupper(m_token); + strdelchr(m_token, ' '); + strdelchr(m_token, '_'); + } +} + + +//------------------------------------------------- +// input_device_item - destructor +//------------------------------------------------- + +input_device_item::~input_device_item() +{ +} + + + +//************************************************************************** +// INPUT DEVICE SWITCH ITEM +//************************************************************************** + +//------------------------------------------------- +// input_device_switch_item - constructor +//------------------------------------------------- + +input_device_switch_item::input_device_switch_item(input_device &device, const char *name, void *internal, input_item_id itemid, item_get_state_func getstate) + : input_device_item(device, name, internal, itemid, getstate, ITEM_CLASS_SWITCH), + m_steadykey(0), + m_oldkey(0) +{ +} + + +//------------------------------------------------- +// read_as_switch - return the raw switch value, +// modified as necessary +//------------------------------------------------- + +int32_t input_device_switch_item::read_as_switch(input_item_modifier modifier) +{ + // if we're doing a lightgun reload hack, button 1 and 2 operate differently + input_device_class devclass = m_device.devclass(); + if (devclass == DEVICE_CLASS_LIGHTGUN && m_device.lightgun_reload_button()) + { + // button 1 is pressed if either button 1 or 2 are active + if (m_itemid == ITEM_ID_BUTTON1) + { + input_device_item *button2_item = m_device.item(ITEM_ID_BUTTON2); + if (button2_item != nullptr) + return button2_item->update_value() | update_value(); + } + + // button 2 is never officially pressed + if (m_itemid == ITEM_ID_BUTTON2) + return 0; + } + + // steadykey for keyboards + if (devclass == DEVICE_CLASS_KEYBOARD && m_device.steadykey_enabled()) + return m_steadykey; + + // everything else is just the current value as-is + return update_value(); +} + + +//------------------------------------------------- +// read_as_relative - return the switch input as +// a relative axis value +//------------------------------------------------- + +int32_t input_device_switch_item::read_as_relative(input_item_modifier modifier) +{ + // no translation to relative + return 0; +} + + +//------------------------------------------------- +// read_as_absolute - return the switch input as +// an absolute axis value +//------------------------------------------------- + +int32_t input_device_switch_item::read_as_absolute(input_item_modifier modifier) +{ + // no translation to absolute + return 0; +} + + +//------------------------------------------------- +// steadykey_changed - update for steadykey +// behavior, returning true if the current state +// has changed since the last call +//------------------------------------------------- + +bool input_device_switch_item::steadykey_changed() +{ + int32_t old = m_oldkey; + m_oldkey = update_value(); + if (((m_current ^ old) & 1) == 0) + return false; + + // if the keypress was missed, turn it on for one frame + if (((m_current | m_steadykey) & 1) == 0) + m_steadykey = 1; + return true; +} + + + +//************************************************************************** +// INPUT DEVICE RELATIVE ITEM +//************************************************************************** + +//------------------------------------------------- +// input_device_relative_item - constructor +//------------------------------------------------- + +input_device_relative_item::input_device_relative_item(input_device &device, const char *name, void *internal, input_item_id itemid, item_get_state_func getstate) + : input_device_item(device, name, internal, itemid, getstate, ITEM_CLASS_RELATIVE) +{ +} + + +//------------------------------------------------- +// read_as_switch - return the relative value as +// a switch result based on the modifier +//------------------------------------------------- + +int32_t input_device_relative_item::read_as_switch(input_item_modifier modifier) +{ + // process according to modifiers + if (modifier == ITEM_MODIFIER_POS || modifier == ITEM_MODIFIER_RIGHT || modifier == ITEM_MODIFIER_DOWN) + return (update_value() > 0); + else if (modifier == ITEM_MODIFIER_NEG || modifier == ITEM_MODIFIER_LEFT || modifier == ITEM_MODIFIER_UP) + return (update_value() < 0); + + // all other cases just return 0 + return 0; +} + + +//------------------------------------------------- +// read_as_relative - return the relative input +// as a relative axis value +//------------------------------------------------- + +int32_t input_device_relative_item::read_as_relative(input_item_modifier modifier) +{ + // just return directly + return update_value(); +} + + +//------------------------------------------------- +// read_as_absolute - return the relative input +// as an absolute axis value +//------------------------------------------------- + +int32_t input_device_relative_item::read_as_absolute(input_item_modifier modifier) +{ + // no translation to absolute + return 0; +} + + + +//************************************************************************** +// INPUT DEVICE ABSOLUTE ITEM +//************************************************************************** + +//------------------------------------------------- +// input_device_absolute_item - constructor +//------------------------------------------------- + +input_device_absolute_item::input_device_absolute_item(input_device &device, const char *name, void *internal, input_item_id itemid, item_get_state_func getstate) + : input_device_item(device, name, internal, itemid, getstate, ITEM_CLASS_ABSOLUTE) +{ +} + + +//------------------------------------------------- +// read_as_switch - return the absolute value as +// a switch result based on the modifier +//------------------------------------------------- + +int32_t input_device_absolute_item::read_as_switch(input_item_modifier modifier) +{ + // start with the current value + int32_t result = m_device.adjust_absolute(update_value()); + assert(result >= INPUT_ABSOLUTE_MIN && result <= INPUT_ABSOLUTE_MAX); + + // left/right/up/down: if this is a joystick, fetch the paired X/Y axis values and convert + if (m_device.devclass() == DEVICE_CLASS_JOYSTICK && modifier >= ITEM_MODIFIER_LEFT && modifier <= ITEM_MODIFIER_DOWN) + { + input_device_item *xaxis_item = m_device.item(ITEM_ID_XAXIS); + input_device_item *yaxis_item = m_device.item(ITEM_ID_YAXIS); + if (xaxis_item != nullptr && yaxis_item != nullptr) + { + // determine which item we didn't update, and update it + assert(this == xaxis_item || this == yaxis_item); + if (this == xaxis_item) + yaxis_item->update_value(); + else + xaxis_item->update_value(); + + // now map the X and Y axes to a 9x9 grid using the raw values + joystick_map &joymap = downcast<input_device_joystick &>(m_device).joymap(); + return (joymap.update(xaxis_item->current(), yaxis_item->current()) >> (modifier - ITEM_MODIFIER_LEFT)) & 1; + } + } + + // positive/negative: true if past the deadzone in either direction + if (modifier == ITEM_MODIFIER_POS || modifier == ITEM_MODIFIER_RIGHT || modifier == ITEM_MODIFIER_DOWN) + return (result > 0); + else if (modifier == ITEM_MODIFIER_NEG || modifier == ITEM_MODIFIER_LEFT || modifier == ITEM_MODIFIER_UP) + return (result < 0); + + // all other cases just return 0 + return 0; +} + + +//------------------------------------------------- +// read_as_relative - return the absolute input +// as a relative axis value +//------------------------------------------------- + +int32_t input_device_absolute_item::read_as_relative(input_item_modifier modifier) +{ + // no translation to relative + return 0; +} + + +//------------------------------------------------- +// read_as_absolute - return the absolute input +// as an absolute axis value, with appropriate +// tweaks +//------------------------------------------------- + +int32_t input_device_absolute_item::read_as_absolute(input_item_modifier modifier) +{ + // start with the current value + int32_t result = m_device.adjust_absolute(update_value()); + assert(result >= INPUT_ABSOLUTE_MIN && result <= INPUT_ABSOLUTE_MAX); + + // if we're doing a lightgun reload hack, override the value + if (m_device.devclass() == DEVICE_CLASS_LIGHTGUN && m_device.lightgun_reload_button()) + { + // if it is pressed, return (min,max) + input_device_item *button2_item = m_device.item(ITEM_ID_BUTTON2); + if (button2_item != nullptr && button2_item->update_value()) + result = (m_itemid == ITEM_ID_XAXIS) ? INPUT_ABSOLUTE_MIN : INPUT_ABSOLUTE_MAX; + } + + // positive/negative: scale to full axis + if (modifier == ITEM_MODIFIER_POS) + result = std::max(result, 0) * 2 + INPUT_ABSOLUTE_MIN; + if (modifier == ITEM_MODIFIER_NEG) + result = std::max(-result, 0) * 2 + INPUT_ABSOLUTE_MIN; + return result; +} |