mirror of
https://github.com/holub/mame
synced 2025-04-18 22:49:58 +03:00
plugins: Reduced amnesia for autofire and inputmacro plugins.
Made autofire and inputmacro plugins capable of remembering settings if the host input device for the binding is missing or if an input for a slot device that isn't present is referenced.
This commit is contained in:
parent
f196989f8b
commit
de9ed12186
@ -71,9 +71,9 @@ local function populate_main_menu(buttons)
|
||||
local ioport = manager.machine.ioport
|
||||
local input = manager.machine.input
|
||||
local menu = {}
|
||||
menu[#menu + 1] = {_p('plugin-autofire', 'Autofire buttons'), '', 'off'}
|
||||
menu[#menu + 1] = {string.format(_p('plugin-autofire', 'Press %s to delete'), manager.ui:get_general_input_setting(ioport:token_to_input_type('UI_CLEAR'))), '', 'off'}
|
||||
menu[#menu + 1] = {'---', '', ''}
|
||||
table.insert(menu, {_p('plugin-autofire', 'Autofire buttons'), '', 'off'})
|
||||
table.insert(menu, {string.format(_p('plugin-autofire', 'Press %s to delete'), manager.ui:get_general_input_setting(ioport:token_to_input_type('UI_CLEAR'))), '', 'off'})
|
||||
table.insert(menu, {'---', '', ''})
|
||||
header_height = #menu
|
||||
|
||||
-- Use frame rate of first screen or 60Hz if no screens
|
||||
@ -88,21 +88,25 @@ local function populate_main_menu(buttons)
|
||||
-- Round rate to two decimal places
|
||||
local rate = freq / (button.on_frames + button.off_frames)
|
||||
rate = math.floor(rate * 100) / 100
|
||||
local text = string.format(_p('plugin-autofire', '%s [%g Hz]'), _p('input-name', button.button.name), rate)
|
||||
local subtext = input:seq_name(button.key)
|
||||
menu[#menu + 1] = {text, subtext, ''}
|
||||
local text
|
||||
if button.button then
|
||||
text = string.format(_p('plugin-autofire', '%s [%g Hz]'), _p('input-name', button.button.name), rate)
|
||||
else
|
||||
text = string.format(_p('plugin-autofire', 'n/a [%g Hz]'), rate)
|
||||
end
|
||||
table.insert(menu, {text, input:seq_name(button.key), ''})
|
||||
if index == initial_button then
|
||||
main_selection_save = #menu
|
||||
end
|
||||
end
|
||||
else
|
||||
menu[#menu + 1] = {_p('plugin-autofire', '[no autofire buttons]'), '', 'off'}
|
||||
table.insert(menu, {_p('plugin-autofire', '[no autofire buttons]'), '', 'off'})
|
||||
end
|
||||
initial_button = nil
|
||||
content_height = #menu
|
||||
|
||||
menu[#menu + 1] = {'---', '', ''}
|
||||
menu[#menu + 1] = {_p('plugin-autofire', 'Add autofire button'), '', ''}
|
||||
table.insert(menu, {'---', '', ''})
|
||||
table.insert(menu, {_p('plugin-autofire', 'Add autofire button'), '', ''})
|
||||
|
||||
local selection = main_selection_save
|
||||
main_selection_save = nil
|
||||
@ -139,15 +143,22 @@ end
|
||||
-- Add/edit menus (mostly identical)
|
||||
|
||||
local function populate_configure_menu(menu)
|
||||
local button_name = current_button.button and _p('input-name', current_button.button.name) or _p('plugin-autofire', '[not set]')
|
||||
local button_name
|
||||
if current_button.button then
|
||||
button_name = _p('input-name', current_button.button.name)
|
||||
elseif current_button.port then
|
||||
button_name = _p('plugin-autofire', 'n/a')
|
||||
else
|
||||
button_name = _p('plugin-autofire', '[not set]')
|
||||
end
|
||||
local key_name = current_button.key and manager.machine.input:seq_name(current_button.key) or _p('plugin-autofire', '[not set]')
|
||||
menu[#menu + 1] = {_p('plugin-autofire', 'Input'), button_name, ''}
|
||||
table.insert(menu, {_p('plugin-autofire', 'Input'), button_name, ''})
|
||||
if not (configure_menu_active or configure_selection_save) then
|
||||
configure_selection_save = #menu
|
||||
end
|
||||
menu[#menu + 1] = {_p('plugin-autofire', 'Hotkey'), key_name, hotkey_poller and 'lr' or ''}
|
||||
menu[#menu + 1] = {_p('plugin-autofire', 'On frames'), current_button.on_frames, current_button.on_frames > 1 and 'lr' or 'r'}
|
||||
menu[#menu + 1] = {_p('plugin-autofire', 'Off frames'), current_button.off_frames, current_button.off_frames > 1 and 'lr' or 'r'}
|
||||
table.insert(menu, {_p('plugin-autofire', 'Hotkey'), key_name, hotkey_poller and 'lr' or ''})
|
||||
table.insert(menu, {_p('plugin-autofire', 'On frames'), current_button.on_frames, current_button.on_frames > 1 and 'lr' or 'r'})
|
||||
table.insert(menu, {_p('plugin-autofire', 'Off frames'), current_button.off_frames, current_button.off_frames > 1 and 'lr' or 'r'})
|
||||
configure_menu_active = true
|
||||
end
|
||||
|
||||
@ -157,6 +168,7 @@ local function handle_configure_menu(index, event)
|
||||
if hotkey_poller:poll() then
|
||||
if hotkey_poller.sequence then
|
||||
current_button.key = hotkey_poller.sequence
|
||||
current_button.key_cfg = manager.machine.input:seq_to_tokens(hotkey_poller.sequence)
|
||||
end
|
||||
hotkey_poller = nil
|
||||
return true
|
||||
@ -215,15 +227,15 @@ end
|
||||
|
||||
local function populate_edit_menu()
|
||||
local menu = {}
|
||||
menu[#menu + 1] = {_p('plugin-autofire', 'Edit autofire button'), '', 'off'}
|
||||
menu[#menu + 1] = {'---', '', ''}
|
||||
table.insert(menu, {_p('plugin-autofire', 'Edit autofire button'), '', 'off'})
|
||||
table.insert(menu, {'---', '', ''})
|
||||
header_height = #menu
|
||||
|
||||
populate_configure_menu(menu)
|
||||
content_height = #menu
|
||||
|
||||
menu[#menu + 1] = {'---', '', ''}
|
||||
menu[#menu + 1] = {_p('plugin-autofire', 'Done'), '', ''}
|
||||
table.insert(menu, {'---', '', ''})
|
||||
table.insert(menu, {_p('plugin-autofire', 'Done'), '', ''})
|
||||
|
||||
local selection = configure_selection_save
|
||||
configure_selection_save = nil
|
||||
@ -248,18 +260,18 @@ end
|
||||
|
||||
local function populate_add_menu()
|
||||
local menu = {}
|
||||
menu[#menu + 1] = {_p('plugin-autofire', 'Add autofire button'), '', 'off'}
|
||||
menu[#menu + 1] = {'---', '', ''}
|
||||
table.insert(menu, {_p('plugin-autofire', 'Add autofire button'), '', 'off'})
|
||||
table.insert(menu, {'---', '', ''})
|
||||
header_height = #menu
|
||||
|
||||
populate_configure_menu(menu)
|
||||
content_height = #menu
|
||||
|
||||
menu[#menu + 1] = {'---', '', ''}
|
||||
table.insert(menu, {'---', '', ''})
|
||||
if is_button_complete(current_button) then
|
||||
menu[#menu + 1] = {_p('plugin-autofire', 'Create'), '', ''}
|
||||
table.insert(menu, {_p('plugin-autofire', 'Create'), '', ''})
|
||||
else
|
||||
menu[#menu + 1] = {_p('plugin-autofire', 'Cancel'), '', ''}
|
||||
table.insert(menu, {_p('plugin-autofire', 'Cancel'), '', ''})
|
||||
end
|
||||
|
||||
local selection = configure_selection_save
|
||||
|
@ -16,6 +16,7 @@ local function initialize_button(settings)
|
||||
mask = settings.mask,
|
||||
type = ioport:token_to_input_type(settings.type),
|
||||
key = manager.machine.input:seq_from_tokens(settings.key),
|
||||
key_cfg = settings.key,
|
||||
on_frames = settings.on_frames,
|
||||
off_frames = settings.off_frames,
|
||||
counter = 0
|
||||
@ -25,9 +26,9 @@ local function initialize_button(settings)
|
||||
local field = port:field(settings.mask)
|
||||
if field and (field.type == new_button.type) then
|
||||
new_button.button = field
|
||||
return new_button
|
||||
end
|
||||
end
|
||||
return new_button
|
||||
end
|
||||
return nil
|
||||
end
|
||||
@ -35,15 +36,15 @@ end
|
||||
local function serialize_settings(button_list)
|
||||
local settings = {}
|
||||
for index, button in ipairs(button_list) do
|
||||
setting = {
|
||||
local setting = {
|
||||
port = button.port,
|
||||
mask = button.button.mask,
|
||||
type = manager.machine.ioport:input_type_to_token(button.button.type),
|
||||
key = manager.machine.input:seq_to_tokens(button.key),
|
||||
mask = button.mask,
|
||||
type = manager.machine.ioport:input_type_to_token(button.type),
|
||||
key = button.key_cfg,
|
||||
on_frames = button.on_frames,
|
||||
off_frames = button.off_frames
|
||||
}
|
||||
settings[#settings + 1] = setting
|
||||
table.insert(settings, setting)
|
||||
end
|
||||
return settings
|
||||
end
|
||||
|
@ -16,6 +16,7 @@ function autofire.startplugin()
|
||||
-- 'mask' - mask of the button field being autofired
|
||||
-- 'type' - input type of the button being autofired
|
||||
-- 'key' - input_seq of the keybinding
|
||||
-- 'key_cfg' - configuration string for the keybinding
|
||||
-- 'on_frames' - number of frames button is pressed
|
||||
-- 'off_frames' - number of frames button is released
|
||||
-- 'button' - reference to ioport_field
|
||||
@ -43,10 +44,12 @@ function autofire.startplugin()
|
||||
local button_states = {}
|
||||
|
||||
for i, button in ipairs(buttons) do
|
||||
local key = button.port .. '\0' .. button.mask .. '.' .. button.type
|
||||
local state = button_states[key] or {0, button.button}
|
||||
state[1] = process_button(button) | state[1]
|
||||
button_states[key] = state
|
||||
if button.button then
|
||||
local key = button.port .. '\0' .. button.mask .. '.' .. button.type
|
||||
local state = button_states[key] or {0, button.button}
|
||||
state[1] = process_button(button) | state[1]
|
||||
button_states[key] = state
|
||||
end
|
||||
end
|
||||
for i, state in pairs(button_states) do
|
||||
state[2]:set_value(state[1])
|
||||
|
@ -662,7 +662,7 @@ function cheat.startplugin()
|
||||
menu[num][3] = "off"
|
||||
elseif cheat.is_oneshot then
|
||||
menu[num][2] = _("Set")
|
||||
menu[num][3] = ""
|
||||
menu[num][3] = ""
|
||||
else
|
||||
if cheat.enabled then
|
||||
menu[num][2] = _("On")
|
||||
|
@ -360,7 +360,7 @@ function cheatfind.startplugin()
|
||||
|
||||
local function menu_lim(val, min, max, menuitem)
|
||||
if min == max then
|
||||
menuitem[3] = "on"
|
||||
menuitem[3] = "on"
|
||||
elseif val == min then
|
||||
menuitem[3] = "r"
|
||||
elseif val == max then
|
||||
|
@ -15,11 +15,14 @@ function inputmacro.startplugin()
|
||||
Configuration data:
|
||||
* name: display name (string)
|
||||
* binding: activation sequence (input sequence)
|
||||
* bindingcfg: activation sequence configuration (string)
|
||||
* earlycancel: cancel or complete on release (Boolean)
|
||||
* loop: -1 = release, 0 = prolong, >0 = loop to step on hold (int)
|
||||
* loop: -1 = release, 0 = prolong, >0 = loop to step on hold (integer)
|
||||
* steps:
|
||||
* inputs:
|
||||
* port: port (I/O port)
|
||||
* port: port tag (string)
|
||||
* mask: port field mask (integer)
|
||||
* type: port field type (integer)
|
||||
* field: field (I/O port field)
|
||||
* delay: delay before activating inputs in frames (integer)
|
||||
* duration: duration to activate inputs for (integer)
|
||||
@ -35,7 +38,9 @@ function inputmacro.startplugin()
|
||||
|
||||
local function activate_inputs(inputs)
|
||||
for index, input in ipairs(inputs) do
|
||||
active_inputs[string.format('%s.%d.%d', input.port.tag, input.field.mask, input.field.type)] = input.field
|
||||
if input.field then
|
||||
active_inputs[string.format('%s.%d.%d', input.port, input.mask, input.type)] = input.field
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -37,6 +37,7 @@ local function new_macro()
|
||||
return {
|
||||
name = name,
|
||||
binding = nil,
|
||||
bindingcfg = '',
|
||||
earlycancel = true,
|
||||
loop = -1,
|
||||
steps = {
|
||||
@ -44,6 +45,8 @@ local function new_macro()
|
||||
inputs = {
|
||||
{
|
||||
port = nil,
|
||||
mask = nil,
|
||||
type = nil,
|
||||
field = nil } },
|
||||
delay = 0,
|
||||
duration = 1 } } }
|
||||
@ -83,11 +86,11 @@ function start_input_menu(handler, start_field)
|
||||
table.insert(menu_stack, MENU_TYPES.INPUT)
|
||||
end
|
||||
|
||||
function handle_input(index, action)
|
||||
local function handle_input(index, action)
|
||||
return input_menu:handle(index, action)
|
||||
end
|
||||
|
||||
function populate_input()
|
||||
local function populate_input()
|
||||
return input_menu:populate(input_start_field)
|
||||
end
|
||||
|
||||
@ -120,6 +123,7 @@ local function handle_edit_items(index, event)
|
||||
if edit_switch_poller:poll() then
|
||||
if edit_switch_poller.sequence then
|
||||
edit_current_macro.binding = edit_switch_poller.sequence
|
||||
edit_current_macro.bindingcfg = manager.machine.input:seq_to_tokens(edit_switch_poller.sequence)
|
||||
end
|
||||
edit_switch_poller = nil
|
||||
return true
|
||||
@ -233,11 +237,12 @@ local function handle_edit_items(index, event)
|
||||
elseif command.action == 'input' then
|
||||
local inputs = edit_current_macro.steps[command.step].inputs
|
||||
if event == 'select' then
|
||||
local hanlder =
|
||||
function(field)
|
||||
inputs[command.input].port = field.port
|
||||
inputs[command.input].field = field
|
||||
end
|
||||
local function hanlder(field)
|
||||
inputs[command.input].port = field.port.tag
|
||||
inputs[command.input].mask = field.mask
|
||||
inputs[command.input].type = field.type
|
||||
inputs[command.input].field = field
|
||||
end
|
||||
start_input_menu(hanlder, inputs[command.input].field)
|
||||
edit_start_selection = index
|
||||
return true
|
||||
@ -250,12 +255,14 @@ local function handle_edit_items(index, event)
|
||||
elseif command.action == 'addinput' then
|
||||
if event == 'select' then
|
||||
local inputs = edit_current_macro.steps[command.step].inputs
|
||||
local handler =
|
||||
function(field)
|
||||
inputs[#inputs + 1] = {
|
||||
port = field.port,
|
||||
field = field }
|
||||
end
|
||||
local function handler(field)
|
||||
local newinput = {
|
||||
port = field.port.tag,
|
||||
mask = field.mask,
|
||||
type = field.type,
|
||||
field = field }
|
||||
table.insert(inputs, newinput)
|
||||
end
|
||||
start_input_menu(handler)
|
||||
edit_start_selection = index
|
||||
return true
|
||||
@ -280,22 +287,23 @@ local function handle_edit_items(index, event)
|
||||
elseif command.action == 'addstep' then
|
||||
if event == 'select' then
|
||||
local steps = edit_current_macro.steps
|
||||
local handler =
|
||||
function(field)
|
||||
local newstep = {
|
||||
inputs = {
|
||||
{
|
||||
port = field.port,
|
||||
field = field } },
|
||||
delay = 0,
|
||||
duration = 1 }
|
||||
table.insert(steps, edit_insert_position, newstep)
|
||||
if edit_current_macro.loop >= edit_insert_position then
|
||||
edit_current_macro.loop = edit_current_macro.loop + 1
|
||||
end
|
||||
edit_start_step = edit_insert_position
|
||||
edit_insert_position = edit_insert_position + 1
|
||||
local function handler(field)
|
||||
local newstep = {
|
||||
inputs = {
|
||||
{
|
||||
port = field.port.tag,
|
||||
mask = field.mask,
|
||||
type = field.type,
|
||||
field = field } },
|
||||
delay = 0,
|
||||
duration = 1 }
|
||||
table.insert(steps, edit_insert_position, newstep)
|
||||
if edit_current_macro.loop >= edit_insert_position then
|
||||
edit_current_macro.loop = edit_current_macro.loop + 1
|
||||
end
|
||||
edit_start_step = edit_insert_position
|
||||
edit_insert_position = edit_insert_position + 1
|
||||
end
|
||||
start_input_menu(handler)
|
||||
edit_start_selection = index
|
||||
return true
|
||||
@ -383,7 +391,14 @@ local function add_edit_items(items)
|
||||
edit_items[#items] = { action = 'duration', step = i }
|
||||
|
||||
for j, input in ipairs(step.inputs) do
|
||||
local inputname = input.field and _p('input-name', input.field.name) or _p('plugin-inputmacro', '[not set]')
|
||||
local inputname
|
||||
if input.field then
|
||||
inputname = _p('input-name', input.field.name)
|
||||
elseif input.port then
|
||||
inputname = _p('plugin-inputmacro', 'n/a')
|
||||
else
|
||||
inputname = _p('plugin-inputmacro', '[not set]')
|
||||
end
|
||||
items[#items + 1] = { string.format(_p('plugin-inputmacro', 'Input %d'), j), inputname, '' }
|
||||
edit_items[#items] = { action = 'input', step = i, input = j }
|
||||
end
|
||||
@ -456,16 +471,16 @@ end
|
||||
local function populate_add()
|
||||
local items = { }
|
||||
|
||||
items[#items + 1] = { _p('plugin-inputmacro', 'Add Input Macro'), '', 'off' }
|
||||
items[#items + 1] = { '---', '', '' }
|
||||
table.insert(items, { _p('plugin-inputmacro', 'Add Input Macro'), '', 'off' })
|
||||
table.insert(items, { '---', '', '' })
|
||||
|
||||
add_edit_items(items)
|
||||
|
||||
items[#items + 1] = { '---', '', '' }
|
||||
table.insert(items, { '---', '', '' })
|
||||
if current_macro_complete() then
|
||||
items[#items + 1] = { _p('plugin-inputmacro', 'Create'), '', '' }
|
||||
table.insert(items, { _p('plugin-inputmacro', 'Create'), '', '' })
|
||||
else
|
||||
items[#items + 1] = { _p('plugin-inputmacro', 'Cancel'), '', '' }
|
||||
table.insert(items, { _p('plugin-inputmacro', 'Cancel'), '', '' })
|
||||
end
|
||||
edit_item_exit = #items
|
||||
|
||||
@ -481,13 +496,13 @@ end
|
||||
local function populate_edit()
|
||||
local items = { }
|
||||
|
||||
items[#items + 1] = { _p('plugin-inputmacro', 'Edit Input Macro'), '', 'off' }
|
||||
items[#items + 1] = { '---', '', '' }
|
||||
table.insert(items, { _p('plugin-inputmacro', 'Edit Input Macro'), '', 'off' })
|
||||
table.insert(items, { '---', '', '' })
|
||||
|
||||
add_edit_items(items)
|
||||
|
||||
items[#items + 1] = { '---', '', '' }
|
||||
items[#items + 1] = { _p('plugin-inputmacro', 'Done'), '', '' }
|
||||
table.insert(items, { '---', '', '' })
|
||||
table.insert(items, { _p('plugin-inputmacro', 'Done'), '', '' })
|
||||
edit_item_exit = #items
|
||||
|
||||
local selection = edit_start_selection
|
||||
@ -542,25 +557,25 @@ function populate_macros()
|
||||
local ioport = manager.machine.ioport
|
||||
local items = { }
|
||||
|
||||
items[#items + 1] = { _p('plugin-inputmacro', 'Input Macros'), '', 'off' }
|
||||
items[#items + 1] = { string.format(_p('plugin-inputmacro', 'Press %s to delete'), manager.ui:get_general_input_setting(ioport:token_to_input_type('UI_CLEAR'))), '', 'off' }
|
||||
items[#items + 1] = { '---', '', '' }
|
||||
table.insert(items, { _p('plugin-inputmacro', 'Input Macros'), '', 'off' })
|
||||
table.insert(items, { string.format(_p('plugin-inputmacro', 'Press %s to delete'), manager.ui:get_general_input_setting(ioport:token_to_input_type('UI_CLEAR'))), '', 'off' })
|
||||
table.insert(items, { '---', '', '' })
|
||||
|
||||
macros_item_first_macro = #items + 1
|
||||
if #macros > 0 then
|
||||
for index, macro in ipairs(macros) do
|
||||
items[#items + 1] = { macro.name, input:seq_name(macro.binding), '' }
|
||||
table.insert(items, { macro.name, input:seq_name(macro.binding), '' })
|
||||
if macros_start_macro == index then
|
||||
macros_selection_save = #items
|
||||
end
|
||||
end
|
||||
else
|
||||
items[#items + 1] = { _p('plugin-inputmacro', '[no macros]'), '', 'off' }
|
||||
table.insert(items, { _p('plugin-inputmacro', '[no macros]'), '', 'off' })
|
||||
end
|
||||
macros_start_macro = nil
|
||||
|
||||
items[#items + 1] = { '---', '', '' }
|
||||
items[#items + 1] = { _p('plugin-inputmacro', 'Add macro'), '', '' }
|
||||
table.insert(items, { '---', '', '' })
|
||||
table.insert(items, { _p('plugin-inputmacro', 'Add macro'), '', '' })
|
||||
macros_item_add = #items
|
||||
|
||||
local selection = macros_selection_save
|
||||
|
@ -20,6 +20,7 @@ local function make_macro(setting)
|
||||
local result = {
|
||||
name = setting.name,
|
||||
binding = manager.machine.input:seq_from_tokens(setting.binding),
|
||||
bindingcfg = setting.binding,
|
||||
earlycancel = setting.earlycancel,
|
||||
loop = setting.loop,
|
||||
steps = { } }
|
||||
@ -33,13 +34,18 @@ local function make_macro(setting)
|
||||
duration = step.duration }
|
||||
for j, input in ipairs(step.inputs) do
|
||||
if input.port and input.mask and input.type then
|
||||
local ipt = {
|
||||
port = input.port,
|
||||
mask = input.mask,
|
||||
type = ioport:token_to_input_type(input.type) }
|
||||
local port = ioport.ports[input.port]
|
||||
if port then
|
||||
local field = port:field(input.mask)
|
||||
if field and (field.type == ioport:token_to_input_type(input.type)) then
|
||||
table.insert(s.inputs, { port = port, field = field })
|
||||
if field and (field.type == ipt.type) then
|
||||
ipt.field = field
|
||||
end
|
||||
end
|
||||
table.insert(s.inputs, ipt)
|
||||
end
|
||||
end
|
||||
if #s.inputs > 0 then
|
||||
@ -66,7 +72,7 @@ local function make_settings(macros)
|
||||
for i, macro in ipairs(macros) do
|
||||
local m = {
|
||||
name = macro.name,
|
||||
binding = input:seq_to_tokens(macro.binding),
|
||||
binding = macro.bindingcfg,
|
||||
earlycancel = macro.earlycancel,
|
||||
loop = macro.loop,
|
||||
steps = { } }
|
||||
@ -79,9 +85,9 @@ local function make_settings(macros)
|
||||
table.insert(m.steps, s)
|
||||
for k, input in ipairs(step.inputs) do
|
||||
local b = {
|
||||
port = input.port.tag,
|
||||
mask = input.field.mask,
|
||||
type = ioport:input_type_to_token(input.field.type) }
|
||||
port = input.port,
|
||||
mask = input.mask,
|
||||
type = ioport:input_type_to_token(input.type) }
|
||||
table.insert(s.inputs, b)
|
||||
end
|
||||
end
|
||||
|
Loading…
Reference in New Issue
Block a user