summaryrefslogtreecommitdiffstatshomepage
path: root/src/frontend/mame/iptseqpoll.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/frontend/mame/iptseqpoll.cpp')
-rw-r--r--src/frontend/mame/iptseqpoll.cpp437
1 files changed, 356 insertions, 81 deletions
diff --git a/src/frontend/mame/iptseqpoll.cpp b/src/frontend/mame/iptseqpoll.cpp
index 8082b257e2f..145c64f033a 100644
--- a/src/frontend/mame/iptseqpoll.cpp
+++ b/src/frontend/mame/iptseqpoll.cpp
@@ -1,113 +1,299 @@
// license:BSD-3-Clause
-// copyright-holders:Vas Crabb,Aaron Giles
+// copyright-holders:Vas Crabb, Aaron Giles
#include "emu.h"
#include "iptseqpoll.h"
+#include "inputdev.h"
+
#include <cassert>
+#include <algorithm>
-input_sequence_poller::input_sequence_poller(input_manager &manager) noexcept :
- m_manager(manager),
- m_sequence(),
- m_class(ITEM_CLASS_INVALID),
- m_last_ticks(0),
- m_modified(false)
+input_code_poller::input_code_poller(input_manager &manager) noexcept :
+ m_manager(manager)
{
}
-void input_sequence_poller::start(input_item_class itemclass)
+input_code_poller::~input_code_poller()
{
- m_sequence.reset();
- do_start(itemclass);
}
-void input_sequence_poller::start(input_item_class itemclass, input_seq const &startseq)
+void input_code_poller::reset()
{
- // grab the starting sequence to append to, and append an OR if it isn't empty
- m_sequence = startseq;
- if (input_seq::end_code != m_sequence[0])
- m_sequence += input_seq::or_code;
+ // iterate over device classes and devices
+ for (input_device_class classno = DEVICE_CLASS_FIRST_VALID; DEVICE_CLASS_LAST_VALID >= classno; ++classno)
+ {
+ input_class &devclass(m_manager.device_class(classno));
+ for (int devnum = 0; devclass.maxindex() >= devnum; ++devnum)
+ {
+ // fetch the device; ignore if nullptr
+ input_device *const device(devclass.device(devnum));
+ if (device)
+ {
+ // iterate over items within each device
+ for (input_item_id itemid = ITEM_ID_FIRST_VALID; device->maxitem() >= itemid; ++itemid)
+ {
+ // for any non-switch items, set memory to the current value
+ input_device_item *const item(device->item(itemid));
+ if (item && (item->itemclass() != ITEM_CLASS_SWITCH))
+ item->set_memory(m_manager.code_value(item->code()));
+ }
+ }
+ }
+ }
+}
+
+
- do_start(itemclass);
+switch_code_poller_base::switch_code_poller_base(input_manager &manager) noexcept :
+ input_code_poller(manager),
+ m_switch_memory()
+{
}
-bool input_sequence_poller::poll()
+void switch_code_poller_base::reset()
{
- assert((ITEM_CLASS_SWITCH == m_class) || (ITEM_CLASS_ABSOLUTE == m_class) || (ITEM_CLASS_RELATIVE == m_class));
- int const curlen = m_sequence.length();
- input_code lastcode = m_sequence[curlen - 1];
+ m_switch_memory.clear();
+ input_code_poller::reset();
+}
+
+
+bool switch_code_poller_base::code_pressed_once(input_code code)
+{
+ // look for the code in the memory
+ bool const pressed(m_manager.code_pressed(code));
+ auto const found(std::lower_bound(m_switch_memory.begin(), m_switch_memory.end(), code));
+ if ((m_switch_memory.end() != found) && (*found == code))
+ {
+ // if no longer pressed, clear entry
+ if (!pressed)
+ m_switch_memory.erase(found);
+
+ // always return false
+ return false;
+ }
+
+ // if we get here, we were not previously pressed; if still not pressed, return false
+ if (!pressed)
+ return false;
+
+ // otherwise, add the code to the memory and return true
+ m_switch_memory.emplace(found, code);
+ return true;
+}
+
+
+
+axis_code_poller::axis_code_poller(input_manager &manager) noexcept :
+ input_code_poller(manager)
+{
+}
+
- input_code newcode;
- if (ITEM_CLASS_SWITCH == m_class)
+input_code axis_code_poller::poll()
+{
+ // iterate over device classes and devices, skipping disabled classes
+ for (input_device_class classno = DEVICE_CLASS_FIRST_VALID; DEVICE_CLASS_LAST_VALID >= classno; ++classno)
{
- // switch case: see if we have a new code to process
- newcode = m_manager.poll_switches();
- if (INPUT_CODE_INVALID != newcode)
+ input_class &devclass(m_manager.device_class(classno));
+ if (devclass.enabled())
{
- // if code is duplicate, toggle the NOT state on the code
- if (curlen && (newcode == lastcode))
+ for (int devnum = 0; devclass.maxindex() >= devnum; ++devnum)
{
- // back up over the existing code
- m_sequence.backspace();
-
- // if there was a NOT preceding it, delete it as well, otherwise append a fresh one
- if (m_sequence[curlen - 2] == input_seq::not_code)
- m_sequence.backspace();
- else
- m_sequence += input_seq::not_code;
+ // fetch the device; ignore if nullptr
+ input_device *const device(devclass.device(devnum));
+ if (device)
+ {
+ // iterate over items within each device
+ for (input_item_id itemid = ITEM_ID_FIRST_VALID; device->maxitem() >= itemid; ++itemid)
+ {
+ input_device_item *const item(device->item(itemid));
+ if (item && (item->itemclass() != ITEM_CLASS_SWITCH))
+ {
+ input_code const code = item->code();
+ if (item->check_axis(code.item_modifier()))
+ return code;
+ }
+ }
+ }
}
}
}
- else
+
+ // if nothing, return an invalid code
+ return INPUT_CODE_INVALID;
+}
+
+
+
+switch_code_poller::switch_code_poller(input_manager &manager) noexcept :
+ switch_code_poller_base(manager)
+{
+}
+
+
+input_code switch_code_poller::poll()
+{
+ // iterate over device classes and devices, skipping disabled classes
+ for (input_device_class classno = DEVICE_CLASS_FIRST_VALID; DEVICE_CLASS_LAST_VALID >= classno; ++classno)
{
- // absolute/relative case: see if we have an analog change of sufficient amount
- bool const has_or = input_seq::or_code == lastcode;
- if (has_or)
- lastcode = m_sequence[curlen - 2];
- newcode = m_manager.poll_axes();
-
- // if the last code doesn't match absolute/relative of this code, ignore the new one
- input_item_class const lastclass = lastcode.item_class();
- input_item_class const newclass = newcode.item_class();
- if (((ITEM_CLASS_ABSOLUTE == lastclass) && (ITEM_CLASS_ABSOLUTE != newclass)) ||
- ((ITEM_CLASS_RELATIVE == lastclass) && (ITEM_CLASS_RELATIVE != newclass)))
- newcode = INPUT_CODE_INVALID;
-
- // if the new code is valid, check for half-axis toggles on absolute controls
- if ((INPUT_CODE_INVALID != newcode) && curlen && (ITEM_CLASS_ABSOLUTE == newclass))
+ input_class &devclass(m_manager.device_class(classno));
+ if (devclass.enabled())
{
- input_code last_nomodifier = lastcode;
- last_nomodifier.set_item_modifier(ITEM_MODIFIER_NONE);
- if (newcode == last_nomodifier)
+ for (int devnum = 0; devclass.maxindex() >= devnum; ++devnum)
{
- // increment the modifier, wrapping back to none
- switch (lastcode.item_modifier())
+ // fetch the device; ignore if nullptr
+ input_device *const device(devclass.device(devnum));
+ if (device)
{
- case ITEM_MODIFIER_NONE:
- newcode.set_item_modifier(ITEM_MODIFIER_POS);
- break;
- case ITEM_MODIFIER_POS:
- newcode.set_item_modifier(ITEM_MODIFIER_NEG);
- break;
- default:
- case ITEM_MODIFIER_NEG:
- newcode.set_item_modifier(ITEM_MODIFIER_NONE);
- break;
+ // iterate over items within each device
+ for (input_item_id itemid = ITEM_ID_FIRST_VALID; device->maxitem() >= itemid; ++itemid)
+ {
+ input_device_item *const item(device->item(itemid));
+ if (item)
+ {
+ input_code code = item->code();
+ if (item->itemclass() == ITEM_CLASS_SWITCH)
+ {
+ // item is natively a switch, poll it
+ if (code_pressed_once(code))
+ return code;
+ }
+ else if (item->check_axis(code.item_modifier()))
+ {
+ // poll axes digitally
+ code.set_item_class(ITEM_CLASS_SWITCH);
+ if ((classno == DEVICE_CLASS_JOYSTICK) && (code.item_id() == ITEM_ID_XAXIS))
+ {
+ // joystick X axis - check with left/right modifiers
+ code.set_item_modifier(ITEM_MODIFIER_LEFT);
+ if (code_pressed_once(code))
+ return code;
+ code.set_item_modifier(ITEM_MODIFIER_RIGHT);
+ if (code_pressed_once(code))
+ return code;
+ }
+ else if ((classno == DEVICE_CLASS_JOYSTICK) && (code.item_id() == ITEM_ID_YAXIS))
+ {
+ // if this is a joystick Y axis, check with up/down modifiers
+ code.set_item_modifier(ITEM_MODIFIER_UP);
+ if (code_pressed_once(code))
+ return code;
+ code.set_item_modifier(ITEM_MODIFIER_DOWN);
+ if (code_pressed_once(code))
+ return code;
+ }
+ else
+ {
+ // any other axis, check with pos/neg modifiers
+ code.set_item_modifier(ITEM_MODIFIER_POS);
+ if (code_pressed_once(code))
+ return code;
+ code.set_item_modifier(ITEM_MODIFIER_NEG);
+ if (code_pressed_once(code))
+ return code;
+ }
+ }
+ }
+ }
}
+ }
+ }
+ }
- // back up over the previous code so we can re-append
- if (has_or)
- m_sequence.backspace();
- m_sequence.backspace();
+ // if nothing, return an invalid code
+ return INPUT_CODE_INVALID;
+}
+
+
+
+keyboard_code_poller::keyboard_code_poller(input_manager &manager) noexcept :
+ switch_code_poller_base(manager)
+{
+}
+
+
+input_code keyboard_code_poller::poll()
+{
+ // iterate over devices in keyboard class
+ input_class &devclass = m_manager.device_class(DEVICE_CLASS_KEYBOARD);
+ for (int devnum = 0; devclass.maxindex() >= devnum; ++devnum)
+ {
+ // fetch the device; ignore if nullptr
+ input_device *const device(devclass.device(devnum));
+ if (device)
+ {
+ // iterate over items within each device
+ for (input_item_id itemid = ITEM_ID_FIRST_VALID; itemid <= device->maxitem(); ++itemid)
+ {
+ // iterate over items within each device
+ for (input_item_id itemid = ITEM_ID_FIRST_VALID; device->maxitem() >= itemid; ++itemid)
+ {
+ input_device_item *const item = device->item(itemid);
+ if (item && (item->itemclass() == ITEM_CLASS_SWITCH))
+ {
+ input_code const code = item->code();
+ if (code_pressed_once(code))
+ return code;
+ }
+ }
}
}
}
+ // if nothing, return an invalid code
+ return INPUT_CODE_INVALID;
+}
+
+
+
+input_sequence_poller::input_sequence_poller() noexcept :
+ m_sequence(),
+ m_last_ticks(0),
+ m_modified(false)
+{
+}
+
+
+input_sequence_poller::~input_sequence_poller()
+{
+}
+
+
+void input_sequence_poller::start()
+{
+ // start with an empty sequence
+ m_sequence.reset();
+
+ // reset the recording count and the clock
+ m_last_ticks = 0;
+ m_modified = false;
+ do_start();
+}
+
+
+void input_sequence_poller::start(input_seq const &startseq)
+{
+ // grab the starting sequence to append to, and append an OR if it isn't empty
+ m_sequence = startseq;
+ if (input_seq::end_code != m_sequence[0])
+ m_sequence += input_seq::or_code;
+
+ // reset the recording count and the clock
+ m_last_ticks = 0;
+ m_modified = false;
+ do_start();
+}
+
+
+bool input_sequence_poller::poll()
+{
// if we got a new code to append it, append it and reset the timer
+ input_code const newcode = do_poll();
osd_ticks_t const newticks = osd_ticks();
if (INPUT_CODE_INVALID != newcode)
{
@@ -118,27 +304,116 @@ bool input_sequence_poller::poll()
// if we're recorded at least one item and 2/3 of a second has passed, we're done
if (m_last_ticks && ((m_last_ticks + (osd_ticks_per_second() * 2 / 3)) < newticks))
- {
- m_class = ITEM_CLASS_INVALID;
return true;
- }
// return false to indicate we are still polling
return false;
}
-void input_sequence_poller::do_start(input_item_class itemclass)
+
+axis_sequence_poller::axis_sequence_poller(input_manager &manager) noexcept :
+ input_sequence_poller(),
+ m_code_poller(manager)
{
- assert((ITEM_CLASS_SWITCH == itemclass) || (ITEM_CLASS_ABSOLUTE == itemclass) || (ITEM_CLASS_RELATIVE == itemclass));
+}
- // reset the recording count and the clock
- m_class = itemclass;
- m_last_ticks = 0;
- m_modified = false;
+void axis_sequence_poller::do_start()
+{
// wait for any inputs that are already active to be released
- m_manager.reset_polling();
+ m_code_poller.reset();
for (input_code dummycode = KEYCODE_ENTER; INPUT_CODE_INVALID != dummycode; )
- dummycode = (ITEM_CLASS_SWITCH == itemclass) ? m_manager.poll_switches() : m_manager.poll_axes();
+ dummycode = m_code_poller.poll();
+}
+
+
+input_code axis_sequence_poller::do_poll()
+{
+ // absolute/relative case: see if we have an analog change of sufficient amount
+ int const curlen = m_sequence.length();
+ input_code lastcode = m_sequence[curlen - 1];
+ bool const has_or = input_seq::or_code == lastcode;
+ if (has_or)
+ lastcode = m_sequence[curlen - 2];
+ input_code newcode = m_code_poller.poll();
+
+ // if the last code doesn't match absolute/relative of this code, ignore the new one
+ input_item_class const lastclass = lastcode.item_class();
+ input_item_class const newclass = newcode.item_class();
+ if (((ITEM_CLASS_ABSOLUTE == lastclass) && (ITEM_CLASS_ABSOLUTE != newclass)) ||
+ ((ITEM_CLASS_RELATIVE == lastclass) && (ITEM_CLASS_RELATIVE != newclass)))
+ newcode = INPUT_CODE_INVALID;
+
+ // if the new code is valid, check for half-axis toggles on absolute controls
+ if ((INPUT_CODE_INVALID != newcode) && curlen && (ITEM_CLASS_ABSOLUTE == newclass))
+ {
+ input_code last_nomodifier = lastcode;
+ last_nomodifier.set_item_modifier(ITEM_MODIFIER_NONE);
+ if (newcode == last_nomodifier)
+ {
+ // increment the modifier, wrapping back to none
+ switch (lastcode.item_modifier())
+ {
+ case ITEM_MODIFIER_NONE:
+ newcode.set_item_modifier(ITEM_MODIFIER_POS);
+ break;
+ case ITEM_MODIFIER_POS:
+ newcode.set_item_modifier(ITEM_MODIFIER_NEG);
+ break;
+ default:
+ case ITEM_MODIFIER_NEG:
+ newcode.set_item_modifier(ITEM_MODIFIER_NONE);
+ break;
+ }
+
+ // back up over the previous code so we can re-append
+ if (has_or)
+ m_sequence.backspace();
+ m_sequence.backspace();
+ }
+ }
+ return newcode;
+}
+
+
+
+switch_sequence_poller::switch_sequence_poller(input_manager &manager) noexcept :
+ input_sequence_poller(),
+ m_code_poller(manager)
+{
+}
+
+
+void switch_sequence_poller::do_start()
+{
+ // wait for any inputs that are already active to be released
+ m_code_poller.reset();
+ for (input_code dummycode = KEYCODE_ENTER; INPUT_CODE_INVALID != dummycode; )
+ dummycode = m_code_poller.poll();
+}
+
+
+input_code switch_sequence_poller::do_poll()
+{
+ // switch case: see if we have a new code to process
+ int const curlen = m_sequence.length();
+ input_code lastcode = m_sequence[curlen - 1];
+ input_code newcode = m_code_poller.poll();
+ if (INPUT_CODE_INVALID != newcode)
+ {
+ // if code is duplicate, toggle the NOT state on the code
+ if (curlen && (newcode == lastcode))
+ {
+ // back up over the existing code
+ m_sequence.backspace();
+
+ // if there was a NOT preceding it, delete it as well, otherwise append a fresh one
+ if (m_sequence[curlen - 2] == input_seq::not_code)
+ m_sequence.backspace();
+ else
+ m_sequence += input_seq::not_code;
+ }
+ }
+ return newcode;
}