diff options
Diffstat (limited to 'src/osd/interface/inputseq.cpp')
-rw-r--r-- | src/osd/interface/inputseq.cpp | 210 |
1 files changed, 210 insertions, 0 deletions
diff --git a/src/osd/interface/inputseq.cpp b/src/osd/interface/inputseq.cpp new file mode 100644 index 00000000000..da1f2b98b26 --- /dev/null +++ b/src/osd/interface/inputseq.cpp @@ -0,0 +1,210 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles +/*************************************************************************** + + inputseq.cpp + + A combination of hosts inputs that can be assigned to a control. + +***************************************************************************/ + +#include "inputseq.h" + + +namespace osd { + +//************************************************************************** +// CONSTANTS +//************************************************************************** + +// additional expanded input codes for sequences +constexpr input_code input_seq::end_code; +constexpr input_code input_seq::default_code; +constexpr input_code input_seq::not_code; +constexpr input_code input_seq::or_code; + +// constant sequences +const input_seq input_seq::empty_seq; + + + +//************************************************************************** +// INPUT SEQ +//************************************************************************** + +//------------------------------------------------- +// operator+= - append a code to the end of an +// input sequence +//------------------------------------------------- + +input_seq &input_seq::operator+=(input_code code) noexcept +{ + // if not enough room, return false + const int curlength = length(); + if (curlength < m_code.size()) + { + m_code[curlength] = code; + if ((curlength + 1) < m_code.size()) + m_code[curlength + 1] = end_code; + } + return *this; +} + + +//------------------------------------------------- +// operator|= - append a code to a sequence; if +// the sequence is non-empty, insert an OR +// before the new code +//------------------------------------------------- + +input_seq &input_seq::operator|=(input_code code) noexcept +{ + // overwrite end/default with the new code + if (m_code[0] == default_code) + { + m_code[0] = code; + m_code[1] = end_code; + } + else + { + // otherwise, append an OR token and then the new code + const int curlength = length(); + if ((curlength + 1) < m_code.size()) + { + m_code[curlength] = or_code; + m_code[curlength + 1] = code; + if ((curlength + 2) < m_code.size()) + m_code[curlength + 2] = end_code; + } + } + return *this; +} + + +//------------------------------------------------- +// length - return the length of the sequence +//------------------------------------------------- + +int input_seq::length() const noexcept +{ + // find the end token; error if none found + for (int seqnum = 0; seqnum < m_code.size(); seqnum++) + if (m_code[seqnum] == end_code) + return seqnum; + return m_code.size(); +} + + +//------------------------------------------------- +// is_valid - return true if a given sequence is +// valid +//------------------------------------------------- + +bool input_seq::is_valid() const noexcept +{ + // "default" can only be of length 1 + if (m_code[0] == default_code) + return m_code[1] == end_code; + + // scan the sequence for valid codes + input_item_class lastclass = ITEM_CLASS_INVALID; + input_code lastcode = INPUT_CODE_INVALID; + decltype(m_code) positive_codes; + decltype(m_code) negative_codes; + auto positive_codes_end = positive_codes.begin(); + auto negative_codes_end = negative_codes.begin(); + for (input_code code : m_code) + { + // invalid codes are never permitted + if (code == INPUT_CODE_INVALID) + return false; + + // if we hit an OR or the end, validate the previous chunk + if (code == or_code || code == end_code) + { + // must be at least one positive code + if (positive_codes.begin() == positive_codes_end) + return false; + + // last code must not have been an internal code + if (lastcode.internal()) + return false; + + // if this is the end, we're ok + if (code == end_code) + return true; + + // reset the state for the next chunk + positive_codes_end = positive_codes.begin(); + negative_codes_end = negative_codes.begin(); + lastclass = ITEM_CLASS_INVALID; + } + else if (code == not_code) + { + // if we hit a NOT, make sure we don't have a double + if (lastcode == not_code) + return false; + } + else + { + // track positive codes, and don't allow positive and negative for the same code + if (lastcode != not_code) + { + *positive_codes_end++ = code; + if (std::find(negative_codes.begin(), negative_codes_end, code) != negative_codes_end) + return false; + } + else + { + *negative_codes_end++ = code; + if (std::find(positive_codes.begin(), positive_codes_end, code) != positive_codes_end) + return false; + } + + // non-switch items can't have a NOT + input_item_class itemclass = code.item_class(); + if (itemclass != ITEM_CLASS_SWITCH && lastcode == not_code) + return false; + + // absolute/relative items must all be the same class + if ((lastclass == ITEM_CLASS_ABSOLUTE && itemclass != ITEM_CLASS_ABSOLUTE) || + (lastclass == ITEM_CLASS_RELATIVE && itemclass != ITEM_CLASS_RELATIVE)) + return false; + } + + // remember the last code + lastcode = code; + } + + // if we got here, we were missing an END token; fail + return false; +} + + +//------------------------------------------------- +// backspace - "backspace" over the last entry in +// a sequence +//------------------------------------------------- + +void input_seq::backspace() noexcept +{ + // if we have at least one entry, remove it + const int curlength = length(); + if (curlength > 0) + m_code[curlength - 1] = end_code; +} + + +//------------------------------------------------- +// replace - replace all instances of oldcode +// with newcode in a sequence +//------------------------------------------------- + +void input_seq::replace(input_code oldcode, input_code newcode) noexcept +{ + for (input_code &elem : m_code) + if (elem == oldcode) + elem = newcode; +} + +} // namespace osd |