summaryrefslogblamecommitdiffstatshomepage
path: root/src/frontend/mame/iptseqpoll.cpp
blob: 8082b257e2f606db292c36e3e0da2a969b384c67 (plain) (tree)















































































































































                                                                                                                             
// license:BSD-3-Clause
// copyright-holders:Vas Crabb,Aaron Giles

#include "emu.h"
#include "iptseqpoll.h"

#include <cassert>


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)
{
}


void input_sequence_poller::start(input_item_class itemclass)
{
	m_sequence.reset();
	do_start(itemclass);
}


void input_sequence_poller::start(input_item_class itemclass, 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;

	do_start(itemclass);
}


bool input_sequence_poller::poll()
{
	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];

	input_code newcode;
	if (ITEM_CLASS_SWITCH == m_class)
	{
		// switch case: see if we have a new code to process
		newcode = m_manager.poll_switches();
		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;
			}
		}
	}
	else
	{
		// 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_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();
			}
		}
	}

	// if we got a new code to append it, append it and reset the timer
	osd_ticks_t const newticks = osd_ticks();
	if (INPUT_CODE_INVALID != newcode)
	{
		m_sequence += newcode;
		m_last_ticks = newticks;
		m_modified = true;
	}

	// 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)
{
	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;

	// wait for any inputs that are already active to be released
	m_manager.reset_polling();
	for (input_code dummycode = KEYCODE_ENTER; INPUT_CODE_INVALID != dummycode; )
		dummycode = (ITEM_CLASS_SWITCH == itemclass) ? m_manager.poll_switches() : m_manager.poll_axes();
}