-emu/ioport.cpp: Fixed some default setting handling issues.

* Issues were unlikely to actually manifest unless you use controller
  configuration files to change specific system input defaults.

-src/emu/output.h: Added size accessor to multi-element output finder.

* std::size will work on the top rank of an outut finder now.  Sorry for
  hitting emu.h again so soon.

-lua: Exposed a couple more input related things.

* Exposed constructor and a few methods on input_seq required for
  scripts to properly clear assignments or restore default settings.
* Exposed ioport_manager::set_type_seq which is required to configure
  general input assignments properly.
* Removed unnecessary use of sol::overload in favour of optional
  parameters.
* Updated documentation and also fixed a few errors.

-docs: Added description for axis setting assignments.
This commit is contained in:
Vas Crabb 2021-11-04 03:11:29 +11:00
parent d29287e092
commit 13612bbe0f
7 changed files with 187 additions and 79 deletions

View File

@ -121,11 +121,11 @@ Properties
^^^^^^^^^^
t.is_zero (read-only)
Whether the value represents no elapsed time.
A Boolean indicating whether the value represents no elapsed time.
t.is_never (read-only)
Whether the value is greater than the maximum number of whole seconds that
can be represented (treated as an unreachable time in the future or
overflow).
A Boolean indicating whether the value is greater than the maximum number of
whole seconds that can be represented (treated as an unreachable time in the
future or overflow).
t.attoseconds (read-only)
The fraction seconds portion of the interval in attoseconds.
t.seconds (read-only)
@ -517,7 +517,8 @@ ui:set_aggressive_input_focus(enable)
On some platforms, this controls whether MAME should accept input focus in
more situations than when its windows have UI focus.
ui:get_general_input_setting(type, [player])
Gets a description of the configured input sequence for the specified input
Gets a description of the configured
:ref:`input sequence <luareference-input-iptseq>` for the specified input
type and player suitable for using in prompts. The input type is an
enumerated value. The player number is a zero-based index. If the player
number is not supplied, it is assumed to be zero.
@ -1660,14 +1661,21 @@ ioport:type_group(type, player)
This should be called with values obtained from I/O port fields to provide
canonical grouping in an input configuration UI.
ioport:type_seq(type, [player], [seqtype])
Get the configured input sequence for the specified input type, player
number and sequence type. The input type is an enumerated value. The
player number is a zero-based index. If the player number is not supplied,
it is assumed to be zero. If the sequence type is supplied, it must be
``"standard"``, ``"increment"`` or ``"decrement"``; if it is not supplied,
it is assumed to be ``"standard"``.
Get the configured :ref:`input sequence <luareference-input-iptseq>` for the
specified input type, player number and sequence type. The input type is an
enumerated value. The player number is a zero-based index. If the player
number is not supplied, it is assumed to be zero. If the sequence type is
supplied, it must be ``"standard"``, ``"increment"`` or ``"decrement"``; if
it is not supplied, it is assumed to be ``"standard"``.
This provides access to general input configuration.
ioport:set_type_seq(type, player, seqtype, seq)
Set the configured :ref:`input sequence <luareference-input-iptseq>` for the
specified input type, player number and sequence type. The input type is an
enumerated value. The player number is a zero-based index. The sequence
type must be ``"standard"``, ``"increment"`` or ``"decrement"``.
This allows general input configuration to be set.
ioport:token_to_input_type(string)
Returns the input type and player number for the specified input type token.
ioport:input_type_to_token(type, [player])
@ -1852,21 +1860,24 @@ field:set_value(value)
compared to zero to determine whether the field should be active; for
analog fields, the value must be right-aligned and in the correct range.
field:set_input_seq(seqtype, seq)
Set the input sequence for the specified sequence type. This is used to
configure per-machine input settings. The sequence type must be
``"standard"``, ``"increment"`` or ``"decrement"``.
Set the :ref:`input sequence <luareference-input-iptseq>` for the
specified sequence type. This is used to configure per-machine input
settings. The sequence type must be ``"standard"``, ``"increment"`` or
``"decrement"``.
field:input_seq(seq_type)
Get the configured input sequence for the specified sequence type. This
gets per-machine input settings. The sequence type must be ``"standard"``,
``"increment"`` or ``"decrement"``.
Get the configured :ref:`input sequence <luareference-input-iptseq>` for the
specified sequence type. This gets per-machine input assignments. The
sequence type must be ``"standard"``, ``"increment"`` or ``"decrement"``.
field:set_default_input_seq(seq_type, seq)
Set the default input sequence for the specified sequence type. This is
used to configure general input settings. The sequence type must be
``"standard"``, ``"increment"`` or ``"decrement"``.
Set the default :ref:`input sequence <luareference-input-iptseq>` for the
specified sequence type. This overrides the default input assignment for a
specific input. The sequence type must be ``"standard"``, ``"increment"``
or ``"decrement"``.
field:default_input_seq(seq_type)
Gets the default input sequence for the specified sequence type. This is
gets general input settings. The sequence type must be ``"standard"``,
``"increment"`` or ``"decrement"``.
Gets the default :ref:`input sequence <luareference-input-iptseq>` for the
specified sequence type. If the default assignment is not overridden, this
gets the general input assignment. The sequence type must be
``"standard"``, ``"increment"`` or ``"decrement"``.
field:keyboard_codes(shift)
Gets a table of characters corresponding to the field for the specified
shift state. The shift state is a bit mask of active shift keys.
@ -2009,18 +2020,20 @@ input:code_from_token(token)
Convert a token string to an input code. Returns the invalid input code if
the token is not valid or belongs to an input device that is not present.
input:seq_pressed(seq)
Returns a Boolen indicating whether the supplied input sequence is currently
pressed.
Returns a Boolean indicating whether the supplied
:ref:`input sequence <luareference-input-iptseq>` is currently pressed.
input:seq_clean(seq)
Remove invalid elements from the supplied input sequence. Returns the new,
cleaned input sequence.
Remove invalid elements from the supplied
:ref:`input sequence <luareference-input-iptseq>`. Returns the new, cleaned
input sequence.
input:seq_name(seq)
Get display text for an inptu sequence.
Get display text for an :ref:`input sequence <luareference-input-iptseq>`.
input:seq_to_tokens(seq)
Convert an input sequence to a token string. This should be used when
saving configuration.
Convert an :ref:`input sequence <luareference-input-iptseq>` to a token
string. This should be used when saving configuration.
input:seq_from_tokens(tokens)
Convert a token string to an input sequence. This should be used when
Convert a token string to an
:ref:`input sequence <luareference-input-iptseq>`. This should be used when
loading configuration.
input:axis_code_poller()
Returns an :ref:`input code poller <luareference-input-codepoll>` for
@ -2034,10 +2047,12 @@ input:keyboard_code_poller()
devices.
input:axis_sequence_poller()
Returns an :ref:`input sequence poller <luareference-input-seqpoll>` for
obtaining an input sequence for configuring an analog input.
obtaining an :ref:`input sequence <luareference-input-iptseq>` for
configuring an analog input.
input:axis_sequence_poller()
Returns an :ref:`input sequence poller <luareference-input-seqpoll>` for
obtaining an input sequence for configuring a digital input.
obtaining an :ref:`input sequence <luareference-input-iptseq>` for
configuring a digital input.
Properties
^^^^^^^^^^
@ -2112,14 +2127,60 @@ Properties
^^^^^^^^^^
poller.sequence (read-only)
The current input sequence. This is updated while polling. It is possible
for the sequence to become invalid.
The current :ref:`input sequence <luareference-input-iptseq>`. This is
updated while polling. It is possible for the sequence to become invalid.
poller.valid (read-only)
A Boolean indicating whether the current input sequence is valid.
poller.modified (read-only)
A Boolean indicating whether the sequence was changed by any user input
since starting polling.
.. _luareference-input-iptseq:
Input sequence
~~~~~~~~~~~~~~
Wraps MAMEs ``input_seq`` class, representing a combination of host inputs that
can be read or assigned to an emulated input. Input sequences can be
manipulated using :ref:`input manager <luareference-input-inputman>` methods.
Use an :ref:`input sequence poller <luareference-input-seqpoll>` to obtain an
input sequence from the user.
Instantiation
^^^^^^^^^^^^^
emu.input_seq()
Creates an empty input sequence.
emu.input_seq(seq)
Creates a copy of an existing input sequence.
Methods
^^^^^^^
seq:reset()
Clears the input sequence, removing all items.
seq:set_default()
Sets the input sequence to a single item containing the metavalue specifying
that the default setting should be used.
Properties
^^^^^^^^^^
seq.empty (read-only)
A Boolean indicating whether the input sequence is empty (contains no items,
indicating an unassigned input).
seq.length (read-only)
The number of items in the input sequence.
seq.is_valid (read-only)
A Boolean indicating whether the input sequence is a valid. To be valid, it
must contain at least one item, all items must be valid codes, all product
groups must contain at least one item that is not negated, and items
referring to absolute and relative axes must not be mixed within a product
group.
seq.is_default (read-only)
A Boolean indicating whether the input sequence specifies that the default
setting should be used.
.. _luareference-input-devclass:
Host input device class

View File

@ -267,6 +267,47 @@ axis of the left analog stick on your controller, you *should not* assign either
the **Steering Wheel Analog Inc** or **Steering Wheel Analog Dec** setting to
the X axis of the same analog stick.
You can assign one or more analog axes to the axis setting for an emulated
analog input. When multiple axes are assigned to an axis setting using **or**
operations, only the first axis that is not in the neutral position will take
effect. For example suppose for Atari Star Wars you assign the **AD Stick X
Analog** axis setting to **Joy 1 LSX or Joy 1 RSX** on an Xbox-style controller.
You will be able to control the emulated X axis using the X axis of the left
stick. If the left stick is in the neutral position (centred) on the X axis,
you will be able to control the emulated X axis using the X axis of the right
stick; however, if the left stick is *not* centred on the X axis, the X axis of
the right stick will be ignored.
MAME allows you to assign either the full range of an axis or the range on one
side of the neutral position (a *half axis*) to an axis setting. Assigning a
half axis is usually used for pedals or other absolute inputs where the neutral
position is at one end of the input range. For example suppose for **Ridge
Racer** you assign the **Brake Pedal Analog** setting to the portion of a
vertical joystick axis below the neutral position. If the joystick is at or
above the neutral position vertically, the brake pedal will be released; if the
joystick is below the neutral position vertically, the brake pedal will be
applied proportionally. Half axes are displayed as the name of the axis
followed by a plus or minus sign (**+** or **-**). Plus refers to the portion
of the axis below or to the right of the neutral position; minus refers to the
portion of the axis above or to the left of the neutral position. For pedal
or analog trigger controls, the active range is treated as being above the
neutral position (the half axis indicated by a minus sign).
When you select an axis setting, MAME will wait for you to enter an input:
* Move an analog control to assign it to the axis setting.
* When appending to a setting, move the last assigned analog control to cycle
between the full range of the axis and the portion of the axis on either side
of the neutral position.
* When appending to a setting, move an analog control other than the last
assigned control to add an **or** operation.
* Pressing **UI Cancel** (**Escape** by default) *before* activating an analog
axis input clears the setting or restores the default assignment.
* Pressing **UI Cancel** *after* activating analog axis input leaves the setting
unchanged.
* The new setting is shown below the menu. Wait one second after activating an
input to accept the new setting.
To adjust sensitivity, auto-centring speed and inversion settings for emulated
analog inputs, or to see how they respond to your settings, select **Analog
Controls** from the main menu during emulation. Settings for emulated analog
@ -285,8 +326,9 @@ Each emulated input has four settings on the **Analog Controls** menu:
increment/decrement settings.
* The *auto-centering speed* setting controls how fast the input value returns
to the neutral state when the controls assigned to the increment/decrement
settings are released.
* The **reverse** setting allows the direction of the emulated inputs response
settings are released. Setting it to zero (**0**) will result in the value
not automatically returning to the neutral position.
* The *reverse* setting allows the direction of the emulated inputs response
to controls to be inverted. This applies to controls assigned to the axis
setting *and* the increment/decrement settings.
* The *sensitivity* setting adjusts the input values response to the control

View File

@ -469,7 +469,7 @@ bool input_seq::is_valid() const noexcept
if (lastcode.internal())
return false;
// if this is the end, we're ok
// if this is the end, we're OK
if (code == end_code)
return true;

View File

@ -705,16 +705,12 @@ const char *ioport_field::name() const
const input_seq &ioport_field::seq(input_seq_type seqtype) const noexcept
{
// if no live state, return default
if (!m_live)
return defseq(seqtype);
// if the sequence is not the special default code, return it
if (m_live && !m_live->seq[seqtype].is_default())
return m_live->seq[seqtype];
// if the sequence is the special default code, return the expanded default value
if (m_live->seq[seqtype].is_default())
return manager().type_seq(m_type, m_player, seqtype);
// otherwise, return the sequence as-is
return m_live->seq[seqtype];
// otherwise return the default sequence
return defseq(seqtype);
}
@ -741,14 +737,8 @@ const input_seq &ioport_field::defseq(input_seq_type seqtype) const noexcept
void ioport_field::set_defseq(input_seq_type seqtype, const input_seq &newseq)
{
const bool was_changed = seq(seqtype) != defseq(seqtype);
// set the new sequence
m_seq[seqtype] = newseq;
// also update live state unless previously customized
if (m_live && !was_changed)
m_live->seq[seqtype] = newseq;
}

View File

@ -109,6 +109,7 @@ public:
auto &operator[](unsigned n) { return m_proxies[n]; }
auto &operator[](unsigned n) const { return m_proxies[n]; }
auto size() const { return std::size(m_proxies); }
auto begin() { return std::begin(m_proxies); }
auto end() { return std::end(m_proxies); }
auto begin() const { return std::begin(m_proxies); }

View File

@ -448,31 +448,26 @@ template <typename T, size_t SIZE>
class lua_engine::enum_parser
{
public:
constexpr enum_parser(std::initializer_list<std::pair<const char *, T>> values)
constexpr enum_parser(std::initializer_list<std::pair<std::string_view, T> > values)
{
if (values.size() != SIZE)
throw false && "size template argument incorrectly specified";
std::copy(values.begin(), values.end(), m_map.begin());
}
T operator()(const char *text) const
T operator()(std::string_view text) const
{
auto iter = std::find_if(
m_map.begin() + 1,
m_map.end(),
[text](const auto &x) { return !strcmp(text, x.first); });
m_map.begin() + 1,
m_map.end(),
[&text] (const auto &x) { return text == x.first; });
if (iter == m_map.end())
iter = m_map.begin();
return iter->second;
}
T operator()(const std::string &text) const
{
return (*this)(text.c_str());
}
private:
std::array<std::pair<const char *, T>, SIZE> m_map;
std::array<std::pair<std::string_view, T>, SIZE> m_map;
};

View File

@ -151,24 +151,32 @@ void lua_engine::initialize_input(sol::table &emu)
ioport_manager_type["type_group"] = sol::overload(
&ioport_manager::type_group,
[] (ioport_manager &im, ioport_type type) { return im.type_group(type, 0); });
ioport_manager_type["type_seq"] = sol::overload(
[] (ioport_manager &im, ioport_type type, int player, char const *seq_type_string)
ioport_manager_type["type_seq"] =
[] (ioport_manager &im, ioport_type type, std::optional<int> player, std::optional<char const *> seq_type_string)
{
input_seq_type seq_type = s_seq_type_parser(seq_type_string);
return im.type_seq(type, player, seq_type);
},
[] (ioport_manager &im, ioport_type type, int player) { return im.type_seq(type, player, SEQ_TYPE_STANDARD); },
[] (ioport_manager &im, ioport_type type) { return im.type_seq(type, 0, SEQ_TYPE_STANDARD); });
if (!player)
player = 0;
input_seq_type seq_type = seq_type_string ? s_seq_type_parser(*seq_type_string) : SEQ_TYPE_STANDARD;
return im.type_seq(type, *player, seq_type);
};
ioport_manager_type["set_type_seq"] =
[] (ioport_manager &im, ioport_type type, std::optional<int> player, std::optional<char const *> seq_type_string, input_seq const &seq)
{
if (!player)
player = 0;
input_seq_type seq_type = seq_type_string ? s_seq_type_parser(*seq_type_string) : SEQ_TYPE_STANDARD;
im.set_type_seq(type, *player, seq_type, seq);
};
ioport_manager_type["token_to_input_type"] =
[] (ioport_manager &im, std::string const &string)
{
int player;
ioport_type const type = im.token_to_input_type(string.c_str(), player);
return std::make_tuple(type, player);
};
[] (ioport_manager &im, std::string const &string)
{
int player;
ioport_type const type = im.token_to_input_type(string.c_str(), player);
return std::make_tuple(type, player);
};
ioport_manager_type["input_type_to_token"] = sol::overload(
&ioport_manager::input_type_to_token,
[] (ioport_manager &im, ioport_type type) { return im.input_type_to_token(type, 0); });
&ioport_manager::input_type_to_token,
[] (ioport_manager &im, ioport_type type) { return im.input_type_to_token(type, 0); });
ioport_manager_type["ports"] = sol::property([] (ioport_manager &im) { return tag_object_ptr_map<ioport_list>(im.ports()); });
@ -402,6 +410,17 @@ void lua_engine::initialize_input(sol::table &emu)
seqpoll_type["modified"] = sol::property(&input_sequence_poller::modified);
auto iptseq_type = emu.new_usertype<input_seq>(
"input_seq",
sol::call_constructor, sol::constructors<input_seq(), input_seq(input_seq const &)>());
iptseq_type["reset"] = &input_seq::reset;
iptseq_type["set_default"] = &input_seq::set_default;
iptseq_type["empty"] = sol::property(&input_seq::empty);
iptseq_type["length"] = sol::property(&input_seq::length);
iptseq_type["is_valid"] = sol::property(&input_seq::is_valid);
iptseq_type["is_default"] = sol::property(&input_seq::is_default);
auto input_class_type = sol().registry().new_usertype<input_class>("input_class", sol::no_constructor);
input_class_type["name"] = sol::property(&input_class::name);
input_class_type["enabled"] = sol::property(&input_class::enabled);