mame/src/emu/ioport.h
Vas Crabb 4f495994c4 -ui: Made zoom controls a bit more intuitive.
* The UI controls are described as zoom in/out, but they had the
  opposite effect on the palette and tile viewers.  That has been
  changed to make them consistent with the tilemap viewer.
* Made the default zoom key not act as a toggle.  People are familiar
  with the function of Ctrl+0/=/- in web browsers, so making them behave
  similarly in MAME should make it more approachable.  Also added the
  default zoom key to the relevant documentation page.
* Implemented the default zoom key for the palette and tile viewers.
* In the tilemap viewer, if the view is in default expand to fit mode,
  zoom in/out starting from the actual zoom ratio.  Once again, this
  behaves more like the zoom controls in a web browser displaying an
  image so it should be more intuitive.
* Made more messages from the tilemap viewer localisable.

-util/zippath.cpp: Fixed MT08074.

* There were multiple issues at play here.  After #8443 was applied,
  is_root was simply never returning true on Windows, as OSD_WINDOWS
  isn't actually defined outside libosd and libocore.  This caused
  phantom parent items to appear in disk roots on Windows, but it meant
  that the check in zippath_resolve would always fail so the trailing
  backslash would be trimmed.  Fixing the macro test in is_root meant
  the trailing backslash from C:\ would no longer be trimmed, which
  caused the stat in zippath_resolve to fail.

-bigbord2.cpp: Hooked up floppy DRQ that had somehow got lost.

-Reduced tag map lookups in several drivers and devices.

-util/coretmpl.h: Removed an overload of bitswap that can be avoided
 using if constexpr.

-Added doxygen comments to some classes, and fixed several doxygen
 warnings.

-util, osd: Test for _WIN32 rather than WIN32.

* In C++17 mode, WIN32 is no longer a predefined macro, although various
  things in 3rdparty define it to maintain legacy support.  We're better
  off moving forward anyway for when WIN32 disappears entirely.  (WIN32
  is not a reserved name, while _WIN32 is, starting with an underscore
  follwed by an uppercase letter.)
2021-09-06 06:34:42 +10:00

1823 lines
63 KiB
C++

// license:BSD-3-Clause
// copyright-holders:Aaron Giles
/***************************************************************************
ioport.h
Input/output port handling.
***************************************************************************/
#pragma once
#ifndef __EMU_H__
#error Dont include this file directly; include emu.h instead.
#endif
#ifndef MAME_EMU_IOPORT_H
#define MAME_EMU_IOPORT_H
#include "ioprocs.h"
#include <array>
#include <cstdint>
#include <cstring>
#include <ctime>
#include <list>
#include <memory>
#include <vector>
//**************************************************************************
// CONSTANTS
//**************************************************************************
// input ports support up to 32 bits each
typedef u32 ioport_value;
// active high/low values for input ports
constexpr ioport_value IP_ACTIVE_HIGH = 0x00000000;
constexpr ioport_value IP_ACTIVE_LOW = 0xffffffff;
// maximum number of players supported
constexpr int MAX_PLAYERS = 10;
// unicode constants
constexpr char32_t UCHAR_PRIVATE = 0x100000;
constexpr char32_t UCHAR_SHIFT_1 = UCHAR_PRIVATE + 0;
constexpr char32_t UCHAR_SHIFT_2 = UCHAR_PRIVATE + 1;
constexpr char32_t UCHAR_SHIFT_BEGIN = UCHAR_SHIFT_1;
constexpr char32_t UCHAR_SHIFT_END = UCHAR_SHIFT_2;
constexpr char32_t UCHAR_MAMEKEY_BEGIN = UCHAR_PRIVATE + 2;
// sequence types for input_port_seq() call
enum input_seq_type
{
SEQ_TYPE_INVALID = -1,
SEQ_TYPE_STANDARD = 0,
SEQ_TYPE_INCREMENT,
SEQ_TYPE_DECREMENT,
SEQ_TYPE_TOTAL
};
DECLARE_ENUM_INCDEC_OPERATORS(input_seq_type)
// crosshair types
enum crosshair_axis_t
{
CROSSHAIR_AXIS_NONE = 0,
CROSSHAIR_AXIS_X,
CROSSHAIR_AXIS_Y
};
// groups for input ports
enum ioport_group
{
IPG_UI = 0,
IPG_PLAYER1,
IPG_PLAYER2,
IPG_PLAYER3,
IPG_PLAYER4,
IPG_PLAYER5,
IPG_PLAYER6,
IPG_PLAYER7,
IPG_PLAYER8,
IPG_PLAYER9,
IPG_PLAYER10,
IPG_OTHER,
IPG_TOTAL_GROUPS,
IPG_INVALID
};
// various input port types
enum ioport_type
{
// pseudo-port types
IPT_INVALID = 0,
IPT_UNUSED,
IPT_END,
IPT_UNKNOWN,
IPT_PORT,
IPT_DIPSWITCH,
IPT_CONFIG,
// start buttons
IPT_START1,
IPT_START2,
IPT_START3,
IPT_START4,
IPT_START5,
IPT_START6,
IPT_START7,
IPT_START8,
IPT_START9,
IPT_START10,
// coin slots
IPT_COIN1,
IPT_COIN2,
IPT_COIN3,
IPT_COIN4,
IPT_COIN5,
IPT_COIN6,
IPT_COIN7,
IPT_COIN8,
IPT_COIN9,
IPT_COIN10,
IPT_COIN11,
IPT_COIN12,
IPT_BILL1,
// service coin
IPT_SERVICE1,
IPT_SERVICE2,
IPT_SERVICE3,
IPT_SERVICE4,
// tilt inputs
IPT_TILT1,
IPT_TILT2,
IPT_TILT3,
IPT_TILT4,
// misc other digital inputs
IPT_POWER_ON,
IPT_POWER_OFF,
IPT_SERVICE,
IPT_TILT,
IPT_INTERLOCK,
IPT_MEMORY_RESET,
IPT_VOLUME_UP,
IPT_VOLUME_DOWN,
IPT_START, // use the numbered start button(s) for coin-ops
IPT_SELECT,
IPT_KEYPAD,
IPT_KEYBOARD,
// digital joystick inputs
IPT_DIGITAL_JOYSTICK_FIRST,
// use IPT_JOYSTICK for panels where the player has one single joystick
IPT_JOYSTICK_UP,
IPT_JOYSTICK_DOWN,
IPT_JOYSTICK_LEFT,
IPT_JOYSTICK_RIGHT,
// use IPT_JOYSTICKLEFT and IPT_JOYSTICKRIGHT for dual joystick panels
IPT_JOYSTICKRIGHT_UP,
IPT_JOYSTICKRIGHT_DOWN,
IPT_JOYSTICKRIGHT_LEFT,
IPT_JOYSTICKRIGHT_RIGHT,
IPT_JOYSTICKLEFT_UP,
IPT_JOYSTICKLEFT_DOWN,
IPT_JOYSTICKLEFT_LEFT,
IPT_JOYSTICKLEFT_RIGHT,
IPT_DIGITAL_JOYSTICK_LAST,
// action buttons
IPT_BUTTON1,
IPT_BUTTON2,
IPT_BUTTON3,
IPT_BUTTON4,
IPT_BUTTON5,
IPT_BUTTON6,
IPT_BUTTON7,
IPT_BUTTON8,
IPT_BUTTON9,
IPT_BUTTON10,
IPT_BUTTON11,
IPT_BUTTON12,
IPT_BUTTON13,
IPT_BUTTON14,
IPT_BUTTON15,
IPT_BUTTON16,
// mahjong inputs
IPT_MAHJONG_FIRST,
IPT_MAHJONG_A,
IPT_MAHJONG_B,
IPT_MAHJONG_C,
IPT_MAHJONG_D,
IPT_MAHJONG_E,
IPT_MAHJONG_F,
IPT_MAHJONG_G,
IPT_MAHJONG_H,
IPT_MAHJONG_I,
IPT_MAHJONG_J,
IPT_MAHJONG_K,
IPT_MAHJONG_L,
IPT_MAHJONG_M,
IPT_MAHJONG_N,
IPT_MAHJONG_O,
IPT_MAHJONG_P,
IPT_MAHJONG_Q,
IPT_MAHJONG_KAN,
IPT_MAHJONG_PON,
IPT_MAHJONG_CHI,
IPT_MAHJONG_REACH,
IPT_MAHJONG_RON,
IPT_MAHJONG_FLIP_FLOP,
IPT_MAHJONG_BET,
IPT_MAHJONG_SCORE,
IPT_MAHJONG_DOUBLE_UP,
IPT_MAHJONG_BIG,
IPT_MAHJONG_SMALL,
IPT_MAHJONG_LAST_CHANCE,
IPT_MAHJONG_LAST,
// hanafuda inputs
IPT_HANAFUDA_FIRST,
IPT_HANAFUDA_A,
IPT_HANAFUDA_B,
IPT_HANAFUDA_C,
IPT_HANAFUDA_D,
IPT_HANAFUDA_E,
IPT_HANAFUDA_F,
IPT_HANAFUDA_G,
IPT_HANAFUDA_H,
IPT_HANAFUDA_YES,
IPT_HANAFUDA_NO,
IPT_HANAFUDA_LAST,
// gambling inputs
IPT_GAMBLING_FIRST,
IPT_GAMBLE_KEYIN, // attendant
IPT_GAMBLE_KEYOUT, // attendant
IPT_GAMBLE_SERVICE, // attendant
IPT_GAMBLE_BOOK, // attendant
IPT_GAMBLE_DOOR, // attendant
// IPT_GAMBLE_DOOR2, // many gambling games have several doors.
// IPT_GAMBLE_DOOR3,
// IPT_GAMBLE_DOOR4,
// IPT_GAMBLE_DOOR5,
IPT_GAMBLE_PAYOUT, // player
IPT_GAMBLE_BET, // player
IPT_GAMBLE_DEAL, // player
IPT_GAMBLE_STAND, // player
IPT_GAMBLE_TAKE, // player
IPT_GAMBLE_D_UP, // player
IPT_GAMBLE_HALF, // player
IPT_GAMBLE_HIGH, // player
IPT_GAMBLE_LOW, // player
// poker-specific inputs
IPT_POKER_HOLD1,
IPT_POKER_HOLD2,
IPT_POKER_HOLD3,
IPT_POKER_HOLD4,
IPT_POKER_HOLD5,
IPT_POKER_CANCEL,
// slot-specific inputs
IPT_SLOT_STOP1,
IPT_SLOT_STOP2,
IPT_SLOT_STOP3,
IPT_SLOT_STOP4,
IPT_SLOT_STOP_ALL,
IPT_GAMBLING_LAST,
// analog inputs
IPT_ANALOG_FIRST,
IPT_ANALOG_ABSOLUTE_FIRST,
IPT_AD_STICK_X, // absolute // autocenter
IPT_AD_STICK_Y, // absolute // autocenter
IPT_AD_STICK_Z, // absolute // autocenter
IPT_PADDLE, // absolute // autocenter
IPT_PADDLE_V, // absolute // autocenter
IPT_PEDAL, // absolute // autocenter
IPT_PEDAL2, // absolute // autocenter
IPT_PEDAL3, // absolute // autocenter
IPT_LIGHTGUN_X, // absolute
IPT_LIGHTGUN_Y, // absolute
IPT_POSITIONAL, // absolute // autocenter if not wraps
IPT_POSITIONAL_V, // absolute // autocenter if not wraps
IPT_ANALOG_ABSOLUTE_LAST,
IPT_DIAL, // relative
IPT_DIAL_V, // relative
IPT_TRACKBALL_X, // relative
IPT_TRACKBALL_Y, // relative
IPT_MOUSE_X, // relative
IPT_MOUSE_Y, // relative
IPT_ANALOG_LAST,
// analog adjuster support
IPT_ADJUSTER,
// the following are special codes for user interface handling - not to be used by drivers!
IPT_UI_FIRST,
IPT_UI_CONFIGURE,
IPT_UI_ON_SCREEN_DISPLAY,
IPT_UI_DEBUG_BREAK,
IPT_UI_PAUSE,
IPT_UI_PAUSE_SINGLE,
IPT_UI_REWIND_SINGLE,
IPT_UI_RESET_MACHINE,
IPT_UI_SOFT_RESET,
IPT_UI_SHOW_GFX,
IPT_UI_FRAMESKIP_DEC,
IPT_UI_FRAMESKIP_INC,
IPT_UI_THROTTLE,
IPT_UI_FAST_FORWARD,
IPT_UI_SHOW_FPS,
IPT_UI_SNAPSHOT,
IPT_UI_TIMECODE,
IPT_UI_RECORD_MNG,
IPT_UI_RECORD_AVI,
IPT_UI_TOGGLE_CHEAT,
IPT_UI_UP,
IPT_UI_DOWN,
IPT_UI_LEFT,
IPT_UI_RIGHT,
IPT_UI_HOME,
IPT_UI_END,
IPT_UI_PAGE_UP,
IPT_UI_PAGE_DOWN,
IPT_UI_FOCUS_NEXT,
IPT_UI_FOCUS_PREV,
IPT_UI_SELECT,
IPT_UI_CANCEL,
IPT_UI_DISPLAY_COMMENT,
IPT_UI_CLEAR,
IPT_UI_ZOOM_IN,
IPT_UI_ZOOM_OUT,
IPT_UI_ZOOM_DEFAULT,
IPT_UI_PREV_GROUP,
IPT_UI_NEXT_GROUP,
IPT_UI_ROTATE,
IPT_UI_SHOW_PROFILER,
IPT_UI_TOGGLE_UI,
IPT_UI_RELEASE_POINTER,
IPT_UI_TOGGLE_DEBUG,
IPT_UI_PASTE,
IPT_UI_SAVE_STATE,
IPT_UI_LOAD_STATE,
IPT_UI_TAPE_START,
IPT_UI_TAPE_STOP,
IPT_UI_DATS,
IPT_UI_FAVORITES,
IPT_UI_EXPORT,
IPT_UI_AUDIT_FAST,
IPT_UI_AUDIT_ALL,
// additional OSD-specified UI port types (up to 16)
IPT_OSD_1,
IPT_OSD_2,
IPT_OSD_3,
IPT_OSD_4,
IPT_OSD_5,
IPT_OSD_6,
IPT_OSD_7,
IPT_OSD_8,
IPT_OSD_9,
IPT_OSD_10,
IPT_OSD_11,
IPT_OSD_12,
IPT_OSD_13,
IPT_OSD_14,
IPT_OSD_15,
IPT_OSD_16,
IPT_UI_LAST,
IPT_OTHER, // not mapped to standard defaults
IPT_SPECIAL, // uninterpreted characters
IPT_CUSTOM, // handled by custom code
IPT_OUTPUT,
IPT_COUNT
};
DECLARE_ENUM_INCDEC_OPERATORS(ioport_type)
// aliases for some types
#define IPT_PADDLE_H IPT_PADDLE
#define IPT_PEDAL1 IPT_PEDAL
#define IPT_POSITIONAL_H IPT_POSITIONAL
#define IPT_DIAL_H IPT_DIAL
// input type classes
enum ioport_type_class
{
INPUT_CLASS_INTERNAL,
INPUT_CLASS_KEYBOARD,
INPUT_CLASS_CONTROLLER,
INPUT_CLASS_CONFIG,
INPUT_CLASS_DIPSWITCH,
INPUT_CLASS_MISC
};
// default strings used in port definitions
enum
{
INPUT_STRING_Off = 1,
INPUT_STRING_On,
INPUT_STRING_No,
INPUT_STRING_Yes,
INPUT_STRING_Lives,
INPUT_STRING_Bonus_Life,
INPUT_STRING_Difficulty,
INPUT_STRING_Demo_Sounds,
INPUT_STRING_Coinage,
INPUT_STRING_Coin_A,
INPUT_STRING_Coin_B,
// INPUT_STRING_20C_1C, // 0.050000
// INPUT_STRING_15C_1C, // 0.066667
// INPUT_STRING_10C_1C, // 0.100000
#define __input_string_coinage_start INPUT_STRING_9C_1C
INPUT_STRING_9C_1C, // 0.111111
INPUT_STRING_8C_1C, // 0.125000
INPUT_STRING_7C_1C, // 0.142857
INPUT_STRING_6C_1C, // 0.166667
// INPUT_STRING_10C_2C, // 0.200000
INPUT_STRING_5C_1C, // 0.200000
// INPUT_STRING_9C_2C, // 0.222222
// INPUT_STRING_8C_2C, // 0.250000
INPUT_STRING_4C_1C, // 0.250000
// INPUT_STRING_7C_2C, // 0.285714
// INPUT_STRING_10C_3C, // 0.300000
// INPUT_STRING_9C_3C, // 0.333333
// INPUT_STRING_6C_2C, // 0.333333
INPUT_STRING_3C_1C, // 0.333333
INPUT_STRING_8C_3C, // 0.375000
// INPUT_STRING_10C_4C, // 0.400000
// INPUT_STRING_7C_3C, // 0.428571
// INPUT_STRING_9C_4C, // 0.444444
// INPUT_STRING_10C_5C, // 0.500000
// INPUT_STRING_8C_4C, // 0.500000
// INPUT_STRING_6C_3C, // 0.500000
INPUT_STRING_4C_2C, // 0.500000
INPUT_STRING_5C_2C, // 0.500000
INPUT_STRING_2C_1C, // 0.500000
// INPUT_STRING_9C_5C, // 0.555556
// INPUT_STRING_7C_4C, // 0.571429
// INPUT_STRING_10C_6C, // 0.600000
INPUT_STRING_5C_3C, // 0.600000
// INPUT_STRING_8C_5C, // 0.625000
// INPUT_STRING_9C_6C, // 0.666667
// INPUT_STRING_6C_4C, // 0.666667
INPUT_STRING_3C_2C, // 0.666667
// INPUT_STRING_10C_7C, // 0.700000
// INPUT_STRING_7C_5C, // 0.714286
// INPUT_STRING_8C_6C, // 0.750000
INPUT_STRING_4C_3C, // 0.750000
// INPUT_STRING_9C_7C, // 0.777778
// INPUT_STRING_10C_8C, // 0.800000
// INPUT_STRING_5C_4C, // 0.800000
// INPUT_STRING_6C_5C, // 0.833333
// INPUT_STRING_7C_6C, // 0.857143
// INPUT_STRING_8C_7C, // 0.875000
// INPUT_STRING_9C_8C, // 0.888889
// INPUT_STRING_10C_9C, // 0.900000
// INPUT_STRING_10C_10C, // 1.000000
// INPUT_STRING_9C_9C, // 1.000000
// INPUT_STRING_8C_8C, // 1.000000
// INPUT_STRING_7C_7C, // 1.000000
// INPUT_STRING_6C_6C, // 1.000000
// INPUT_STRING_5C_5C, // 1.000000
INPUT_STRING_4C_4C, // 1.000000
INPUT_STRING_3C_3C, // 1.000000
INPUT_STRING_2C_2C, // 1.000000
INPUT_STRING_1C_1C, // 1.000000
// INPUT_STRING_9C_10C, // 1.111111
// INPUT_STRING_8C_9C, // 1.125000
// INPUT_STRING_7C_8C, // 1.142857
// INPUT_STRING_6C_7C, // 1.166667
// INPUT_STRING_5C_6C, // 1.200000
// INPUT_STRING_8C_10C, // 1.250000
INPUT_STRING_3C_5C, // 1.250000
INPUT_STRING_4C_5C, // 1.250000
// INPUT_STRING_7C_9C, // 1.285714
// INPUT_STRING_6C_8C, // 1.333333
INPUT_STRING_3C_4C, // 1.333333
// INPUT_STRING_5C_7C, // 1.400000
// INPUT_STRING_7C_10C, // 1.428571
// INPUT_STRING_6C_9C, // 1.500000
// INPUT_STRING_4C_6C, // 1.500000
INPUT_STRING_2C_3C, // 1.500000
// INPUT_STRING_5C_8C, // 1.600000
// INPUT_STRING_6C_10C, // 1.666667
// INPUT_STRING_3C_5C, // 1.666667
INPUT_STRING_4C_7C, // 1.750000
// INPUT_STRING_5C_9C, // 1.800000
// INPUT_STRING_5C_10C, // 2.000000
// INPUT_STRING_4C_8C, // 2.000000
// INPUT_STRING_3C_6C, // 2.000000
INPUT_STRING_2C_4C, // 2.000000
INPUT_STRING_1C_2C, // 2.000000
// INPUT_STRING_4C_9C, // 2.250000
// INPUT_STRING_3C_7C, // 2.333333
// INPUT_STRING_4C_10C, // 2.500000
INPUT_STRING_2C_5C, // 2.500000
// INPUT_STRING_3C_8C, // 2.666667
// INPUT_STRING_3C_9C, // 3.000000
INPUT_STRING_2C_6C, // 3.000000
INPUT_STRING_1C_3C, // 3.000000
// INPUT_STRING_3C_10C, // 3.333333
INPUT_STRING_2C_7C, // 3.500000
INPUT_STRING_2C_8C, // 4.000000
INPUT_STRING_1C_4C, // 4.000000
// INPUT_STRING_2C_9C, // 4.500000
// INPUT_STRING_2C_10C, // 5.000000
INPUT_STRING_1C_5C, // 5.000000
INPUT_STRING_1C_6C, // 6.000000
INPUT_STRING_1C_7C, // 7.000000
INPUT_STRING_1C_8C, // 8.000000
INPUT_STRING_1C_9C, // 9.000000
#define __input_string_coinage_end INPUT_STRING_1C_9C
// INPUT_STRING_1C_10C, // 10.000000
// INPUT_STRING_1C_11C, // 11.000000
// INPUT_STRING_1C_12C, // 12.000000
// INPUT_STRING_1C_13C, // 13.000000
// INPUT_STRING_1C_14C, // 14.000000
// INPUT_STRING_1C_15C, // 15.000000
// INPUT_STRING_1C_20C, // 20.000000
// INPUT_STRING_1C_25C, // 25.000000
// INPUT_STRING_1C_30C, // 30.000000
// INPUT_STRING_1C_40C, // 40.000000
// INPUT_STRING_1C_50C, // 50.000000
// INPUT_STRING_1C_99C, // 99.000000
// INPUT_STRING_1C_100C, // 100.000000
// INPUT_STRING_1C_120C, // 120.000000
// INPUT_STRING_1C_125C, // 125.000000
// INPUT_STRING_1C_150C, // 150.000000
// INPUT_STRING_1C_200C, // 200.000000
// INPUT_STRING_1C_250C, // 250.000000
// INPUT_STRING_1C_500C, // 500.000000
// INPUT_STRING_1C_1000C, // 1000.000000
INPUT_STRING_Free_Play,
INPUT_STRING_Cabinet,
INPUT_STRING_Upright,
INPUT_STRING_Cocktail,
INPUT_STRING_Flip_Screen,
INPUT_STRING_Service_Mode,
INPUT_STRING_Pause,
INPUT_STRING_Test,
INPUT_STRING_Tilt,
INPUT_STRING_Version,
INPUT_STRING_Region,
INPUT_STRING_International,
INPUT_STRING_Japan,
INPUT_STRING_USA,
INPUT_STRING_Europe,
INPUT_STRING_Asia,
INPUT_STRING_China,
INPUT_STRING_Hong_Kong,
INPUT_STRING_Korea,
INPUT_STRING_Southeast_Asia,
INPUT_STRING_Taiwan,
INPUT_STRING_World,
INPUT_STRING_Language,
INPUT_STRING_English,
INPUT_STRING_Japanese,
INPUT_STRING_Chinese,
INPUT_STRING_French,
INPUT_STRING_German,
INPUT_STRING_Italian,
INPUT_STRING_Korean,
INPUT_STRING_Spanish,
INPUT_STRING_Very_Easy,
INPUT_STRING_Easiest,
INPUT_STRING_Easier,
INPUT_STRING_Easy,
INPUT_STRING_Medium_Easy,
INPUT_STRING_Normal,
INPUT_STRING_Medium,
INPUT_STRING_Medium_Hard,
INPUT_STRING_Hard,
INPUT_STRING_Harder,
INPUT_STRING_Hardest,
INPUT_STRING_Very_Hard,
INPUT_STRING_Medium_Difficult,
INPUT_STRING_Difficult,
INPUT_STRING_Very_Difficult,
INPUT_STRING_Very_Low,
INPUT_STRING_Low,
INPUT_STRING_High,
INPUT_STRING_Higher,
INPUT_STRING_Highest,
INPUT_STRING_Very_High,
INPUT_STRING_Players,
INPUT_STRING_Controls,
INPUT_STRING_Dual,
INPUT_STRING_Single,
INPUT_STRING_Game_Time,
INPUT_STRING_Continue_Price,
INPUT_STRING_Controller,
INPUT_STRING_Light_Gun,
INPUT_STRING_Joystick,
INPUT_STRING_Trackball,
INPUT_STRING_Continues,
INPUT_STRING_Allow_Continue,
INPUT_STRING_Level_Select,
// INPUT_STRING_Allow,
// INPUT_STRING_Forbid,
// INPUT_STRING_Enable,
// INPUT_STRING_Disable,
INPUT_STRING_Infinite,
// INPUT_STRING_Invincibility,
// INPUT_STRING_Invulnerability,
INPUT_STRING_Stereo,
INPUT_STRING_Mono,
INPUT_STRING_Unused,
INPUT_STRING_Unknown,
// INPUT_STRING_Undefined,
INPUT_STRING_Standard,
INPUT_STRING_Reverse,
INPUT_STRING_Alternate,
// INPUT_STRING_Reserve,
// INPUT_STRING_Spare,
// INPUT_STRING_Invalid,
INPUT_STRING_None,
INPUT_STRING_COUNT
};
//**************************************************************************
// TYPE DEFINITIONS
//**************************************************************************
// constructor function pointer
typedef void(*ioport_constructor)(device_t &owner, ioport_list &portlist, std::string &errorbuf);
// I/O port callback function delegates
typedef device_delegate<ioport_value ()> ioport_field_read_delegate;
typedef device_delegate<void (ioport_field &, u32, ioport_value, ioport_value)> ioport_field_write_delegate;
typedef device_delegate<float (float)> ioport_field_crossmap_delegate;
// ======================> inp_header
// header at the front of INP files
class inp_header
{
public:
// parameters
static constexpr unsigned MAJVERSION = 3;
static constexpr unsigned MINVERSION = 0;
bool read(emu_file &f)
{
return f.read(m_data, sizeof(m_data)) == sizeof(m_data);
}
bool write(emu_file &f) const
{
return f.write(m_data, sizeof(m_data)) == sizeof(m_data);
}
bool check_magic() const
{
return 0 == std::memcmp(MAGIC, m_data + OFFS_MAGIC, OFFS_BASETIME - OFFS_MAGIC);
}
u64 get_basetime() const
{
return
(u64(m_data[OFFS_BASETIME + 0]) << (0 * 8)) |
(u64(m_data[OFFS_BASETIME + 1]) << (1 * 8)) |
(u64(m_data[OFFS_BASETIME + 2]) << (2 * 8)) |
(u64(m_data[OFFS_BASETIME + 3]) << (3 * 8)) |
(u64(m_data[OFFS_BASETIME + 4]) << (4 * 8)) |
(u64(m_data[OFFS_BASETIME + 5]) << (5 * 8)) |
(u64(m_data[OFFS_BASETIME + 6]) << (6 * 8)) |
(u64(m_data[OFFS_BASETIME + 7]) << (7 * 8));
}
unsigned get_majversion() const
{
return m_data[OFFS_MAJVERSION];
}
unsigned get_minversion() const
{
return m_data[OFFS_MINVERSION];
}
std::string get_sysname() const
{
return get_string<OFFS_SYSNAME, OFFS_APPDESC>();
}
std::string get_appdesc() const
{
return get_string<OFFS_APPDESC, OFFS_END>();
}
void set_magic()
{
std::memcpy(m_data + OFFS_MAGIC, MAGIC, OFFS_BASETIME - OFFS_MAGIC);
}
void set_basetime(u64 time)
{
m_data[OFFS_BASETIME + 0] = u8((time >> (0 * 8)) & 0x00ff);
m_data[OFFS_BASETIME + 1] = u8((time >> (1 * 8)) & 0x00ff);
m_data[OFFS_BASETIME + 2] = u8((time >> (2 * 8)) & 0x00ff);
m_data[OFFS_BASETIME + 3] = u8((time >> (3 * 8)) & 0x00ff);
m_data[OFFS_BASETIME + 4] = u8((time >> (4 * 8)) & 0x00ff);
m_data[OFFS_BASETIME + 5] = u8((time >> (5 * 8)) & 0x00ff);
m_data[OFFS_BASETIME + 6] = u8((time >> (6 * 8)) & 0x00ff);
m_data[OFFS_BASETIME + 7] = u8((time >> (7 * 8)) & 0x00ff);
}
void set_version()
{
m_data[OFFS_MAJVERSION] = MAJVERSION;
m_data[OFFS_MINVERSION] = MINVERSION;
}
void set_sysname(std::string const &name)
{
set_string<OFFS_SYSNAME, OFFS_APPDESC>(name);
}
void set_appdesc(std::string const &desc)
{
set_string<OFFS_APPDESC, OFFS_END>(desc);
}
private:
template <std::size_t BEGIN, std::size_t END> void set_string(std::string const &str)
{
std::size_t const used = (std::min<std::size_t>)(str.size() + 1, END - BEGIN);
std::memcpy(m_data + BEGIN, str.c_str(), used);
if ((END - BEGIN) > used)
std::memset(m_data + BEGIN + used, 0, (END - BEGIN) - used);
}
template <std::size_t BEGIN, std::size_t END> std::string get_string() const
{
char const *const begin = reinterpret_cast<char const *>(m_data + BEGIN);
return std::string(begin, std::find(begin, reinterpret_cast<char const *>(m_data + END), '\0'));
}
static constexpr std::size_t OFFS_MAGIC = 0x00; // 0x08 bytes
static constexpr std::size_t OFFS_BASETIME = 0x08; // 0x08 bytes (little-endian binary integer)
static constexpr std::size_t OFFS_MAJVERSION = 0x10; // 0x01 bytes (binary integer)
static constexpr std::size_t OFFS_MINVERSION = 0x11; // 0x01 bytes (binary integer)
// 0x02 bytes reserved
static constexpr std::size_t OFFS_SYSNAME = 0x14; // 0x0c bytes (ASCII)
static constexpr std::size_t OFFS_APPDESC = 0x20; // 0x20 bytes (ASCII)
static constexpr std::size_t OFFS_END = 0x40;
static u8 const MAGIC[OFFS_BASETIME - OFFS_MAGIC];
u8 m_data[OFFS_END];
};
// ======================> input_device_default
// device defined default input settings
struct input_device_default
{
const char * tag; // tag of port to update
ioport_value mask; // mask to apply to the port
ioport_value defvalue; // new default value
};
// ======================> input_type_entry
// describes a fundamental input type, including default input sequences
class input_type_entry
{
public:
// construction/destruction
input_type_entry(ioport_type type, ioport_group group, int player, const char *token, const char *name, input_seq standard) noexcept;
input_type_entry(ioport_type type, ioport_group group, int player, const char *token, const char *name, input_seq standard, input_seq decrement, input_seq increment) noexcept;
// getters
ioport_type type() const noexcept { return m_type; }
ioport_group group() const noexcept { return m_group; }
u8 player() const noexcept { return m_player; }
const char *token() const noexcept { return m_token; }
const char *name() const noexcept { return m_name; }
input_seq &defseq(input_seq_type seqtype = SEQ_TYPE_STANDARD) noexcept { return m_defseq[seqtype]; }
const input_seq &defseq(input_seq_type seqtype = SEQ_TYPE_STANDARD) const noexcept { return m_defseq[seqtype]; }
const input_seq &seq(input_seq_type seqtype = SEQ_TYPE_STANDARD) const noexcept { return m_seq[seqtype]; }
// setters
void restore_default_seq() noexcept;
void set_seq(input_seq_type seqtype, const input_seq &seq) noexcept { m_seq[seqtype] = seq; }
void replace_code(input_code oldcode, input_code newcode) noexcept;
void configure_osd(const char *token, const char *name) noexcept;
private:
// internal state
ioport_type m_type; // IPT_* for this entry
ioport_group m_group; // which group the port belongs to
u8 m_player; // player number (0 is player 1)
const char * m_token; // token used to store settings
const char * m_name; // user-friendly name
std::array<input_seq, SEQ_TYPE_TOTAL> m_defseq; // default input sequence
std::array<input_seq, SEQ_TYPE_TOTAL> m_seq; // currently configured sequences
};
// ======================> digital_joystick
// tracking information about a digital joystick input
class digital_joystick
{
DISABLE_COPYING(digital_joystick);
public:
// directions
enum direction_t
{
JOYDIR_UP,
JOYDIR_DOWN,
JOYDIR_LEFT,
JOYDIR_RIGHT,
JOYDIR_COUNT
};
// bit constants
static constexpr u8 UP_BIT = 1 << JOYDIR_UP;
static constexpr u8 DOWN_BIT = 1 << JOYDIR_DOWN;
static constexpr u8 LEFT_BIT = 1 << JOYDIR_LEFT;
static constexpr u8 RIGHT_BIT = 1 << JOYDIR_RIGHT;
// construction/destruction
digital_joystick(int player, int number);
// getters
int player() const noexcept { return m_player; }
int number() const noexcept { return m_number; }
u8 current() const noexcept { return m_current; }
u8 current4way() const noexcept { return m_current4way; }
// configuration
direction_t add_axis(ioport_field &field);
// updates
void frame_update();
private:
// internal state
int m_player; // player number represented
int m_number; // joystick number represented
std::forward_list<std::reference_wrapper<ioport_field> > m_field[JOYDIR_COUNT]; // potential input fields for each direction
u8 m_current; // current value
u8 m_current4way; // current 4-way value
u8 m_previous; // previous value
};
DECLARE_ENUM_INCDEC_OPERATORS(digital_joystick::direction_t)
// ======================> ioport_condition
// encapsulates a condition on a port field or setting
class ioport_condition
{
public:
// condition types
enum condition_t
{
ALWAYS = 0,
EQUALS,
NOTEQUALS,
GREATERTHAN,
NOTGREATERTHAN,
LESSTHAN,
NOTLESSTHAN
};
// construction/destruction
ioport_condition() { reset(); }
ioport_condition(condition_t condition, const char *tag, ioport_value mask, ioport_value value) { set(condition, tag, mask, value); }
// getters
condition_t condition() const { return m_condition; }
const char *tag() const { return m_tag; }
ioport_value mask() const { return m_mask; }
ioport_value value() const { return m_value; }
// operators
bool operator==(const ioport_condition &rhs) const { return (m_mask == rhs.m_mask && m_value == rhs.m_value && m_condition == rhs.m_condition && strcmp(m_tag, rhs.m_tag) == 0); }
bool eval() const;
bool none() const { return (m_condition == ALWAYS); }
// configuration
void reset() { set(ALWAYS, nullptr, 0, 0); }
void set(condition_t condition, const char *tag, ioport_value mask, ioport_value value)
{
m_condition = condition;
m_tag = tag;
m_mask = mask;
m_value = value;
}
void initialize(device_t &device);
private:
// internal state
condition_t m_condition; // condition to use
const char * m_tag; // tag of port whose condition is to be tested
ioport_port * m_port; // reference to the port to be tested
ioport_value m_mask; // mask to apply to the port
ioport_value m_value; // value to compare against
};
// ======================> ioport_setting
// a single setting for a configuration or DIP switch
class ioport_setting
{
public:
// construction/destruction
ioport_setting(ioport_field &field, ioport_value value, const char *name);
// getters
ioport_field &field() const { return m_field; }
device_t &device() const;
running_machine &machine() const;
ioport_value value() const { return m_value; }
ioport_condition &condition() { return m_condition; }
ioport_condition const &condition() const { return m_condition; }
const char *name() const { return m_name; }
// helpers
bool enabled() const { return m_condition.eval(); }
private:
// internal state
ioport_field & m_field; // pointer back to the field that owns us
ioport_value m_value; // value of the bits in this setting
const char * m_name; // user-friendly name to display
ioport_condition m_condition; // condition under which this setting is valid
};
// ======================> ioport_diplocation
// a mapping from a bit to a physical DIP switch description
class ioport_diplocation
{
public:
// construction/destruction
ioport_diplocation(const char *name, u8 swnum, bool invert);
// getters
const char *name() const { return m_name.c_str(); }
u8 number() const { return m_number; }
bool inverted() const { return m_invert; }
private:
std::string m_name; // name of the physical DIP switch
u8 m_number; // physical switch number
bool m_invert; // is this an active-high DIP?
};
// ======================> ioport_field
// a single bitfield within an input port
class ioport_field
{
DISABLE_COPYING(ioport_field);
friend class simple_list<ioport_field>;
friend class ioport_manager;
friend class ioport_configurer;
friend class dynamic_field;
// flags for ioport_fields
static inline constexpr u32 FIELD_FLAG_OPTIONAL = 0x0001; // set if this field is not required but recognized by hw
static inline constexpr u32 FIELD_FLAG_COCKTAIL = 0x0002; // set if this field is relevant only for cocktail cabinets
static inline constexpr u32 FIELD_FLAG_TOGGLE = 0x0004; // set if this field should behave as a toggle
static inline constexpr u32 FIELD_FLAG_ROTATED = 0x0008; // set if this field represents a rotated control
static inline constexpr u32 ANALOG_FLAG_REVERSE = 0x0010; // analog only: reverse the sense of the axis
static inline constexpr u32 ANALOG_FLAG_RESET = 0x0020; // analog only: always preload in->default for relative axes, returning only deltas
static inline constexpr u32 ANALOG_FLAG_WRAPS = 0x0040; // analog only: positional count wraps around
static inline constexpr u32 ANALOG_FLAG_INVERT = 0x0080; // analog only: bitwise invert bits
public:
// construction/destruction
ioport_field(ioport_port &port, ioport_type type, ioport_value defvalue, ioport_value maskbits, const char *name = nullptr);
~ioport_field();
// getters
ioport_field *next() const { return m_next; }
ioport_port &port() const { return m_port; }
device_t &device() const;
ioport_manager &manager() const;
running_machine &machine() const;
int modcount() const { return m_modcount; }
const std::vector<ioport_setting> &settings() const { return m_settinglist; }
const std::vector<ioport_diplocation> &diplocations() const { return m_diploclist; }
ioport_value mask() const { return m_mask; }
ioport_value defvalue() const { return m_defvalue; }
ioport_condition &condition() { return m_condition; }
ioport_condition const &condition() const { return m_condition; }
ioport_type type() const { return m_type; }
u8 player() const { return m_player; }
bool digital_value() const { return m_digital_value; }
void set_value(ioport_value value);
bool optional() const { return ((m_flags & FIELD_FLAG_OPTIONAL) != 0); }
bool cocktail() const { return ((m_flags & FIELD_FLAG_COCKTAIL) != 0); }
bool toggle() const { return ((m_flags & FIELD_FLAG_TOGGLE) != 0); }
bool rotated() const { return ((m_flags & FIELD_FLAG_ROTATED) != 0); }
bool analog_reverse() const { return ((m_flags & ANALOG_FLAG_REVERSE) != 0); }
bool analog_reset() const { return ((m_flags & ANALOG_FLAG_RESET) != 0); }
bool analog_wraps() const { return ((m_flags & ANALOG_FLAG_WRAPS) != 0); }
bool analog_invert() const { return ((m_flags & ANALOG_FLAG_INVERT) != 0); }
u8 impulse() const noexcept { return m_impulse; }
const char *name() const;
const char *specific_name() const noexcept { return m_name; }
const input_seq &seq(input_seq_type seqtype = SEQ_TYPE_STANDARD) const noexcept;
const input_seq &defseq(input_seq_type seqtype = SEQ_TYPE_STANDARD) const noexcept;
const input_seq &defseq_unresolved(input_seq_type seqtype = SEQ_TYPE_STANDARD) const noexcept { return m_seq[seqtype]; }
void set_defseq(const input_seq &newseq) noexcept { set_defseq(SEQ_TYPE_STANDARD, newseq); }
void set_defseq(input_seq_type seqtype, const input_seq &newseq);
bool has_dynamic_read() const { return !m_read.isnull(); }
bool has_dynamic_write() const { return !m_write.isnull(); }
ioport_value minval() const noexcept { return m_min; }
ioport_value maxval() const noexcept { return m_max; }
s32 sensitivity() const noexcept { return m_sensitivity; }
s32 delta() const noexcept { return m_delta; }
s32 centerdelta() const noexcept { return m_centerdelta; }
crosshair_axis_t crosshair_axis() const noexcept { return m_crosshair_axis; }
float crosshair_scale() const noexcept { return m_crosshair_scale; }
float crosshair_offset() const noexcept { return m_crosshair_offset; }
float crosshair_altaxis() const noexcept { return m_crosshair_altaxis; }
u16 full_turn_count() const noexcept { return m_full_turn_count; }
const ioport_value *remap_table() const noexcept { return m_remap_table; }
u8 way() const noexcept { return m_way; }
std::vector<char32_t> keyboard_codes(int which) const;
std::string key_name(int which) const;
ioport_field_live &live() const { assert(m_live != nullptr); return *m_live; }
// setters
void set_crosshair_scale(float scale) { m_crosshair_scale = scale; }
void set_crosshair_offset(float offset) { m_crosshair_offset = offset; }
void set_player(u8 player) { m_player = player; }
// derived getters
ioport_type_class type_class() const noexcept;
bool is_analog() const noexcept { return (m_type > IPT_ANALOG_FIRST && m_type < IPT_ANALOG_LAST); }
bool is_digital_joystick() const noexcept { return (m_type > IPT_DIGITAL_JOYSTICK_FIRST && m_type < IPT_DIGITAL_JOYSTICK_LAST); }
// additional operations
bool enabled() const { return m_condition.eval(); }
const char *setting_name() const;
bool has_previous_setting() const;
void select_previous_setting();
bool has_next_setting() const;
void select_next_setting();
float crosshair_read() const;
void init_live_state(analog_field *analog);
void frame_update(ioport_value &result);
void reduce_mask(ioport_value bits_to_remove) { m_mask &= ~bits_to_remove; }
// user-controllable settings for a field
struct user_settings
{
ioport_value value = 0; // for DIP switches
input_seq seq[SEQ_TYPE_TOTAL]; // sequences of all types
s32 sensitivity = 0; // for analog controls
s32 delta = 0; // for analog controls
s32 centerdelta = 0; // for analog controls
bool reverse = false; // for analog controls
bool toggle = false; // for non-analog controls
};
void get_user_settings(user_settings &settings) const noexcept;
void set_user_settings(const user_settings &settings) noexcept;
private:
void expand_diplocation(const char *location, std::string &errorbuf);
// internal state
ioport_field * m_next; // pointer to next field in sequence
ioport_port & m_port; // reference to the port that owns us
std::unique_ptr<ioport_field_live> m_live; // live state of field (nullptr if not live)
int m_modcount; // modification count
std::vector<ioport_setting> m_settinglist; // list of input_setting_configs
std::vector<ioport_diplocation> m_diploclist; // list of locations for various bits
// generally-applicable data
ioport_value m_mask; // mask of bits belonging to the field
ioport_value m_defvalue; // default value of these bits
ioport_condition m_condition; // condition under which this field is relevant
ioport_type m_type; // IPT_* type for this port
u8 m_player; // player number (0-based)
u32 m_flags; // combination of FIELD_FLAG_* and ANALOG_FLAG_* above
u8 m_impulse; // number of frames before reverting to defvalue
const char * m_name; // user-friendly name to display
input_seq m_seq[SEQ_TYPE_TOTAL];// sequences of all types
ioport_field_read_delegate m_read; // read callback routine
ioport_field_write_delegate m_write; // write callback routine
u32 m_write_param; // parameter for write callback routine
// data relevant to digital control types
bool m_digital_value; // externally set value
// data relevant to analog control types
ioport_value m_min; // minimum value for absolute axes
ioport_value m_max; // maximum value for absolute axes
s32 m_sensitivity; // sensitivity (100=normal)
s32 m_delta; // delta to apply each frame a digital inc/dec key is pressed
s32 m_centerdelta; // delta to apply each frame no digital inputs are pressed
crosshair_axis_t m_crosshair_axis; // crosshair axis
float m_crosshair_scale; // crosshair scale
float m_crosshair_offset; // crosshair offset
float m_crosshair_altaxis;// crosshair alternate axis value
ioport_field_crossmap_delegate m_crosshair_mapper; // crosshair mapping function
u16 m_full_turn_count; // number of optical counts for 1 full turn of the original control
const ioport_value * m_remap_table; // pointer to an array that remaps the port value
// data relevant to other specific types
u8 m_way; // digital joystick 2/4/8-way descriptions
char32_t m_chars[1 << (UCHAR_SHIFT_END - UCHAR_SHIFT_BEGIN + 1)][2]; // unicode key data
};
// ======================> ioport_field_live
// internal live state of an input field
struct ioport_field_live
{
// construction/destruction
ioport_field_live(ioport_field &field, analog_field *analog);
// public state
analog_field * analog; // pointer to live analog data if this is an analog field
digital_joystick * joystick; // pointer to digital joystick information
input_seq seq[SEQ_TYPE_TOTAL];// currently configured input sequences
ioport_value value; // current value of this port
u8 impulse; // counter for impulse controls
bool last; // were we pressed last time?
bool toggle; // current toggle setting
digital_joystick::direction_t joydir; // digital joystick direction index
bool lockout; // user lockout
std::string name; // overridden name
};
// ======================> ioport_list
// class that holds a list of I/O ports
class ioport_list : public std::map<std::string, std::unique_ptr<ioport_port>>
{
DISABLE_COPYING(ioport_list);
public:
ioport_list() { }
void append(device_t &device, std::string &errorbuf);
};
// ======================> ioport_port
// a single input port configuration
class ioport_port
{
DISABLE_COPYING(ioport_port);
friend class simple_list<ioport_port>;
friend class ioport_configurer;
public:
// construction/destruction
ioport_port(device_t &owner, const char *tag);
~ioport_port();
// getters
ioport_port *next() const { return m_next; }
ioport_manager &manager() const;
device_t &device() const { return m_device; }
running_machine &machine() const;
const simple_list<ioport_field> &fields() const { return m_fieldlist; }
const char *tag() const { return m_tag.c_str(); }
int modcount() const { return m_modcount; }
ioport_value active() const { return m_active; }
ioport_port_live &live() const { assert(m_live != nullptr); return *m_live; }
// read/write to the port
ioport_value read();
void write(ioport_value value, ioport_value mask = ~0);
// other operations
ioport_field *field(ioport_value mask) const;
void collapse_fields(std::string &errorbuf);
void frame_update();
void init_live_state();
void update_defvalue(bool flush_defaults);
private:
void insert_field(ioport_field &newfield, ioport_value &disallowedbits, std::string &errorbuf);
// internal state
ioport_port * m_next; // pointer to next port
device_t & m_device; // associated device
simple_list<ioport_field> m_fieldlist; // list of ioport_fields
std::string m_tag; // copy of this port's tag
int m_modcount; // modification count
ioport_value m_active; // mask of active bits in the port
std::unique_ptr<ioport_port_live> m_live; // live state of port (nullptr if not live)
};
// ======================> analog_field
// live analog field information
class analog_field
{
friend class ioport_manager;
friend void ioport_field::set_user_settings(const ioport_field::user_settings &settings) noexcept;
public:
// construction/destruction
analog_field(ioport_field &field);
// getters
ioport_manager &manager() const noexcept { return m_field.manager(); }
ioport_field &field() const noexcept { return m_field; }
s32 sensitivity() const noexcept { return m_sensitivity; }
bool reverse() const noexcept { return m_reverse; }
s32 delta() const noexcept { return m_delta; }
s32 centerdelta() const noexcept { return m_centerdelta; }
// readers
void read(ioport_value &value);
float crosshair_read();
void frame_update(running_machine &machine);
// setters
void set_value(s32 value);
private:
// helpers
s32 apply_min_max(s32 value) const;
s32 apply_settings(s32 value) const;
s32 apply_sensitivity(s32 value) const;
s32 apply_inverse_sensitivity(s32 value) const;
// internal state
ioport_field & m_field; // pointer to the input field referenced
// adjusted values (right-justified and tweaked)
u8 m_shift; // shift to align final value in the port
s32 m_adjdefvalue; // adjusted default value from the config
s32 m_adjmin; // adjusted minimum value from the config
s32 m_adjmax; // adjusted maximum value from the config
// live values of configurable parameters
s32 m_sensitivity; // current live sensitivity (100=normal)
bool m_reverse; // current live reverse flag
s32 m_delta; // current live delta to apply each frame a digital inc/dec key is pressed
s32 m_centerdelta; // current live delta to apply each frame no digital inputs are pressed
// live analog value tracking
s32 m_accum; // accumulated value (including relative adjustments)
s32 m_previous; // previous adjusted value
s32 m_previousanalog; // previous analog value
s32 m_prog_analog_value; // programmatically set analog value
// parameters for modifying live values
s32 m_minimum; // minimum adjusted value
s32 m_maximum; // maximum adjusted value
s32 m_center; // center adjusted value for autocentering
s32 m_reverse_val; // value where we subtract from to reverse directions
// scaling factors
s64 m_scalepos; // scale factor to apply to positive adjusted values
s64 m_scaleneg; // scale factor to apply to negative adjusted values
s64 m_keyscalepos; // scale factor to apply to the key delta field when pos
s64 m_keyscaleneg; // scale factor to apply to the key delta field when neg
s64 m_positionalscale; // scale factor to divide a joystick into positions
// misc flags
bool m_absolute; // is this an absolute or relative input?
bool m_wraps; // does the control wrap around?
bool m_autocenter; // autocenter this input?
bool m_single_scale; // scale joystick differently if default is between min/max
bool m_interpolate; // should we do linear interpolation for mid-frame reads?
bool m_lastdigital; // was the last modification caused by a digital form?
bool m_was_written; // was the last modification caused programmatically?
};
// ======================> dynamic_field
// live device field information
class dynamic_field
{
public:
// construction/destruction
dynamic_field(ioport_field &field);
// getters
ioport_field &field() const { return m_field; }
// read/write
void read(ioport_value &result);
void write(ioport_value newval);
private:
// internal state
ioport_field & m_field; // reference to the input field
u8 m_shift; // shift to apply to the final result
ioport_value m_oldval; // last value
};
// ======================> ioport_port_live
// internal live state of an input port
struct ioport_port_live
{
// construction/destruction
ioport_port_live(ioport_port &port);
// public state
std::list<analog_field> analoglist; // list of analog port info
std::vector<dynamic_field> readlist; // list of dynamic read fields
std::vector<dynamic_field> writelist; // list of dynamic write fields
ioport_value defvalue; // combined default value across the port
ioport_value digital; // current value from all digital inputs
ioport_value outputvalue; // current value for outputs
};
// ======================> ioport_manager
// private input port state
class ioport_manager
{
DISABLE_COPYING(ioport_manager);
friend class device_t;
friend class ioport_configurer;
public:
// construction/destruction
ioport_manager(running_machine &machine);
time_t initialize();
~ioport_manager();
// getters
running_machine &machine() const noexcept { return m_machine; }
const ioport_list &ports() const noexcept { return m_portlist; }
bool safe_to_read() const noexcept { return m_safe_to_read; }
// type helpers
const std::vector<input_type_entry> &types() const noexcept { return m_typelist; }
bool type_pressed(ioport_type type, int player = 0);
const char *type_name(ioport_type type, u8 player) const noexcept;
ioport_group type_group(ioport_type type, int player) const noexcept;
const input_seq &type_seq(ioport_type type, int player = 0, input_seq_type seqtype = SEQ_TYPE_STANDARD) const noexcept;
void set_type_seq(ioport_type type, int player, input_seq_type seqtype, const input_seq &newseq) noexcept;
static constexpr bool type_is_analog(ioport_type type) noexcept { return (type > IPT_ANALOG_FIRST && type < IPT_ANALOG_LAST); }
bool type_class_present(ioport_type_class inputclass) const noexcept;
// other helpers
digital_joystick &digjoystick(int player, int joysticknum);
int count_players() const noexcept;
s32 frame_interpolate(s32 oldval, s32 newval);
ioport_type token_to_input_type(const char *string, int &player) const;
std::string input_type_to_token(ioport_type type, int player);
private:
// internal helpers
void init_port_types();
void init_autoselect_devices(int type1, int type2, int type3, const char *option, const char *ananame);
void frame_update_callback();
void frame_update();
ioport_port *port(const std::string &tag) const { auto search = m_portlist.find(tag); if (search != m_portlist.end()) return search->second.get(); else return nullptr; }
void exit();
input_seq_type token_to_seq_type(const char *string);
static const char *const seqtypestrings[];
void load_config(config_type cfg_type, config_level cfg_level, util::xml::data_node const *parentnode);
void load_remap_table(util::xml::data_node const &parentnode);
bool load_default_config(int type, int player, const input_seq (&newseq)[SEQ_TYPE_TOTAL]);
bool load_controller_config(util::xml::data_node const &portnode, int type, int player, const input_seq (&newseq)[SEQ_TYPE_TOTAL]);
void load_system_config(util::xml::data_node const &portnode, int type, int player, const input_seq (&newseq)[SEQ_TYPE_TOTAL]);
void save_config(config_type cfg_type, util::xml::data_node *parentnode);
void save_sequence(util::xml::data_node &parentnode, input_seq_type type, ioport_type porttype, const input_seq &seq);
bool save_this_input_field_type(ioport_type type);
void save_default_inputs(util::xml::data_node &parentnode);
void save_game_inputs(util::xml::data_node &parentnode);
template<typename Type> Type playback_read(Type &result);
time_t playback_init();
void playback_end(const char *message = nullptr);
void playback_frame(const attotime &curtime);
void playback_port(ioport_port &port);
template<typename Type> void record_write(Type value);
void record_init();
void record_end(const char *message = nullptr);
void record_frame(const attotime &curtime);
void record_port(ioport_port &port);
template<typename Type> void timecode_write(Type value);
void timecode_init();
void timecode_end(const char *message = nullptr);
// internal state
running_machine & m_machine; // reference to owning machine
bool m_safe_to_read; // clear at start; set after state is loaded
ioport_list m_portlist; // list of input port configurations
// types
std::vector<input_type_entry> m_typelist; // list of live type states
input_type_entry * m_type_to_entry[IPT_COUNT][MAX_PLAYERS]; // map from type/player to type state
// specific special global input states
std::list<digital_joystick> m_joystick_list; // list of digital joysticks
// frame time tracking
attotime m_last_frame_time; // time of the last frame callback
attoseconds_t m_last_delta_nsec; // nanoseconds that passed since the previous callback
// playback/record information
emu_file m_record_file; // recording file (closed if not recording)
emu_file m_playback_file; // playback file (closed if not recording)
util::write_stream::ptr m_record_stream; // recording stream (nullptr if not recording)
util::read_stream::ptr m_playback_stream; // playback stream (nullptr if not recording)
u64 m_playback_accumulated_speed; // accumulated speed during playback
u32 m_playback_accumulated_frames; // accumulated frames during playback
emu_file m_timecode_file; // timecode/frames playback file (nullptr if not recording)
int m_timecode_count;
attotime m_timecode_last_time;
// storage for inactive configuration
std::unique_ptr<util::xml::file> m_deselected_card_config;
};
// ======================> ioport_configurer
// class to wrap helper functions
class ioport_configurer
{
public:
// construction/destruction
ioport_configurer(device_t &owner, ioport_list &portlist, std::string &errorbuf);
// static helpers
static const char *string_from_token(const char *string);
// port helpers
ioport_configurer& port_alloc(const char *tag);
ioport_configurer& port_modify(const char *tag);
// field helpers
ioport_configurer& field_alloc(ioport_type type, ioport_value defval, ioport_value mask, const char *name = nullptr);
ioport_configurer& field_add_char(std::initializer_list<char32_t> charlist);
ioport_configurer& field_add_code(input_seq_type which, input_code code);
ioport_configurer& field_set_way(int way) { m_curfield->m_way = way; return *this; }
ioport_configurer& field_set_rotated() { m_curfield->m_flags |= ioport_field::FIELD_FLAG_ROTATED; return *this; }
ioport_configurer& field_set_name(const char *name) { assert(m_curfield != nullptr); m_curfield->m_name = string_from_token(name); return *this; }
ioport_configurer& field_set_player(int player) { m_curfield->m_player = player - 1; return *this; }
ioport_configurer& field_set_cocktail() { m_curfield->m_flags |= ioport_field::FIELD_FLAG_COCKTAIL; field_set_player(2); return *this; }
ioport_configurer& field_set_toggle() { m_curfield->m_flags |= ioport_field::FIELD_FLAG_TOGGLE; return *this; }
ioport_configurer& field_set_impulse(u8 impulse) { m_curfield->m_impulse = impulse; return *this; }
ioport_configurer& field_set_analog_reverse() { m_curfield->m_flags |= ioport_field::ANALOG_FLAG_REVERSE; return *this; }
ioport_configurer& field_set_analog_reset() { m_curfield->m_flags |= ioport_field::ANALOG_FLAG_RESET; return *this; }
ioport_configurer& field_set_optional() { m_curfield->m_flags |= ioport_field::FIELD_FLAG_OPTIONAL; return *this; }
ioport_configurer& field_set_min_max(ioport_value minval, ioport_value maxval) { m_curfield->m_min = minval; m_curfield->m_max = maxval; return *this; }
ioport_configurer& field_set_sensitivity(s32 sensitivity) { m_curfield->m_sensitivity = sensitivity; return *this; }
ioport_configurer& field_set_delta(s32 delta) { m_curfield->m_centerdelta = m_curfield->m_delta = delta; return *this; }
ioport_configurer& field_set_centerdelta(s32 delta) { m_curfield->m_centerdelta = delta; return *this; }
ioport_configurer& field_set_crosshair(crosshair_axis_t axis, double altaxis, double scale, double offset) { m_curfield->m_crosshair_axis = axis; m_curfield->m_crosshair_altaxis = altaxis; m_curfield->m_crosshair_scale = scale; m_curfield->m_crosshair_offset = offset; return *this; }
ioport_configurer& field_set_crossmapper(ioport_field_crossmap_delegate callback) { m_curfield->m_crosshair_mapper = callback; return *this; }
ioport_configurer& field_set_full_turn_count(u16 count) { m_curfield->m_full_turn_count = count; return *this; }
ioport_configurer& field_set_analog_wraps() { m_curfield->m_flags |= ioport_field::ANALOG_FLAG_WRAPS; return *this; }
ioport_configurer& field_set_remap_table(const ioport_value *table) { m_curfield->m_remap_table = table; return *this; }
ioport_configurer& field_set_analog_invert() { m_curfield->m_flags |= ioport_field::ANALOG_FLAG_INVERT; return *this; }
ioport_configurer& field_set_dynamic_read(ioport_field_read_delegate delegate) { m_curfield->m_read = delegate; return *this; }
ioport_configurer& field_set_dynamic_write(ioport_field_write_delegate delegate, u32 param = 0) { m_curfield->m_write = delegate; m_curfield->m_write_param = param; return *this; }
ioport_configurer& field_set_diplocation(const char *location) { m_curfield->expand_diplocation(location, m_errorbuf); return *this; }
// setting helpers
ioport_configurer& setting_alloc(ioport_value value, const char *name);
// misc helpers
ioport_configurer& set_condition(ioport_condition::condition_t condition, const char *tag, ioport_value mask, ioport_value value);
ioport_configurer& onoff_alloc(const char *name, ioport_value defval, ioport_value mask, const char *diplocation);
private:
// internal state
device_t & m_owner;
ioport_list & m_portlist;
std::string & m_errorbuf;
ioport_port * m_curport;
ioport_field * m_curfield;
ioport_setting * m_cursetting;
};
//**************************************************************************
// MACROS
//**************************************************************************
#define UCHAR_MAMEKEY(code) (UCHAR_MAMEKEY_BEGIN + ITEM_ID_##code)
// macro for a read callback function (PORT_CUSTOM)
#define CUSTOM_INPUT_MEMBER(name) ioport_value name()
#define DECLARE_CUSTOM_INPUT_MEMBER(name) ioport_value name()
// macro for port write callback functions (PORT_CHANGED)
#define INPUT_CHANGED_MEMBER(name) void name(ioport_field &field, u32 param, ioport_value oldval, ioport_value newval)
#define DECLARE_INPUT_CHANGED_MEMBER(name) void name(ioport_field &field, u32 param, ioport_value oldval, ioport_value newval)
// macro for port changed callback functions (PORT_CROSSHAIR_MAPPER)
#define CROSSHAIR_MAPPER_MEMBER(name) float name(float linear_value)
#define DECLARE_CROSSHAIR_MAPPER_MEMBER(name) float name(float linear_value)
// macro for wrapping a default string
#define DEF_STR(str_num) ((const char *)INPUT_STRING_##str_num)
//**************************************************************************
// MACROS FOR BUILDING INPUT PORTS
//**************************************************************************
// so that "0" can be used for unneeded input ports
#define construct_ioport_0 nullptr
// name of table
#define INPUT_PORTS_NAME(_name) construct_ioport_##_name
// start of table
#define INPUT_PORTS_START(_name) \
ATTR_COLD void INPUT_PORTS_NAME(_name)(device_t &owner, ioport_list &portlist, std::string &errorbuf) \
{ \
ioport_configurer configurer(owner, portlist, errorbuf);
// end of table
#define INPUT_PORTS_END \
}
// aliasing
#define INPUT_PORTS_EXTERN(_name) \
extern void INPUT_PORTS_NAME(_name)(device_t &owner, ioport_list &portlist, std::string &errorbuf)
// including
#define PORT_INCLUDE(_name) \
INPUT_PORTS_NAME(_name)(owner, portlist, errorbuf);
// start of a new input port (with included tag)
#define PORT_START(_tag) \
configurer.port_alloc(_tag);
// modify an existing port
#define PORT_MODIFY(_tag) \
configurer.port_modify(_tag);
// input bit definition
#define PORT_BIT(_mask, _default, _type) \
configurer.field_alloc((_type), (_default), (_mask));
#define PORT_SPECIAL_ONOFF(_mask, _default, _strindex) \
PORT_SPECIAL_ONOFF_DIPLOC(_mask, _default, _strindex, nullptr)
#define PORT_SPECIAL_ONOFF_DIPLOC(_mask, _default, _strindex, _diploc) \
configurer.onoff_alloc(DEF_STR(_strindex), _default, _mask, _diploc);
// append a code
#define PORT_CODE(_code) \
configurer.field_add_code(SEQ_TYPE_STANDARD, _code);
#define PORT_CODE_DEC(_code) \
configurer.field_add_code(SEQ_TYPE_DECREMENT, _code);
#define PORT_CODE_INC(_code) \
configurer.field_add_code(SEQ_TYPE_INCREMENT, _code);
// joystick flags
#define PORT_2WAY \
configurer.field_set_way(2);
#define PORT_4WAY \
configurer.field_set_way(4);
#define PORT_8WAY \
configurer.field_set_way(8);
#define PORT_16WAY \
configurer.field_set_way(16);
#define PORT_ROTATED \
configurer.field_set_rotated();
// general flags
#define PORT_NAME(_name) \
configurer.field_set_name(_name);
#define PORT_PLAYER(_player) \
configurer.field_set_player(_player);
#define PORT_COCKTAIL \
configurer.field_set_cocktail();
#define PORT_TOGGLE \
configurer.field_set_toggle();
#define PORT_IMPULSE(_duration) \
configurer.field_set_impulse(_duration);
#define PORT_REVERSE \
configurer.field_set_analog_reverse();
#define PORT_RESET \
configurer.field_set_analog_reset();
#define PORT_OPTIONAL \
configurer.field_set_optional();
// analog settings
// if this macro is not used, the minimum defaults to 0 and maximum defaults to the mask value
#define PORT_MINMAX(_min, _max) \
configurer.field_set_min_max(_min, _max);
#define PORT_SENSITIVITY(_sensitivity) \
configurer.field_set_sensitivity(_sensitivity);
#define PORT_KEYDELTA(_delta) \
configurer.field_set_delta(_delta);
// note that PORT_CENTERDELTA must appear after PORT_KEYDELTA
#define PORT_CENTERDELTA(_delta) \
configurer.field_set_centerdelta(_delta);
#define PORT_CROSSHAIR(axis, scale, offset, altaxis) \
configurer.field_set_crosshair(CROSSHAIR_AXIS_##axis, altaxis, scale, offset);
#define PORT_CROSSHAIR_MAPPER(_callback) \
configurer.field_set_crossmapper(ioport_field_crossmap_delegate(_callback, #_callback, DEVICE_SELF, (device_t *)nullptr));
#define PORT_CROSSHAIR_MAPPER_MEMBER(_device, _class, _member) \
configurer.field_set_crossmapper(ioport_field_crossmap_delegate(&_class::_member, #_class "::" #_member, _device, (_class *)nullptr));
// how many optical counts for 1 full turn of the control
#define PORT_FULL_TURN_COUNT(_count) \
configurer.field_set_full_turn_count(_count);
// positional controls can be binary or 1 of X
// 1 of X not completed yet
// if it is specified as PORT_REMAP_TABLE then it is binary, but remapped
// otherwise it is binary
#define PORT_POSITIONS(_positions) \
configurer.field_set_min_max(0, _positions);
// positional control wraps at min/max
#define PORT_WRAPS \
configurer.field_set_analog_wraps();
// positional control uses this remap table
#define PORT_REMAP_TABLE(_table) \
configurer.field_set_remap_table(_table);
// positional control bits are active low
#define PORT_INVERT \
configurer.field_set_analog_invert();
// read callbacks
#define PORT_CUSTOM_MEMBER(_class, _member) \
configurer.field_set_dynamic_read(ioport_field_read_delegate(owner, DEVICE_SELF, &_class::_member, #_class "::" #_member));
#define PORT_CUSTOM_DEVICE_MEMBER(_device, _class, _member) \
configurer.field_set_dynamic_read(ioport_field_read_delegate(owner, _device, &_class::_member, #_class "::" #_member));
// write callbacks
#define PORT_CHANGED_MEMBER(_device, _class, _member, _param) \
configurer.field_set_dynamic_write(ioport_field_write_delegate(owner, _device, &_class::_member, #_class "::" #_member), (_param));
// input device handler
#define PORT_READ_LINE_MEMBER(_class, _member) \
configurer.field_set_dynamic_read( \
ioport_field_read_delegate( \
owner, \
DEVICE_SELF, \
static_cast<ioport_value (*)(_class &)>([] (_class &device) -> ioport_value { return (device._member() & 1) ? ~ioport_value(0) : 0; }), \
#_class "::" #_member));
#define PORT_READ_LINE_DEVICE_MEMBER(_device, _class, _member) \
configurer.field_set_dynamic_read( \
ioport_field_read_delegate( \
owner, \
_device, \
static_cast<ioport_value (*)(_class &)>([] (_class &device) -> ioport_value { return (device._member() & 1) ? ~ioport_value(0) : 0; }), \
#_class "::" #_member));
// output device handler
#define PORT_WRITE_LINE_MEMBER(_class, _member) \
configurer.field_set_dynamic_write( \
ioport_field_write_delegate( \
owner, \
DEVICE_SELF, \
static_cast<void (*)(_class &, ioport_field &, u32, ioport_value, ioport_value)>([] (_class &device, ioport_field &field, u32 param, ioport_value oldval, ioport_value newval) { device._member(newval); }), \
#_class "::" #_member));
#define PORT_WRITE_LINE_DEVICE_MEMBER(_device, _class, _member) \
configurer.field_set_dynamic_write( \
ioport_field_write_delegate( \
owner, \
_device, \
static_cast<void (*)(_class &, ioport_field &, u32, ioport_value, ioport_value)>([] (_class &device, ioport_field &field, u32 param, ioport_value oldval, ioport_value newval) { device._member(newval); }), \
#_class "::" #_member));
// dip switch definition
#define PORT_DIPNAME(_mask, _default, _name) \
configurer.field_alloc(IPT_DIPSWITCH, (_default), (_mask), (_name));
#define PORT_DIPSETTING(_default, _name) \
configurer.setting_alloc((_default), (_name));
// physical location, of the form: name:[!]sw,[name:][!]sw,...
// note that these are specified LSB-first
#define PORT_DIPLOCATION(_location) \
configurer.field_set_diplocation(_location);
// conditionals for dip switch settings
#define PORT_CONDITION(_tag, _mask, _condition, _value) \
configurer.set_condition(ioport_condition::_condition, _tag, _mask, _value);
// analog adjuster definition
#define PORT_ADJUSTER(_default, _name) \
configurer.field_alloc(IPT_ADJUSTER, (_default), 0xff, (_name)); \
configurer.field_set_min_max(0, 100);
// config definition
#define PORT_CONFNAME(_mask, _default, _name) \
configurer.field_alloc(IPT_CONFIG, (_default), (_mask), (_name));
#define PORT_CONFSETTING(_default, _name) \
configurer.setting_alloc((_default), (_name));
// keyboard chars
#define PORT_CHAR(...) \
configurer.field_add_char({ __VA_ARGS__ });
// name of table
#define DEVICE_INPUT_DEFAULTS_NAME(_name) device_iptdef_##_name
#define device_iptdef_NOOP nullptr
// start of table
#define DEVICE_INPUT_DEFAULTS_START(_name) \
const input_device_default DEVICE_INPUT_DEFAULTS_NAME(_name)[] = {
// end of table
#define DEVICE_INPUT_DEFAULTS(_tag,_mask,_defval) \
{ _tag ,_mask, _defval },
// end of table
#define DEVICE_INPUT_DEFAULTS_END \
{nullptr,0,0} };
//**************************************************************************
// HELPER MACROS
//**************************************************************************
#define PORT_DIPUNUSED_DIPLOC(_mask, _default, _diploc) \
PORT_SPECIAL_ONOFF_DIPLOC(_mask, _default, Unused, _diploc)
#define PORT_DIPUNUSED(_mask, _default) \
PORT_SPECIAL_ONOFF(_mask, _default, Unused)
#define PORT_DIPUNKNOWN_DIPLOC(_mask, _default, _diploc) \
PORT_SPECIAL_ONOFF_DIPLOC(_mask, _default, Unknown, _diploc)
#define PORT_DIPUNKNOWN(_mask, _default) \
PORT_SPECIAL_ONOFF(_mask, _default, Unknown)
#define PORT_SERVICE_DIPLOC(_mask, _default, _diploc) \
PORT_SPECIAL_ONOFF_DIPLOC(_mask, _default, Service_Mode, _diploc)
#define PORT_SERVICE(_mask, _default) \
PORT_SPECIAL_ONOFF(_mask, _default, Service_Mode)
#define PORT_SERVICE_NO_TOGGLE(_mask, _default) \
PORT_BIT( _mask, _mask & _default, IPT_SERVICE ) PORT_NAME( DEF_STR( Service_Mode ))
#define PORT_VBLANK(_screen) \
PORT_READ_LINE_DEVICE_MEMBER(_screen, screen_device, vblank)
#define PORT_HBLANK(_screen) \
PORT_READ_LINE_DEVICE_MEMBER(_screen, screen_device, hblank)
//**************************************************************************
// INLINE FUNCTIONS
//**************************************************************************
inline ioport_manager &ioport_field::manager() const { return m_port.manager(); }
inline device_t &ioport_field::device() const { return m_port.device(); }
inline running_machine &ioport_field::machine() const { return m_port.machine(); }
inline device_t &ioport_setting::device() const { return m_field.device(); }
inline running_machine &ioport_setting::machine() const { return m_field.machine(); }
#endif // MAME_EMU_IOPORT_H