mirror of
https://github.com/holub/mame
synced 2025-06-14 00:25:38 +03:00

* move rarely-used output and pty interfaces out of emu.h * consolidate and de-duplicate forward declarations, also remove some obsolete ones * clean up more #include guard macros * scope down a few more things (nw) Everyone, please keep forward declarations for src/emu in src/emu/emufwd.h - this will make it far easier to keep them in sync with declarations than having them scattered through all the other files.
949 lines
30 KiB
C++
949 lines
30 KiB
C++
// license:BSD-3-Clause
|
|
// copyright-holders:Aaron Giles
|
|
/***************************************************************************
|
|
|
|
inputdev.cpp
|
|
|
|
Input devices, items and device classes.
|
|
|
|
***************************************************************************/
|
|
|
|
#include "emu.h"
|
|
#include "inputdev.h"
|
|
|
|
#include "emuopts.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 s32 read_as_switch(input_item_modifier modifier) override;
|
|
virtual s32 read_as_relative(input_item_modifier modifier) override;
|
|
virtual s32 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
|
|
s32 m_steadykey; // the live steadykey state
|
|
s32 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 s32 read_as_switch(input_item_modifier modifier) override;
|
|
virtual s32 read_as_relative(input_item_modifier modifier) override;
|
|
virtual s32 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 s32 read_as_switch(input_item_modifier modifier) override;
|
|
virtual s32 read_as_relative(input_item_modifier modifier) override;
|
|
virtual s32 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 u8 *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++)
|
|
{
|
|
u8 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);
|
|
u8 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 u8 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
|
|
//-------------------------------------------------
|
|
|
|
u8 joystick_map::update(s32 xaxisval, s32 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);
|
|
u8 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(s32(manager.machine().options().joystick_deadzone() * INPUT_ABSOLUTE_MAX)),
|
|
m_joystick_saturation(s32(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
|
|
//-------------------------------------------------
|
|
|
|
s32 input_device_joystick::adjust_absolute_value(s32 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 = s64(result - m_joystick_deadzone) * s64(INPUT_ABSOLUTE_MAX) / s64(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(&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
|
|
//-------------------------------------------------
|
|
|
|
s32 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
|
|
//-------------------------------------------------
|
|
|
|
s32 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
|
|
//-------------------------------------------------
|
|
|
|
s32 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()
|
|
{
|
|
s32 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
|
|
//-------------------------------------------------
|
|
|
|
s32 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
|
|
//-------------------------------------------------
|
|
|
|
s32 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
|
|
//-------------------------------------------------
|
|
|
|
s32 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
|
|
//-------------------------------------------------
|
|
|
|
s32 input_device_absolute_item::read_as_switch(input_item_modifier modifier)
|
|
{
|
|
// start with the current value
|
|
s32 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
|
|
//-------------------------------------------------
|
|
|
|
s32 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
|
|
//-------------------------------------------------
|
|
|
|
s32 input_device_absolute_item::read_as_absolute(input_item_modifier modifier)
|
|
{
|
|
// start with the current value
|
|
s32 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;
|
|
}
|