summaryrefslogtreecommitdiffstatshomepage
path: root/src/frontend/mame/luaengine_input.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/frontend/mame/luaengine_input.cpp')
-rw-r--r--src/frontend/mame/luaengine_input.cpp441
1 files changed, 441 insertions, 0 deletions
diff --git a/src/frontend/mame/luaengine_input.cpp b/src/frontend/mame/luaengine_input.cpp
new file mode 100644
index 00000000000..f954038b70f
--- /dev/null
+++ b/src/frontend/mame/luaengine_input.cpp
@@ -0,0 +1,441 @@
+// license:BSD-3-Clause
+// copyright-holders:Miodrag Milanovic,Luca Bruno
+/***************************************************************************
+
+ luaengine_input.cpp
+
+ Controls execution of the core MAME system.
+
+***************************************************************************/
+
+#include "emu.h"
+#include "luaengine.ipp"
+
+#include "inputdev.h"
+#include "natkeyboard.h"
+#include "render.h"
+#include "uiinput.h"
+
+
+//-------------------------------------------------
+// initialize_input - register input user types
+//-------------------------------------------------
+
+void lua_engine::initialize_input()
+{
+
+ static const enum_parser<input_seq_type, 3> s_seq_type_parser =
+ {
+ { "standard", SEQ_TYPE_STANDARD },
+ { "increment", SEQ_TYPE_INCREMENT },
+ { "decrement", SEQ_TYPE_DECREMENT },
+ };
+
+
+/* ioport_manager library
+ *
+ * manager:machine():ioport()
+ *
+ * ioport:count_players() - get count of player controllers
+ * ioport:type_group(type, player)
+ * ioport:type_seq(type, player, seqtype) - get input sequence for ioport type/player
+ *
+ * ioport.ports[] - ioports table (k=tag, v=ioport_port)
+ */
+
+ auto ioport_manager_type = sol().registry().new_usertype<ioport_manager>("ioport", "new", sol::no_constructor);
+ ioport_manager_type.set("count_players", &ioport_manager::count_players);
+ ioport_manager_type.set("natkeyboard", &ioport_manager::natkeyboard);
+ ioport_manager_type.set("type_group", [](ioport_manager &im, ioport_type type, int player) {
+ return im.type_group(type, player);
+ });
+ ioport_manager_type.set("ports", sol::property([this](ioport_manager &im) {
+ sol::table port_table = sol().create_table();
+ for (auto &port : im.ports())
+ port_table[port.second->tag()] = port.second.get();
+ return port_table;
+ }));
+ ioport_manager_type.set("type_seq", [](ioport_manager &m, ioport_type type, int player, input_seq_type seqtype) {
+ return m.type_seq(type, player, seqtype);
+ });
+
+
+/* natural_keyboard library
+ *
+ * manager:machine():ioport():natkeyboard()
+ *
+ * natkeyboard:paste() - paste clipboard data
+ * natkeyboard:post() - post data to natural keyboard
+ * natkeyboard:post_coded() - post data to natural keyboard
+ *
+ * natkeyboard.empty - is the natural keyboard buffer empty?
+ * natkeyboard.in_use - is the natural keyboard in use?
+ */
+
+ auto natkeyboard_type = sol().registry().new_usertype<natural_keyboard>("natkeyboard", "new", sol::no_constructor);
+ natkeyboard_type.set("empty", sol::property(&natural_keyboard::empty));
+ natkeyboard_type.set("in_use", sol::property(&natural_keyboard::in_use, &natural_keyboard::set_in_use));
+ natkeyboard_type.set("paste", &natural_keyboard::paste);
+ natkeyboard_type.set("post", [](natural_keyboard &nat, const std::string &text) { nat.post_utf8(text); });
+ natkeyboard_type.set("post_coded", [](natural_keyboard &nat, const std::string &text) { nat.post_coded(text); });
+
+
+/* ioport_port library
+ *
+ * manager:machine():ioport().ports[port_tag]
+ *
+ * port:tag() - get port tag
+ * port:active() - get port status
+ * port:live() - get port ioport_port_live (TODO: not usable from lua as of now)
+ * port:read() - get port value
+ * port:write(val, mask) - set port to value & mask (output fields only, for other fields use field:set_value(val))
+ * port:field(mask) - get ioport_field for port and mask
+ *
+ * port.fields[] - get ioport_field table (k=name, v=ioport_field)
+ */
+
+ auto ioport_port_type = sol().registry().new_usertype<ioport_port>("ioport_port", "new", sol::no_constructor);
+ ioport_port_type.set("tag", &ioport_port::tag);
+ ioport_port_type.set("active", &ioport_port::active);
+ ioport_port_type.set("live", &ioport_port::live);
+ ioport_port_type.set("read", &ioport_port::read);
+ ioport_port_type.set("write", &ioport_port::write);
+ ioport_port_type.set("field", &ioport_port::field);
+ ioport_port_type.set("fields", sol::property([this](ioport_port &p){
+ sol::table f_table = sol().create_table();
+ // parse twice for custom and default names, default has priority
+ for(ioport_field &field : p.fields())
+ {
+ if (field.type_class() != INPUT_CLASS_INTERNAL)
+ f_table[field.name()] = &field;
+ }
+ for(ioport_field &field : p.fields())
+ {
+ if (field.type_class() != INPUT_CLASS_INTERNAL)
+ {
+ if(field.specific_name())
+ f_table[field.specific_name()] = &field;
+ else
+ f_table[field.manager().type_name(field.type(), field.player())] = &field;
+ }
+ }
+ return f_table;
+ }));
+
+
+/* ioport_field library
+ *
+ * manager:machine():ioport().ports[port_tag].fields[field_name]
+ *
+ * field:set_value(value)
+ * field:set_input_seq(seq_type, seq)
+ * field:input_seq(seq_type)
+ * field:set_default_input_seq(seq_type, seq)
+ * field:default_input_seq(seq_type)
+ * field:keyboard_codes(which)
+ *
+ * field.device - get associated device_t
+ * field.port - get associated ioport_port
+ * field.live - get ioport_field_live
+ * field.name
+ * field.default_name
+ * field.player
+ * field.mask
+ * field.defvalue
+ * field.sensitivity
+ * field.way - amount of available directions
+ * field.type_class
+ * field.is_analog
+ * field.is_digital_joystick
+ * field.enabled
+ * field.optional
+ * field.cocktail
+ * field.toggle - whether field is a toggle
+ * field.rotated
+ * field.analog_reverse
+ * field.analog_reset
+ * field.analog_wraps
+ * field.analog_invert
+ * field.impulse
+ * field.type
+ * field.crosshair_scale
+ * field.crosshair_offset
+ * field.user_value
+ *
+ * field.settings[] - ioport_setting table (k=value, v=name)
+ */
+
+ auto ioport_field_type = sol().registry().new_usertype<ioport_field>("ioport_field", "new", sol::no_constructor);
+ ioport_field_type.set("set_value", &ioport_field::set_value);
+ ioport_field_type.set("set_input_seq", [](ioport_field &f, const std::string &seq_type_string, const input_seq &seq) {
+ input_seq_type seq_type = s_seq_type_parser(seq_type_string);
+ ioport_field::user_settings settings;
+ f.get_user_settings(settings);
+ settings.seq[seq_type] = seq;
+ f.set_user_settings(settings);
+ });
+ ioport_field_type.set("input_seq", [](ioport_field &f, const std::string &seq_type_string) {
+ input_seq_type seq_type = s_seq_type_parser(seq_type_string);
+ return f.seq(seq_type);
+ });
+ ioport_field_type.set("set_default_input_seq", [](ioport_field &f, const std::string &seq_type_string, const input_seq &seq) {
+ input_seq_type seq_type = s_seq_type_parser(seq_type_string);
+ f.set_defseq(seq_type, seq);
+ });
+ ioport_field_type.set("default_input_seq", [](ioport_field &f, const std::string &seq_type_string) {
+ input_seq_type seq_type = s_seq_type_parser(seq_type_string);
+ return f.defseq(seq_type);
+ });
+ ioport_field_type.set("keyboard_codes", [this](ioport_field &f, int which) {
+ sol::table result = sol().create_table();
+ int index = 1;
+ for (char32_t code : f.keyboard_codes(which))
+ result[index++] = code;
+ return result;
+ });
+ ioport_field_type.set("device", sol::property(&ioport_field::device));
+ ioport_field_type.set("port", sol::property(&ioport_field::port));
+ ioport_field_type.set("name", sol::property(&ioport_field::name));
+ ioport_field_type.set("default_name", sol::property([](ioport_field &f) {
+ return f.specific_name() ? f.specific_name() : f.manager().type_name(f.type(), f.player());
+ }));
+ ioport_field_type.set("player", sol::property(&ioport_field::player, &ioport_field::set_player));
+ ioport_field_type.set("mask", sol::property(&ioport_field::mask));
+ ioport_field_type.set("defvalue", sol::property(&ioport_field::defvalue));
+ ioport_field_type.set("sensitivity", sol::property(&ioport_field::sensitivity));
+ ioport_field_type.set("way", sol::property(&ioport_field::way));
+ ioport_field_type.set("type_class", sol::property([](ioport_field &f) {
+ switch (f.type_class())
+ {
+ case INPUT_CLASS_KEYBOARD: return "keyboard";
+ case INPUT_CLASS_CONTROLLER: return "controller";
+ case INPUT_CLASS_CONFIG: return "config";
+ case INPUT_CLASS_DIPSWITCH: return "dipswitch";
+ case INPUT_CLASS_MISC: return "misc";
+ default: break;
+ }
+ throw false;
+ }));
+ ioport_field_type.set("is_analog", sol::property(&ioport_field::is_analog));
+ ioport_field_type.set("is_digital_joystick", sol::property(&ioport_field::is_digital_joystick));
+ ioport_field_type.set("enabled", sol::property(&ioport_field::enabled));
+ ioport_field_type.set("optional", sol::property(&ioport_field::optional));
+ ioport_field_type.set("cocktail", sol::property(&ioport_field::cocktail));
+ ioport_field_type.set("toggle", sol::property(&ioport_field::toggle));
+ ioport_field_type.set("rotated", sol::property(&ioport_field::rotated));
+ ioport_field_type.set("analog_reverse", sol::property(&ioport_field::analog_reverse));
+ ioport_field_type.set("analog_reset", sol::property(&ioport_field::analog_reset));
+ ioport_field_type.set("analog_wraps", sol::property(&ioport_field::analog_wraps));
+ ioport_field_type.set("analog_invert", sol::property(&ioport_field::analog_invert));
+ ioport_field_type.set("impulse", sol::property(&ioport_field::impulse));
+ ioport_field_type.set("type", sol::property(&ioport_field::type));
+ ioport_field_type.set("live", sol::property(&ioport_field::live));
+ ioport_field_type.set("crosshair_scale", sol::property(&ioport_field::crosshair_scale, &ioport_field::set_crosshair_scale));
+ ioport_field_type.set("crosshair_offset", sol::property(&ioport_field::crosshair_offset, &ioport_field::set_crosshair_offset));
+ ioport_field_type.set("user_value", sol::property(
+ [](ioport_field &f) {
+ ioport_field::user_settings settings;
+ f.get_user_settings(settings);
+ return settings.value;
+ },
+ [](ioport_field &f, ioport_value val) {
+ ioport_field::user_settings settings;
+ f.get_user_settings(settings);
+ settings.value = val;
+ f.set_user_settings(settings);
+ }));
+ ioport_field_type.set("settings", sol::property([this](ioport_field &f) {
+ sol::table result = sol().create_table();
+ for (ioport_setting &setting : f.settings())
+ if (setting.enabled())
+ result[setting.value()] = setting.name();
+ return result;
+ }));
+
+
+/* ioport_field_live library
+ *
+ * manager:machine():ioport().ports[port_tag].fields[field_name].live
+ *
+ * live.name
+ */
+
+ sol().registry().new_usertype<ioport_field_live>("ioport_field_live", "new", sol::no_constructor,
+ "name", &ioport_field_live::name);
+
+
+/* input_manager library
+ *
+ * manager:machine():input()
+ *
+ * input:code_from_token(token) - get input_code for KEYCODE_* string token
+ * input:code_pressed(code) - get pressed state for input_code
+ * input:code_to_token(code) - get KEYCODE_* string token for code
+ * input:code_name(code) - get code friendly name
+ * input:seq_from_tokens(tokens) - get input_seq for multiple space separated KEYCODE_* string tokens
+ * input:seq_pressed(seq) - get pressed state for input_seq
+ * input:seq_to_tokens(seq) - get KEYCODE_* string tokens for seq
+ * input:seq_name(seq) - get seq friendly name
+ * input:seq_clean(seq) - clean the seq and remove invalid elements
+ * input:seq_poll_start(class, [opt] start_seq) - start polling for input_item_class passed as string
+ * (switch/abs[olute]/rel[ative]/max[imum])
+ * input:seq_poll() - poll once, returns true if input was fetched
+ * input:seq_poll_final() - get final input_seq
+ * input.device_classes - returns device classes
+ */
+
+ auto input_type = sol().registry().new_usertype<input_manager>("input", "new", sol::no_constructor);
+ input_type.set("code_from_token", [](input_manager &input, const char *token) { return input.code_from_token(token); });
+ input_type.set("code_pressed", [](input_manager &input, const input_code &code) { return input.code_pressed(code); });
+ input_type.set("code_to_token", [](input_manager &input, const input_code &code) { return input.code_to_token(code); });
+ input_type.set("code_name", [](input_manager &input, const input_code &code) { return input.code_name(code); });
+ input_type.set("seq_from_tokens", [](input_manager &input, const char *tokens) { input_seq seq; input.seq_from_tokens(seq, tokens); return seq; });
+ input_type.set("seq_pressed", [](input_manager &input, const input_seq &seq) { return input.seq_pressed(seq); });
+ input_type.set("seq_to_tokens", [](input_manager &input, const input_seq &seq) { return input.seq_to_tokens(seq); });
+ input_type.set("seq_name", [](input_manager &input, const input_seq &seq) { return input.seq_name(seq); });
+ input_type.set("seq_clean", [](input_manager &input, const input_seq &seq) { return input.seq_clean(seq); });
+ input_type.set("seq_poll_start", [this](input_manager &input, const char *cls_string, sol::object seq) {
+ if (!m_seq_poll)
+ m_seq_poll.reset(new input_sequence_poller(input));
+
+ input_item_class cls;
+ if (!strcmp(cls_string, "switch"))
+ cls = ITEM_CLASS_SWITCH;
+ else if (!strcmp(cls_string, "absolute") || !strcmp(cls_string, "abs"))
+ cls = ITEM_CLASS_ABSOLUTE;
+ else if (!strcmp(cls_string, "relative") || !strcmp(cls_string, "rel"))
+ cls = ITEM_CLASS_RELATIVE;
+ else if (!strcmp(cls_string, "maximum") || !strcmp(cls_string, "max"))
+ cls = ITEM_CLASS_MAXIMUM;
+ else
+ cls = ITEM_CLASS_INVALID;
+
+ if (seq.is<sol::user<input_seq>>())
+ m_seq_poll->start(cls, seq.as<sol::user<input_seq>>());
+ else
+ m_seq_poll->start(cls);
+ });
+ input_type.set("seq_poll", [this](input_manager &input) -> sol::object {
+ if (!m_seq_poll)
+ return sol::make_object(sol(), sol::lua_nil);
+ return sol::make_object(sol(), m_seq_poll->poll());
+ });
+ input_type.set("seq_poll_final", [this](input_manager &input) -> sol::object {
+ if (!m_seq_poll)
+ return sol::make_object(sol(), sol::lua_nil);
+ return sol::make_object(sol(), m_seq_poll->valid() ? m_seq_poll->sequence() : input_seq());
+ });
+ input_type.set("seq_poll_modified", [this](input_manager &input) -> sol::object {
+ if (!m_seq_poll)
+ return sol::make_object(sol(), sol::lua_nil);
+ return sol::make_object(sol(), m_seq_poll->modified());
+ });
+ input_type.set("seq_poll_valid", [this](input_manager &input) -> sol::object {
+ if (!m_seq_poll)
+ return sol::make_object(sol(), sol::lua_nil);
+ return sol::make_object(sol(), m_seq_poll->valid());
+ });
+ input_type.set("seq_poll_sequence", [this](input_manager &input) -> sol::object {
+ if (!m_seq_poll)
+ return sol::make_object(sol(), sol::lua_nil);
+ return sol::make_object(sol(), m_seq_poll->sequence());
+ });
+ input_type.set("device_classes", sol::property([this](input_manager &input) {
+ sol::table result = sol().create_table();
+ for (input_device_class devclass_id = DEVICE_CLASS_FIRST_VALID; devclass_id <= DEVICE_CLASS_LAST_VALID; devclass_id++)
+ {
+ input_class &devclass = input.device_class(devclass_id);
+ result[devclass.name()] = &devclass;
+ }
+ return result;
+ }));
+
+
+/* input_class library
+ *
+ * manager:machine():input().device_classes[devclass]
+ *
+ * devclass.name
+ * devclass.enabled
+ * devclass.multi
+ * devclass.devices[]
+ */
+
+ auto input_class_type = sol().registry().new_usertype<input_class>("input_class", "new", sol::no_constructor);
+ input_class_type.set("name", sol::property(&input_class::name));
+ input_class_type.set("enabled", sol::property(&input_class::enabled, &input_class::enable));
+ input_class_type.set("multi", sol::property(&input_class::multi, &input_class::set_multi));
+ input_class_type.set("devices", sol::property([this](input_class &devclass) {
+ sol::table result = sol().create_table();
+ int index = 1;
+ for (int devindex = 0; devindex <= devclass.maxindex(); devindex++)
+ {
+ input_device *dev = devclass.device(devindex);
+ if (dev)
+ result[index++] = dev;
+ }
+ return result;
+ }));
+
+
+/* input_device library
+ *
+ * manager:machine():input().device_classes[devclass].devices[index]
+ * device.name
+ * device.id
+ * device.devindex
+ * device.items[]
+ */
+
+ auto input_device_type = sol().registry().new_usertype<input_device>("input_device", "new", sol::no_constructor);
+ input_device_type.set("name", sol::property(&input_device::name));
+ input_device_type.set("id", sol::property(&input_device::id));
+ input_device_type.set("devindex", sol::property(&input_device::devindex));
+ input_device_type.set("items", sol::property([this](input_device &dev) {
+ sol::table result = sol().create_table();
+ for (input_item_id id = ITEM_ID_FIRST_VALID; id < dev.maxitem(); id++)
+ {
+ input_device_item *item = dev.item(id);
+ if (item)
+ result[id] = dev.item(id);
+ }
+ return result;
+ }));
+
+
+/* input_device_item library
+ *
+ * manager:machine():input().device_classes[devclass].devices[index].items[item_id]
+ * item.name
+ * item.token
+ * item:code()
+ */
+
+ auto input_device_item_type = sol().registry().new_usertype<input_device_item>("input_device_item", "new", sol::no_constructor);
+ input_device_item_type.set("name", sol::property(&input_device_item::name));
+ input_device_item_type.set("token", sol::property(&input_device_item::token));
+ input_device_item_type.set("code", [](input_device_item &item) {
+ return input_code(item.device().devclass(), item.device().devindex(), item.itemclass(), ITEM_MODIFIER_NONE, item.itemid());
+ });
+
+
+/* ui_input_manager library
+ *
+ * manager:machine():uiinput()
+ *
+ * uiinput:find_mouse() - return x, y, button state, ui render target
+ * uiinput:pressed(key) - get pressed state for ui key
+ * uiinput.presses_enabled - enable/disable ui key presses
+ */
+
+ auto uiinput_type = sol().registry().new_usertype<ui_input_manager>("uiinput", "new", sol::no_constructor);
+ uiinput_type.set("find_mouse", [](ui_input_manager &ui) {
+ int32_t x, y;
+ bool button;
+ render_target *rt = ui.find_mouse(&x, &y, &button);
+ return std::tuple<int32_t, int32_t, bool, render_target *>(x, y, button, rt);
+ });
+ uiinput_type.set("pressed", &ui_input_manager::pressed);
+ uiinput_type.set("presses_enabled", sol::property(&ui_input_manager::presses_enabled, &ui_input_manager::set_presses_enabled));
+
+}