summaryrefslogtreecommitdiffstatshomepage
path: root/src/emu/ioport.c
diff options
context:
space:
mode:
author Aaron Giles <aaron@aarongiles.com>2012-05-03 09:00:08 +0000
committer Aaron Giles <aaron@aarongiles.com>2012-05-03 09:00:08 +0000
commit2a88e54278acc526c11dba7961204f234f1f6e05 (patch)
tree1d78e932e47bb535e7e56ddac05232cdf551c3a1 /src/emu/ioport.c
parent605a48921b48e0127ff0330f1e895dcf16d084fb (diff)
ioport.c C++ conversion. Mostly internal changes, with no
intended differences from previous behavior. For drivers, the main change is that input_port_read() no longer exists. Instead, the port must be fetched from the appropriate device, and then read() is called. For member functions, this is actually simpler/cleaner: value = ioport("tag")->read() For legacy functions which have a driver_data state, it goes: value = state->ioport("tag")->read() For other legacy functions, they need to fetch the root device: value = machine.root_device().ioport("tag")->read() The other big change for drivers is that IPT_VBLANK is gone. Instead, it has been replaced by a device line callback on the screen device. There's a new macro PORT_VBLANK("tag") which automatically points things to the right spot. Here's a set of imperfect search & replace strings to convert the input_port_read calls and fix up IPT_VBLANK: input_port_read( *\( *)(machine\(\)) *, *([^)]+ *\)) ioport\1\3->read\(\) input_port_read( *\( *)(.*machine[()]*) *, *([^)]+ *\)) \2\.root_device\(\)\.ioport\1\3->read\(\) (state = .*driver_data[^}]+)space->machine\(\)\.root_device\(\)\. \1state-> (state = .*driver_data[^}]+)device->machine\(\)\.root_device\(\)\. \1state-> input_port_read_safe( *\( *)(machine\(\)) *, *([^,]+), *([^)]+\)) ioport\1\3->read_safe\(\4\) IPT_VBLANK( *\)) IPT_CUSTOM\1 PORT_VBLANK("screen")
Diffstat (limited to 'src/emu/ioport.c')
-rw-r--r--src/emu/ioport.c6807
1 files changed, 3228 insertions, 3579 deletions
diff --git a/src/emu/ioport.c b/src/emu/ioport.c
index 081b1a7d6a6..2341aa9a51c 100644
--- a/src/emu/ioport.c
+++ b/src/emu/ioport.c
@@ -4,8 +4,36 @@
Input/output port handling.
- Copyright Nicola Salmoria and the MAME Team.
- Visit http://mamedev.org for licensing and usage restrictions.
+****************************************************************************
+
+ Copyright Aaron Giles
+ All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are
+ met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the
+ distribution.
+ * Neither the name 'MAME' nor the names of its contributors may be
+ used to endorse or promote products derived from this software
+ without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY AARON GILES ''AS IS'' AND ANY EXPRESS OR
+ IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ DISCLAIMED. IN NO EVENT SHALL AARON GILES BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
+ IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ POSSIBILITY OF SUCH DAMAGE.
****************************************************************************
@@ -103,459 +131,527 @@
#include <ctype.h>
#include <time.h>
-/* temporary: set this to 1 to enable the originally defined behavior that
- a field specified via PORT_MODIFY which intersects a previously-defined
- field completely wipes out the previous definition */
+// temporary: set this to 1 to enable the originally defined behavior that
+// a field specified via PORT_MODIFY which intersects a previously-defined
+// field completely wipes out the previous definition
#define INPUT_PORT_OVERRIDE_FULLY_NUKES_PREVIOUS 1
-/***************************************************************************
- CONSTANTS
-***************************************************************************/
-
-/* these constants must match the order of the joystick directions in the IPT definition */
-#define JOYDIR_UP 0
-#define JOYDIR_DOWN 1
-#define JOYDIR_LEFT 2
-#define JOYDIR_RIGHT 3
+//**************************************************************************
+// DEBUGGING
+//**************************************************************************
+
+#define LOG_NATURAL_KEYBOARD 0
+
+
+
+//**************************************************************************
+// CONSTANTS
+//**************************************************************************
+
+const int SPACE_COUNT = 3;
+const int KEY_BUFFER_SIZE = 4096;
+const unicode_char INVALID_CHAR = '?';
+
+
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// live analog field information
+class analog_field
+{
+ friend class simple_list<analog_field>;
+ friend class ioport_manager;
+ friend void ioport_field::set_user_settings(const ioport_field::user_settings &settings);
+
+public:
+ // construction/destruction
+ analog_field(ioport_field &field);
+
+ // getters
+ analog_field *next() const { return m_next; }
+ ioport_manager &manager() const { return m_field.manager(); }
+ ioport_field &field() const { return m_field; }
+ INT32 sensitivity() const { return m_sensitivity; }
+ bool reverse() const { return m_reverse; }
+ INT32 delta() const { return m_delta; }
+ INT32 centerdelta() const { return m_centerdelta; }
+
+ // helpers
+ ioport_value apply_min_max(ioport_value value) const;
+ ioport_value apply_settings(ioport_value value) const;
+ ioport_value apply_sensitivity(ioport_value value) const;
+ ioport_value apply_inverse_sensitivity(ioport_value value) const;
+
+ // readers
+ void read(ioport_value &value);
+ float crosshair_read();
+ void frame_update(running_machine &machine);
+
+private:
+ // internal state
+ analog_field * m_next; // link to the next analog state for this port
+ ioport_field & m_field; // pointer to the input field referenced
+
+ // adjusted values (right-justified and tweaked)
+ UINT8 m_shift; // shift to align final value in the port
+ INT32 m_adjdefvalue; // adjusted default value from the config
+ INT32 m_adjmin; // adjusted minimum value from the config
+ INT32 m_adjmax; // adjusted maximum value from the config
+
+ // live values of configurable parameters
+ INT32 m_sensitivity; // current live sensitivity (100=normal)
+ bool m_reverse; // current live reverse flag
+ INT32 m_delta; // current live delta to apply each frame a digital inc/dec key is pressed
+ INT32 m_centerdelta; // current live delta to apply each frame no digital inputs are pressed
+
+ // live analog value tracking
+ INT32 m_accum; // accumulated value (including relative adjustments)
+ INT32 m_previous; // previous adjusted value
+ INT32 m_previousanalog; // previous analog value
+
+ // parameters for modifying live values
+ INT32 m_minimum; // minimum adjusted value
+ INT32 m_maximum; // maximum adjusted value
+ INT32 m_center; // center adjusted value for autocentering
+ INT32 m_reverse_val; // value where we subtract from to reverse directions
+
+ // scaling factors
+ INT64 m_scalepos; // scale factor to apply to positive adjusted values
+ INT64 m_scaleneg; // scale factor to apply to negative adjusted values
+ INT64 m_keyscalepos; // scale factor to apply to the key delta field when pos
+ INT64 m_keyscaleneg; // scale factor to apply to the key delta field when neg
+ INT64 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?
+};
-#define JOYDIR_UP_BIT (1 << JOYDIR_UP)
-#define JOYDIR_DOWN_BIT (1 << JOYDIR_DOWN)
-#define JOYDIR_LEFT_BIT (1 << JOYDIR_LEFT)
-#define JOYDIR_RIGHT_BIT (1 << JOYDIR_RIGHT)
-#define LOG_INPUTX 0
-#define SPACE_COUNT 3
-#define INVALID_CHAR '?'
-#define IP_NAME_DEFAULT NULL
+// live device field information
+class dynamic_field
+{
+ friend class simple_list<dynamic_field>;
+
+public:
+ // construction/destruction
+ dynamic_field(ioport_field &field);
+
+ // getters
+ dynamic_field *next() const { return m_next; }
+ ioport_field &field() const { return m_field; }
+
+ // read/write
+ void read(ioport_value &result);
+ void write(ioport_value newval);
+
+private:
+ // internal state
+ dynamic_field * m_next; // linked list of info for this port
+ ioport_field & m_field; // reference to the input field
+ UINT8 m_shift; // shift to apply to the final result
+ ioport_value m_oldval; // last value
+};
-/***************************************************************************
- TYPE DEFINITIONS
-***************************************************************************/
+// internal live state of an input field
+struct ioport_field_live
+{
+ // construction/destruction
+ ioport_field_live(ioport_field &field, analog_field *analog);
-/* live analog field information */
-typedef struct _analog_field_state analog_field_state;
-struct _analog_field_state
-{
- analog_field_state * next; /* link to the next analog state for this port */
- const input_field_config * field; /* pointer to the input field referenced */
-
- /* adjusted values (right-justified and tweaked) */
- UINT8 shift; /* shift to align final value in the port */
- INT32 adjdefvalue; /* adjusted default value from the config */
- INT32 adjmin; /* adjusted minimum value from the config */
- INT32 adjmax; /* adjusted maximum value from the config */
-
- /* live values of configurable parameters */
- INT32 sensitivity; /* current live sensitivity (100=normal) */
- UINT8 reverse; /* current live reverse flag */
- INT32 delta; /* current live delta to apply each frame a digital inc/dec key is pressed */
- INT32 centerdelta; /* current live delta to apply each frame no digital inputs are pressed */
-
- /* live analog value tracking */
- INT32 accum; /* accumulated value (including relative adjustments) */
- INT32 previous; /* previous adjusted value */
- INT32 previousanalog; /* previous analog value */
-
- /* parameters for modifying live values */
- INT32 minimum; /* minimum adjusted value */
- INT32 maximum; /* maximum adjusted value */
- INT32 center; /* center adjusted value for autocentering */
- INT32 reverse_val; /* value where we subtract from to reverse directions */
-
- /* scaling factors */
- INT64 scalepos; /* scale factor to apply to positive adjusted values */
- INT64 scaleneg; /* scale factor to apply to negative adjusted values */
- INT64 keyscalepos; /* scale factor to apply to the key delta field when pos */
- INT64 keyscaleneg; /* scale factor to apply to the key delta field when neg */
- INT64 positionalscale; /* scale factor to divide a joystick into positions */
-
- /* misc flags */
- UINT8 absolute; /* is this an absolute or relative input? */
- UINT8 wraps; /* does the control wrap around? */
- UINT8 autocenter; /* autocenter this input? */
- UINT8 single_scale; /* scale joystick differently if default is between min/max */
- UINT8 interpolate; /* should we do linear interpolation for mid-frame reads? */
- UINT8 lastdigital; /* was the last modification caused by a digital form? */
+ // 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
+ UINT8 impulse; // counter for impulse controls
+ bool last; // were we pressed last time?
+ digital_joystick::direction_t joydir; // digital joystick direction index
+ astring name; // overridden name
};
-/* live device field information */
-typedef struct _device_field_info device_field_info;
-struct _device_field_info
+// internal live state of an input port
+struct ioport_port_live
{
- device_field_info * next; /* linked list of info for this port */
- const input_field_config * field; /* pointer to the input field referenced */
- device_t * device; /* device */
- UINT8 shift; /* shift to apply to the final result */
- input_port_value oldval; /* last value */
+ // construction/destruction
+ ioport_port_live(ioport_port &port);
+
+ // public state
+ simple_list<analog_field> analoglist; // list of analog port info
+ simple_list<dynamic_field> readlist; // list of dynamic read fields
+ simple_list<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
};
-/* internal live state of an input field */
-struct _input_field_state
+// character information
+struct char_info
{
- analog_field_state * analog; /* pointer to live analog data if this is an analog field */
- digital_joystick_state * joystick; /* pointer to digital joystick information */
- input_seq seq[SEQ_TYPE_TOTAL];/* currently configured input sequences */
- input_port_value value; /* current value of this port */
- UINT8 impulse; /* counter for impulse controls */
- UINT8 last; /* were we pressed last time? */
- UINT8 joydir; /* digital joystick direction index */
- char * name; /* overridden name */
+ unicode_char ch;
+ const char *name;
+ const char *alternate; // alternative string, in UTF-8
+
+ static const char_info *find(unicode_char target);
};
-/* internal live state of an input port */
-struct _input_port_state
-{
- analog_field_state * analoglist; /* pointer to list of analog port info */
- device_field_info * readdevicelist; /* pointer to list of input device info */
- device_field_info * writedevicelist; /* pointer to list of output device info */
- input_port_value defvalue; /* combined default value across the port */
- input_port_value digital; /* current value from all digital inputs */
- input_port_value vblank; /* value of all IPT_VBLANK bits */
- input_port_value outputvalue; /* current value for outputs */
-};
+//**************************************************************************
+// INLINE FUNCTIONS
+//**************************************************************************
-#define KEY_BUFFER_SIZE 4096
+//-------------------------------------------------
+// compute_scale -- compute an 8.24 scale value
+// from a numerator and a denominator
+//-------------------------------------------------
-typedef struct _char_info char_info;
-struct _char_info
+inline INT32 compute_scale(INT32 num, INT32 den)
{
- unicode_char ch;
- const char *name;
- const char *alternate; /* alternative string, in UTF-8 */
-};
+ return (INT64(num) << 24) / den;
+}
-/***************************************************************************
- MACROS
-***************************************************************************/
+//-------------------------------------------------
+// recip_scale -- compute an 8.24 reciprocal of
+// an 8.24 scale value
+//-------------------------------------------------
+
+inline INT32 recip_scale(INT32 scale)
+{
+ return (INT64(1) << 48) / scale;
+}
+
-#define APPLY_SENSITIVITY(x,s) (((INT64)(x) * (s)) / 100.0 + 0.5)
-#define APPLY_INVERSE_SENSITIVITY(x,s) (((INT64)(x) * 100) / (s))
+//-------------------------------------------------
+// apply_scale -- apply an 8.24 scale value to
+// a 32-bit value
+//-------------------------------------------------
-#define COMPUTE_SCALE(num,den) (((INT64)(num) << 24) / (den))
-#define RECIP_SCALE(s) (((INT64)1 << 48) / (s))
-#define APPLY_SCALE(x,s) (((INT64)(x) * (s)) >> 24)
+inline INT32 apply_scale(INT32 value, INT32 scale)
+{
+ return (INT64(value) * scale) >> 24;
+}
-/***************************************************************************
- GLOBAL VARIABLES
-***************************************************************************/
+//**************************************************************************
+// GLOBAL VARIABLES
+//**************************************************************************
-/* XML attributes for the different types */
+// XML attributes for the different types
static const char *const seqtypestrings[] = { "standard", "increment", "decrement" };
-
+// master character info table
static const char_info charinfo[] =
{
- { 0x0008, "Backspace", NULL }, /* Backspace */
- { 0x0009, "Tab", " " }, /* Tab */
- { 0x000c, "Clear", NULL }, /* Clear */
- { 0x000d, "Enter", NULL }, /* Enter */
- { 0x001a, "Esc", NULL }, /* Esc */
- { 0x0020, "Space", " " }, /* Space */
- { 0x0061, NULL, "A" }, /* a */
- { 0x0062, NULL, "B" }, /* b */
- { 0x0063, NULL, "C" }, /* c */
- { 0x0064, NULL, "D" }, /* d */
- { 0x0065, NULL, "E" }, /* e */
- { 0x0066, NULL, "F" }, /* f */
- { 0x0067, NULL, "G" }, /* g */
- { 0x0068, NULL, "H" }, /* h */
- { 0x0069, NULL, "I" }, /* i */
- { 0x006a, NULL, "J" }, /* j */
- { 0x006b, NULL, "K" }, /* k */
- { 0x006c, NULL, "L" }, /* l */
- { 0x006d, NULL, "M" }, /* m */
- { 0x006e, NULL, "N" }, /* n */
- { 0x006f, NULL, "O" }, /* o */
- { 0x0070, NULL, "P" }, /* p */
- { 0x0071, NULL, "Q" }, /* q */
- { 0x0072, NULL, "R" }, /* r */
- { 0x0073, NULL, "S" }, /* s */
- { 0x0074, NULL, "T" }, /* t */
- { 0x0075, NULL, "U" }, /* u */
- { 0x0076, NULL, "V" }, /* v */
- { 0x0077, NULL, "W" }, /* w */
- { 0x0078, NULL, "X" }, /* x */
- { 0x0079, NULL, "Y" }, /* y */
- { 0x007a, NULL, "Z" }, /* z */
- { 0x00a0, NULL, " " }, /* non breaking space */
- { 0x00a1, NULL, "!" }, /* inverted exclaimation mark */
- { 0x00a6, NULL, "|" }, /* broken bar */
- { 0x00a9, NULL, "(c)" }, /* copyright sign */
- { 0x00ab, NULL, "<<" }, /* left pointing double angle */
- { 0x00ae, NULL, "(r)" }, /* registered sign */
- { 0x00bb, NULL, ">>" }, /* right pointing double angle */
- { 0x00bc, NULL, "1/4" }, /* vulgar fraction one quarter */
- { 0x00bd, NULL, "1/2" }, /* vulgar fraction one half */
- { 0x00be, NULL, "3/4" }, /* vulgar fraction three quarters */
- { 0x00bf, NULL, "?" }, /* inverted question mark */
- { 0x00c0, NULL, "A" }, /* 'A' grave */
- { 0x00c1, NULL, "A" }, /* 'A' acute */
- { 0x00c2, NULL, "A" }, /* 'A' circumflex */
- { 0x00c3, NULL, "A" }, /* 'A' tilde */
- { 0x00c4, NULL, "A" }, /* 'A' diaeresis */
- { 0x00c5, NULL, "A" }, /* 'A' ring above */
- { 0x00c6, NULL, "AE" }, /* 'AE' ligature */
- { 0x00c7, NULL, "C" }, /* 'C' cedilla */
- { 0x00c8, NULL, "E" }, /* 'E' grave */
- { 0x00c9, NULL, "E" }, /* 'E' acute */
- { 0x00ca, NULL, "E" }, /* 'E' circumflex */
- { 0x00cb, NULL, "E" }, /* 'E' diaeresis */
- { 0x00cc, NULL, "I" }, /* 'I' grave */
- { 0x00cd, NULL, "I" }, /* 'I' acute */
- { 0x00ce, NULL, "I" }, /* 'I' circumflex */
- { 0x00cf, NULL, "I" }, /* 'I' diaeresis */
- { 0x00d0, NULL, "D" }, /* 'ETH' */
- { 0x00d1, NULL, "N" }, /* 'N' tilde */
- { 0x00d2, NULL, "O" }, /* 'O' grave */
- { 0x00d3, NULL, "O" }, /* 'O' acute */
- { 0x00d4, NULL, "O" }, /* 'O' circumflex */
- { 0x00d5, NULL, "O" }, /* 'O' tilde */
- { 0x00d6, NULL, "O" }, /* 'O' diaeresis */
- { 0x00d7, NULL, "X" }, /* multiplication sign */
- { 0x00d8, NULL, "O" }, /* 'O' stroke */
- { 0x00d9, NULL, "U" }, /* 'U' grave */
- { 0x00da, NULL, "U" }, /* 'U' acute */
- { 0x00db, NULL, "U" }, /* 'U' circumflex */
- { 0x00dc, NULL, "U" }, /* 'U' diaeresis */
- { 0x00dd, NULL, "Y" }, /* 'Y' acute */
- { 0x00df, NULL, "SS" }, /* sharp S */
- { 0x00e0, NULL, "a" }, /* 'a' grave */
- { 0x00e1, NULL, "a" }, /* 'a' acute */
- { 0x00e2, NULL, "a" }, /* 'a' circumflex */
- { 0x00e3, NULL, "a" }, /* 'a' tilde */
- { 0x00e4, NULL, "a" }, /* 'a' diaeresis */
- { 0x00e5, NULL, "a" }, /* 'a' ring above */
- { 0x00e6, NULL, "ae" }, /* 'ae' ligature */
- { 0x00e7, NULL, "c" }, /* 'c' cedilla */
- { 0x00e8, NULL, "e" }, /* 'e' grave */
- { 0x00e9, NULL, "e" }, /* 'e' acute */
- { 0x00ea, NULL, "e" }, /* 'e' circumflex */
- { 0x00eb, NULL, "e" }, /* 'e' diaeresis */
- { 0x00ec, NULL, "i" }, /* 'i' grave */
- { 0x00ed, NULL, "i" }, /* 'i' acute */
- { 0x00ee, NULL, "i" }, /* 'i' circumflex */
- { 0x00ef, NULL, "i" }, /* 'i' diaeresis */
- { 0x00f0, NULL, "d" }, /* 'eth' */
- { 0x00f1, NULL, "n" }, /* 'n' tilde */
- { 0x00f2, NULL, "o" }, /* 'o' grave */
- { 0x00f3, NULL, "o" }, /* 'o' acute */
- { 0x00f4, NULL, "o" }, /* 'o' circumflex */
- { 0x00f5, NULL, "o" }, /* 'o' tilde */
- { 0x00f6, NULL, "o" }, /* 'o' diaeresis */
- { 0x00f8, NULL, "o" }, /* 'o' stroke */
- { 0x00f9, NULL, "u" }, /* 'u' grave */
- { 0x00fa, NULL, "u" }, /* 'u' acute */
- { 0x00fb, NULL, "u" }, /* 'u' circumflex */
- { 0x00fc, NULL, "u" }, /* 'u' diaeresis */
- { 0x00fd, NULL, "y" }, /* 'y' acute */
- { 0x00ff, NULL, "y" }, /* 'y' diaeresis */
- { 0x2010, NULL, "-" }, /* hyphen */
- { 0x2011, NULL, "-" }, /* non-breaking hyphen */
- { 0x2012, NULL, "-" }, /* figure dash */
- { 0x2013, NULL, "-" }, /* en dash */
- { 0x2014, NULL, "-" }, /* em dash */
- { 0x2015, NULL, "-" }, /* horizontal dash */
- { 0x2018, NULL, "\'" }, /* left single quotation mark */
- { 0x2019, NULL, "\'" }, /* right single quotation mark */
- { 0x201a, NULL, "\'" }, /* single low quotation mark */
- { 0x201b, NULL, "\'" }, /* single high reversed quotation mark */
- { 0x201c, NULL, "\"" }, /* left double quotation mark */
- { 0x201d, NULL, "\"" }, /* right double quotation mark */
- { 0x201e, NULL, "\"" }, /* double low quotation mark */
- { 0x201f, NULL, "\"" }, /* double high reversed quotation mark */
- { 0x2024, NULL, "." }, /* one dot leader */
- { 0x2025, NULL, ".." }, /* two dot leader */
- { 0x2026, NULL, "..." }, /* horizontal ellipsis */
- { 0x2047, NULL, "??" }, /* double question mark */
- { 0x2048, NULL, "?!" }, /* question exclamation mark */
- { 0x2049, NULL, "!?" }, /* exclamation question mark */
- { 0xff01, NULL, "!" }, /* fullwidth exclamation point */
- { 0xff02, NULL, "\"" }, /* fullwidth quotation mark */
- { 0xff03, NULL, "#" }, /* fullwidth number sign */
- { 0xff04, NULL, "$" }, /* fullwidth dollar sign */
- { 0xff05, NULL, "%" }, /* fullwidth percent sign */
- { 0xff06, NULL, "&" }, /* fullwidth ampersand */
- { 0xff07, NULL, "\'" }, /* fullwidth apostrophe */
- { 0xff08, NULL, "(" }, /* fullwidth left parenthesis */
- { 0xff09, NULL, ")" }, /* fullwidth right parenthesis */
- { 0xff0a, NULL, "*" }, /* fullwidth asterisk */
- { 0xff0b, NULL, "+" }, /* fullwidth plus */
- { 0xff0c, NULL, "," }, /* fullwidth comma */
- { 0xff0d, NULL, "-" }, /* fullwidth minus */
- { 0xff0e, NULL, "." }, /* fullwidth period */
- { 0xff0f, NULL, "/" }, /* fullwidth slash */
- { 0xff10, NULL, "0" }, /* fullwidth zero */
- { 0xff11, NULL, "1" }, /* fullwidth one */
- { 0xff12, NULL, "2" }, /* fullwidth two */
- { 0xff13, NULL, "3" }, /* fullwidth three */
- { 0xff14, NULL, "4" }, /* fullwidth four */
- { 0xff15, NULL, "5" }, /* fullwidth five */
- { 0xff16, NULL, "6" }, /* fullwidth six */
- { 0xff17, NULL, "7" }, /* fullwidth seven */
- { 0xff18, NULL, "8" }, /* fullwidth eight */
- { 0xff19, NULL, "9" }, /* fullwidth nine */
- { 0xff1a, NULL, ":" }, /* fullwidth colon */
- { 0xff1b, NULL, ";" }, /* fullwidth semicolon */
- { 0xff1c, NULL, "<" }, /* fullwidth less than sign */
- { 0xff1d, NULL, "=" }, /* fullwidth equals sign */
- { 0xff1e, NULL, ">" }, /* fullwidth greater than sign */
- { 0xff1f, NULL, "?" }, /* fullwidth question mark */
- { 0xff20, NULL, "@" }, /* fullwidth at sign */
- { 0xff21, NULL, "A" }, /* fullwidth 'A' */
- { 0xff22, NULL, "B" }, /* fullwidth 'B' */
- { 0xff23, NULL, "C" }, /* fullwidth 'C' */
- { 0xff24, NULL, "D" }, /* fullwidth 'D' */
- { 0xff25, NULL, "E" }, /* fullwidth 'E' */
- { 0xff26, NULL, "F" }, /* fullwidth 'F' */
- { 0xff27, NULL, "G" }, /* fullwidth 'G' */
- { 0xff28, NULL, "H" }, /* fullwidth 'H' */
- { 0xff29, NULL, "I" }, /* fullwidth 'I' */
- { 0xff2a, NULL, "J" }, /* fullwidth 'J' */
- { 0xff2b, NULL, "K" }, /* fullwidth 'K' */
- { 0xff2c, NULL, "L" }, /* fullwidth 'L' */
- { 0xff2d, NULL, "M" }, /* fullwidth 'M' */
- { 0xff2e, NULL, "N" }, /* fullwidth 'N' */
- { 0xff2f, NULL, "O" }, /* fullwidth 'O' */
- { 0xff30, NULL, "P" }, /* fullwidth 'P' */
- { 0xff31, NULL, "Q" }, /* fullwidth 'Q' */
- { 0xff32, NULL, "R" }, /* fullwidth 'R' */
- { 0xff33, NULL, "S" }, /* fullwidth 'S' */
- { 0xff34, NULL, "T" }, /* fullwidth 'T' */
- { 0xff35, NULL, "U" }, /* fullwidth 'U' */
- { 0xff36, NULL, "V" }, /* fullwidth 'V' */
- { 0xff37, NULL, "W" }, /* fullwidth 'W' */
- { 0xff38, NULL, "X" }, /* fullwidth 'X' */
- { 0xff39, NULL, "Y" }, /* fullwidth 'Y' */
- { 0xff3a, NULL, "Z" }, /* fullwidth 'Z' */
- { 0xff3b, NULL, "[" }, /* fullwidth left bracket */
- { 0xff3c, NULL, "\\" }, /* fullwidth backslash */
- { 0xff3d, NULL, "]" }, /* fullwidth right bracket */
- { 0xff3e, NULL, "^" }, /* fullwidth caret */
- { 0xff3f, NULL, "_" }, /* fullwidth underscore */
- { 0xff40, NULL, "`" }, /* fullwidth backquote */
- { 0xff41, NULL, "a" }, /* fullwidth 'a' */
- { 0xff42, NULL, "b" }, /* fullwidth 'b' */
- { 0xff43, NULL, "c" }, /* fullwidth 'c' */
- { 0xff44, NULL, "d" }, /* fullwidth 'd' */
- { 0xff45, NULL, "e" }, /* fullwidth 'e' */
- { 0xff46, NULL, "f" }, /* fullwidth 'f' */
- { 0xff47, NULL, "g" }, /* fullwidth 'g' */
- { 0xff48, NULL, "h" }, /* fullwidth 'h' */
- { 0xff49, NULL, "i" }, /* fullwidth 'i' */
- { 0xff4a, NULL, "j" }, /* fullwidth 'j' */
- { 0xff4b, NULL, "k" }, /* fullwidth 'k' */
- { 0xff4c, NULL, "l" }, /* fullwidth 'l' */
- { 0xff4d, NULL, "m" }, /* fullwidth 'm' */
- { 0xff4e, NULL, "n" }, /* fullwidth 'n' */
- { 0xff4f, NULL, "o" }, /* fullwidth 'o' */
- { 0xff50, NULL, "p" }, /* fullwidth 'p' */
- { 0xff51, NULL, "q" }, /* fullwidth 'q' */
- { 0xff52, NULL, "r" }, /* fullwidth 'r' */
- { 0xff53, NULL, "s" }, /* fullwidth 's' */
- { 0xff54, NULL, "t" }, /* fullwidth 't' */
- { 0xff55, NULL, "u" }, /* fullwidth 'u' */
- { 0xff56, NULL, "v" }, /* fullwidth 'v' */
- { 0xff57, NULL, "w" }, /* fullwidth 'w' */
- { 0xff58, NULL, "x" }, /* fullwidth 'x' */
- { 0xff59, NULL, "y" }, /* fullwidth 'y' */
- { 0xff5a, NULL, "z" }, /* fullwidth 'z' */
- { 0xff5b, NULL, "{" }, /* fullwidth left brace */
- { 0xff5c, NULL, "|" }, /* fullwidth vertical bar */
- { 0xff5d, NULL, "}" }, /* fullwidth right brace */
- { 0xff5e, NULL, "~" }, /* fullwidth tilde */
- { 0xff5f, NULL, "((" }, /* fullwidth double left parenthesis */
- { 0xff60, NULL, "))" }, /* fullwidth double right parenthesis */
- { 0xffe0, NULL, "\xC2\xA2" }, /* fullwidth cent sign */
- { 0xffe1, NULL, "\xC2\xA3" }, /* fullwidth pound sign */
- { 0xffe4, NULL, "\xC2\xA4" }, /* fullwidth broken bar */
- { 0xffe5, NULL, "\xC2\xA5" }, /* fullwidth yen sign */
- { 0xffe6, NULL, "\xE2\x82\xA9" }, /* fullwidth won sign */
- { 0xffe9, NULL, "\xE2\x86\x90" }, /* fullwidth left arrow */
- { 0xffea, NULL, "\xE2\x86\x91" }, /* fullwidth up arrow */
- { 0xffeb, NULL, "\xE2\x86\x92" }, /* fullwidth right arrow */
- { 0xffec, NULL, "\xE2\x86\x93" }, /* fullwidth down arrow */
- { 0xffed, NULL, "\xE2\x96\xAA" }, /* fullwidth solid box */
- { 0xffee, NULL, "\xE2\x97\xA6" }, /* fullwidth open circle */
- { UCHAR_SHIFT_1, "Shift", NULL }, /* Shift key */
- { UCHAR_SHIFT_2, "Ctrl", NULL }, /* Ctrl key */
- { UCHAR_MAMEKEY(F1), "F1", NULL }, /* F1 function key */
- { UCHAR_MAMEKEY(F2), "F2", NULL }, /* F2 function key */
- { UCHAR_MAMEKEY(F3), "F3", NULL }, /* F3 function key */
- { UCHAR_MAMEKEY(F4), "F4", NULL }, /* F4 function key */
- { UCHAR_MAMEKEY(F5), "F5", NULL }, /* F5 function key */
- { UCHAR_MAMEKEY(F6), "F6", NULL }, /* F6 function key */
- { UCHAR_MAMEKEY(F7), "F7", NULL }, /* F7 function key */
- { UCHAR_MAMEKEY(F8), "F8", NULL }, /* F8 function key */
- { UCHAR_MAMEKEY(F9), "F9", NULL }, /* F9 function key */
- { UCHAR_MAMEKEY(F10), "F10", NULL }, /* F10 function key */
- { UCHAR_MAMEKEY(F11), "F11", NULL }, /* F11 function key */
- { UCHAR_MAMEKEY(F12), "F12", NULL }, /* F12 function key */
- { UCHAR_MAMEKEY(F13), "F13", NULL }, /* F13 function key */
- { UCHAR_MAMEKEY(F14), "F14", NULL }, /* F14 function key */
- { UCHAR_MAMEKEY(F15), "F15", NULL }, /* F15 function key */
- { UCHAR_MAMEKEY(ESC), "Esc", "\033" }, /* Esc key */
- { UCHAR_MAMEKEY(INSERT), "Insert", NULL }, /* Insert key */
- { UCHAR_MAMEKEY(DEL), "Delete", "\010" }, /* Delete key */
- { UCHAR_MAMEKEY(HOME), "Home", "\014" }, /* Home key */
- { UCHAR_MAMEKEY(END), "End", NULL }, /* End key */
- { UCHAR_MAMEKEY(PGUP), "Page Up", NULL }, /* Page Up key */
- { UCHAR_MAMEKEY(PGDN), "Page Down", NULL }, /* Page Down key */
- { UCHAR_MAMEKEY(LEFT), "Cursor Left", NULL }, /* Cursor Left */
- { UCHAR_MAMEKEY(RIGHT), "Cursor Right", NULL }, /* Cursor Right */
- { UCHAR_MAMEKEY(UP), "Cursor Up", NULL }, /* Cursor Up */
- { UCHAR_MAMEKEY(DOWN), "Cursor Down", NULL }, /* Cursor Down */
- { UCHAR_MAMEKEY(0_PAD), "Keypad 0", NULL }, /* 0 on the numeric keypad */
- { UCHAR_MAMEKEY(1_PAD), "Keypad 1", NULL }, /* 1 on the numeric keypad */
- { UCHAR_MAMEKEY(2_PAD), "Keypad 2", NULL }, /* 2 on the numeric keypad */
- { UCHAR_MAMEKEY(3_PAD), "Keypad 3", NULL }, /* 3 on the numeric keypad */
- { UCHAR_MAMEKEY(4_PAD), "Keypad 4", NULL }, /* 4 on the numeric keypad */
- { UCHAR_MAMEKEY(5_PAD), "Keypad 5", NULL }, /* 5 on the numeric keypad */
- { UCHAR_MAMEKEY(6_PAD), "Keypad 6", NULL }, /* 6 on the numeric keypad */
- { UCHAR_MAMEKEY(7_PAD), "Keypad 7", NULL }, /* 7 on the numeric keypad */
- { UCHAR_MAMEKEY(8_PAD), "Keypad 8", NULL }, /* 8 on the numeric keypad */
- { UCHAR_MAMEKEY(9_PAD), "Keypad 9", NULL }, /* 9 on the numeric keypad */
- { UCHAR_MAMEKEY(SLASH_PAD), "Keypad /", NULL }, /* / on the numeric keypad */
- { UCHAR_MAMEKEY(ASTERISK), "Keypad *", NULL }, /* * on the numeric keypad */
- { UCHAR_MAMEKEY(MINUS_PAD), "Keypad -", NULL }, /* - on the numeric Keypad */
- { UCHAR_MAMEKEY(PLUS_PAD), "Keypad +", NULL }, /* + on the numeric Keypad */
- { UCHAR_MAMEKEY(DEL_PAD), "Keypad .", NULL }, /* . on the numeric keypad */
- { UCHAR_MAMEKEY(ENTER_PAD), "Keypad Enter", NULL }, /* Enter on the numeric keypad */
- { UCHAR_MAMEKEY(PRTSCR), "Print Screen", NULL }, /* Print Screen key */
- { UCHAR_MAMEKEY(PAUSE), "Pause", NULL }, /* Pause key */
- { UCHAR_MAMEKEY(LSHIFT), "Left Shift", NULL }, /* Left Shift key */
- { UCHAR_MAMEKEY(RSHIFT), "Right Shift", NULL }, /* Right Shift key */
- { UCHAR_MAMEKEY(LCONTROL), "Left Ctrl", NULL }, /* Left Control key */
- { UCHAR_MAMEKEY(RCONTROL), "Right Ctrl", NULL }, /* Right Control key */
- { UCHAR_MAMEKEY(LALT), "Left Alt", NULL }, /* Left Alt key */
- { UCHAR_MAMEKEY(RALT), "Right Alt", NULL }, /* Right Alt key */
- { UCHAR_MAMEKEY(SCRLOCK), "Scroll Lock", NULL }, /* Scroll Lock key */
- { UCHAR_MAMEKEY(NUMLOCK), "Num Lock", NULL }, /* Num Lock key */
- { UCHAR_MAMEKEY(CAPSLOCK), "Caps Lock", NULL }, /* Caps Lock key */
- { UCHAR_MAMEKEY(LWIN), "Left Win", NULL }, /* Left Win key */
- { UCHAR_MAMEKEY(RWIN), "Right Win", NULL }, /* Right Win key */
- { UCHAR_MAMEKEY(MENU), "Menu", NULL }, /* Menu key */
- { UCHAR_MAMEKEY(CANCEL), "Break", NULL } /* Break/Pause key */
+ { 0x0008, "Backspace", NULL }, // Backspace
+ { 0x0009, "Tab", " " }, // Tab
+ { 0x000c, "Clear", NULL }, // Clear
+ { 0x000d, "Enter", NULL }, // Enter
+ { 0x001a, "Esc", NULL }, // Esc
+ { 0x0020, "Space", " " }, // Space
+ { 0x0061, NULL, "A" }, // a
+ { 0x0062, NULL, "B" }, // b
+ { 0x0063, NULL, "C" }, // c
+ { 0x0064, NULL, "D" }, // d
+ { 0x0065, NULL, "E" }, // e
+ { 0x0066, NULL, "F" }, // f
+ { 0x0067, NULL, "G" }, // g
+ { 0x0068, NULL, "H" }, // h
+ { 0x0069, NULL, "I" }, // i
+ { 0x006a, NULL, "J" }, // j
+ { 0x006b, NULL, "K" }, // k
+ { 0x006c, NULL, "L" }, // l
+ { 0x006d, NULL, "M" }, // m
+ { 0x006e, NULL, "N" }, // n
+ { 0x006f, NULL, "O" }, // o
+ { 0x0070, NULL, "P" }, // p
+ { 0x0071, NULL, "Q" }, // q
+ { 0x0072, NULL, "R" }, // r
+ { 0x0073, NULL, "S" }, // s
+ { 0x0074, NULL, "T" }, // t
+ { 0x0075, NULL, "U" }, // u
+ { 0x0076, NULL, "V" }, // v
+ { 0x0077, NULL, "W" }, // w
+ { 0x0078, NULL, "X" }, // x
+ { 0x0079, NULL, "Y" }, // y
+ { 0x007a, NULL, "Z" }, // z
+ { 0x00a0, NULL, " " }, // non breaking space
+ { 0x00a1, NULL, "!" }, // inverted exclaimation mark
+ { 0x00a6, NULL, "|" }, // broken bar
+ { 0x00a9, NULL, "(c)" }, // copyright sign
+ { 0x00ab, NULL, "<<" }, // left pointing double angle
+ { 0x00ae, NULL, "(r)" }, // registered sign
+ { 0x00bb, NULL, ">>" }, // right pointing double angle
+ { 0x00bc, NULL, "1/4" }, // vulgar fraction one quarter
+ { 0x00bd, NULL, "1/2" }, // vulgar fraction one half
+ { 0x00be, NULL, "3/4" }, // vulgar fraction three quarters
+ { 0x00bf, NULL, "?" }, // inverted question mark
+ { 0x00c0, NULL, "A" }, // 'A' grave
+ { 0x00c1, NULL, "A" }, // 'A' acute
+ { 0x00c2, NULL, "A" }, // 'A' circumflex
+ { 0x00c3, NULL, "A" }, // 'A' tilde
+ { 0x00c4, NULL, "A" }, // 'A' diaeresis
+ { 0x00c5, NULL, "A" }, // 'A' ring above
+ { 0x00c6, NULL, "AE" }, // 'AE' ligature
+ { 0x00c7, NULL, "C" }, // 'C' cedilla
+ { 0x00c8, NULL, "E" }, // 'E' grave
+ { 0x00c9, NULL, "E" }, // 'E' acute
+ { 0x00ca, NULL, "E" }, // 'E' circumflex
+ { 0x00cb, NULL, "E" }, // 'E' diaeresis
+ { 0x00cc, NULL, "I" }, // 'I' grave
+ { 0x00cd, NULL, "I" }, // 'I' acute
+ { 0x00ce, NULL, "I" }, // 'I' circumflex
+ { 0x00cf, NULL, "I" }, // 'I' diaeresis
+ { 0x00d0, NULL, "D" }, // 'ETH'
+ { 0x00d1, NULL, "N" }, // 'N' tilde
+ { 0x00d2, NULL, "O" }, // 'O' grave
+ { 0x00d3, NULL, "O" }, // 'O' acute
+ { 0x00d4, NULL, "O" }, // 'O' circumflex
+ { 0x00d5, NULL, "O" }, // 'O' tilde
+ { 0x00d6, NULL, "O" }, // 'O' diaeresis
+ { 0x00d7, NULL, "X" }, // multiplication sign
+ { 0x00d8, NULL, "O" }, // 'O' stroke
+ { 0x00d9, NULL, "U" }, // 'U' grave
+ { 0x00da, NULL, "U" }, // 'U' acute
+ { 0x00db, NULL, "U" }, // 'U' circumflex
+ { 0x00dc, NULL, "U" }, // 'U' diaeresis
+ { 0x00dd, NULL, "Y" }, // 'Y' acute
+ { 0x00df, NULL, "SS" }, // sharp S
+ { 0x00e0, NULL, "a" }, // 'a' grave
+ { 0x00e1, NULL, "a" }, // 'a' acute
+ { 0x00e2, NULL, "a" }, // 'a' circumflex
+ { 0x00e3, NULL, "a" }, // 'a' tilde
+ { 0x00e4, NULL, "a" }, // 'a' diaeresis
+ { 0x00e5, NULL, "a" }, // 'a' ring above
+ { 0x00e6, NULL, "ae" }, // 'ae' ligature
+ { 0x00e7, NULL, "c" }, // 'c' cedilla
+ { 0x00e8, NULL, "e" }, // 'e' grave
+ { 0x00e9, NULL, "e" }, // 'e' acute
+ { 0x00ea, NULL, "e" }, // 'e' circumflex
+ { 0x00eb, NULL, "e" }, // 'e' diaeresis
+ { 0x00ec, NULL, "i" }, // 'i' grave
+ { 0x00ed, NULL, "i" }, // 'i' acute
+ { 0x00ee, NULL, "i" }, // 'i' circumflex
+ { 0x00ef, NULL, "i" }, // 'i' diaeresis
+ { 0x00f0, NULL, "d" }, // 'eth'
+ { 0x00f1, NULL, "n" }, // 'n' tilde
+ { 0x00f2, NULL, "o" }, // 'o' grave
+ { 0x00f3, NULL, "o" }, // 'o' acute
+ { 0x00f4, NULL, "o" }, // 'o' circumflex
+ { 0x00f5, NULL, "o" }, // 'o' tilde
+ { 0x00f6, NULL, "o" }, // 'o' diaeresis
+ { 0x00f8, NULL, "o" }, // 'o' stroke
+ { 0x00f9, NULL, "u" }, // 'u' grave
+ { 0x00fa, NULL, "u" }, // 'u' acute
+ { 0x00fb, NULL, "u" }, // 'u' circumflex
+ { 0x00fc, NULL, "u" }, // 'u' diaeresis
+ { 0x00fd, NULL, "y" }, // 'y' acute
+ { 0x00ff, NULL, "y" }, // 'y' diaeresis
+ { 0x2010, NULL, "-" }, // hyphen
+ { 0x2011, NULL, "-" }, // non-breaking hyphen
+ { 0x2012, NULL, "-" }, // figure dash
+ { 0x2013, NULL, "-" }, // en dash
+ { 0x2014, NULL, "-" }, // em dash
+ { 0x2015, NULL, "-" }, // horizontal dash
+ { 0x2018, NULL, "\'" }, // left single quotation mark
+ { 0x2019, NULL, "\'" }, // right single quotation mark
+ { 0x201a, NULL, "\'" }, // single low quotation mark
+ { 0x201b, NULL, "\'" }, // single high reversed quotation mark
+ { 0x201c, NULL, "\"" }, // left double quotation mark
+ { 0x201d, NULL, "\"" }, // right double quotation mark
+ { 0x201e, NULL, "\"" }, // double low quotation mark
+ { 0x201f, NULL, "\"" }, // double high reversed quotation mark
+ { 0x2024, NULL, "." }, // one dot leader
+ { 0x2025, NULL, ".." }, // two dot leader
+ { 0x2026, NULL, "..." }, // horizontal ellipsis
+ { 0x2047, NULL, "??" }, // double question mark
+ { 0x2048, NULL, "?!" }, // question exclamation mark
+ { 0x2049, NULL, "!?" }, // exclamation question mark
+ { 0xff01, NULL, "!" }, // fullwidth exclamation point
+ { 0xff02, NULL, "\"" }, // fullwidth quotation mark
+ { 0xff03, NULL, "#" }, // fullwidth number sign
+ { 0xff04, NULL, "$" }, // fullwidth dollar sign
+ { 0xff05, NULL, "%" }, // fullwidth percent sign
+ { 0xff06, NULL, "&" }, // fullwidth ampersand
+ { 0xff07, NULL, "\'" }, // fullwidth apostrophe
+ { 0xff08, NULL, "(" }, // fullwidth left parenthesis
+ { 0xff09, NULL, ")" }, // fullwidth right parenthesis
+ { 0xff0a, NULL, "*" }, // fullwidth asterisk
+ { 0xff0b, NULL, "+" }, // fullwidth plus
+ { 0xff0c, NULL, "," }, // fullwidth comma
+ { 0xff0d, NULL, "-" }, // fullwidth minus
+ { 0xff0e, NULL, "." }, // fullwidth period
+ { 0xff0f, NULL, "/" }, // fullwidth slash
+ { 0xff10, NULL, "0" }, // fullwidth zero
+ { 0xff11, NULL, "1" }, // fullwidth one
+ { 0xff12, NULL, "2" }, // fullwidth two
+ { 0xff13, NULL, "3" }, // fullwidth three
+ { 0xff14, NULL, "4" }, // fullwidth four
+ { 0xff15, NULL, "5" }, // fullwidth five
+ { 0xff16, NULL, "6" }, // fullwidth six
+ { 0xff17, NULL, "7" }, // fullwidth seven
+ { 0xff18, NULL, "8" }, // fullwidth eight
+ { 0xff19, NULL, "9" }, // fullwidth nine
+ { 0xff1a, NULL, ":" }, // fullwidth colon
+ { 0xff1b, NULL, ";" }, // fullwidth semicolon
+ { 0xff1c, NULL, "<" }, // fullwidth less than sign
+ { 0xff1d, NULL, "=" }, // fullwidth equals sign
+ { 0xff1e, NULL, ">" }, // fullwidth greater than sign
+ { 0xff1f, NULL, "?" }, // fullwidth question mark
+ { 0xff20, NULL, "@" }, // fullwidth at sign
+ { 0xff21, NULL, "A" }, // fullwidth 'A'
+ { 0xff22, NULL, "B" }, // fullwidth 'B'
+ { 0xff23, NULL, "C" }, // fullwidth 'C'
+ { 0xff24, NULL, "D" }, // fullwidth 'D'
+ { 0xff25, NULL, "E" }, // fullwidth 'E'
+ { 0xff26, NULL, "F" }, // fullwidth 'F'
+ { 0xff27, NULL, "G" }, // fullwidth 'G'
+ { 0xff28, NULL, "H" }, // fullwidth 'H'
+ { 0xff29, NULL, "I" }, // fullwidth 'I'
+ { 0xff2a, NULL, "J" }, // fullwidth 'J'
+ { 0xff2b, NULL, "K" }, // fullwidth 'K'
+ { 0xff2c, NULL, "L" }, // fullwidth 'L'
+ { 0xff2d, NULL, "M" }, // fullwidth 'M'
+ { 0xff2e, NULL, "N" }, // fullwidth 'N'
+ { 0xff2f, NULL, "O" }, // fullwidth 'O'
+ { 0xff30, NULL, "P" }, // fullwidth 'P'
+ { 0xff31, NULL, "Q" }, // fullwidth 'Q'
+ { 0xff32, NULL, "R" }, // fullwidth 'R'
+ { 0xff33, NULL, "S" }, // fullwidth 'S'
+ { 0xff34, NULL, "T" }, // fullwidth 'T'
+ { 0xff35, NULL, "U" }, // fullwidth 'U'
+ { 0xff36, NULL, "V" }, // fullwidth 'V'
+ { 0xff37, NULL, "W" }, // fullwidth 'W'
+ { 0xff38, NULL, "X" }, // fullwidth 'X'
+ { 0xff39, NULL, "Y" }, // fullwidth 'Y'
+ { 0xff3a, NULL, "Z" }, // fullwidth 'Z'
+ { 0xff3b, NULL, "[" }, // fullwidth left bracket
+ { 0xff3c, NULL, "\\" }, // fullwidth backslash
+ { 0xff3d, NULL, "]" }, // fullwidth right bracket
+ { 0xff3e, NULL, "^" }, // fullwidth caret
+ { 0xff3f, NULL, "_" }, // fullwidth underscore
+ { 0xff40, NULL, "`" }, // fullwidth backquote
+ { 0xff41, NULL, "a" }, // fullwidth 'a'
+ { 0xff42, NULL, "b" }, // fullwidth 'b'
+ { 0xff43, NULL, "c" }, // fullwidth 'c'
+ { 0xff44, NULL, "d" }, // fullwidth 'd'
+ { 0xff45, NULL, "e" }, // fullwidth 'e'
+ { 0xff46, NULL, "f" }, // fullwidth 'f'
+ { 0xff47, NULL, "g" }, // fullwidth 'g'
+ { 0xff48, NULL, "h" }, // fullwidth 'h'
+ { 0xff49, NULL, "i" }, // fullwidth 'i'
+ { 0xff4a, NULL, "j" }, // fullwidth 'j'
+ { 0xff4b, NULL, "k" }, // fullwidth 'k'
+ { 0xff4c, NULL, "l" }, // fullwidth 'l'
+ { 0xff4d, NULL, "m" }, // fullwidth 'm'
+ { 0xff4e, NULL, "n" }, // fullwidth 'n'
+ { 0xff4f, NULL, "o" }, // fullwidth 'o'
+ { 0xff50, NULL, "p" }, // fullwidth 'p'
+ { 0xff51, NULL, "q" }, // fullwidth 'q'
+ { 0xff52, NULL, "r" }, // fullwidth 'r'
+ { 0xff53, NULL, "s" }, // fullwidth 's'
+ { 0xff54, NULL, "t" }, // fullwidth 't'
+ { 0xff55, NULL, "u" }, // fullwidth 'u'
+ { 0xff56, NULL, "v" }, // fullwidth 'v'
+ { 0xff57, NULL, "w" }, // fullwidth 'w'
+ { 0xff58, NULL, "x" }, // fullwidth 'x'
+ { 0xff59, NULL, "y" }, // fullwidth 'y'
+ { 0xff5a, NULL, "z" }, // fullwidth 'z'
+ { 0xff5b, NULL, "{" }, // fullwidth left brace
+ { 0xff5c, NULL, "|" }, // fullwidth vertical bar
+ { 0xff5d, NULL, "}" }, // fullwidth right brace
+ { 0xff5e, NULL, "~" }, // fullwidth tilde
+ { 0xff5f, NULL, "((" }, // fullwidth double left parenthesis
+ { 0xff60, NULL, "))" }, // fullwidth double right parenthesis
+ { 0xffe0, NULL, "\xC2\xA2" }, // fullwidth cent sign
+ { 0xffe1, NULL, "\xC2\xA3" }, // fullwidth pound sign
+ { 0xffe4, NULL, "\xC2\xA4" }, // fullwidth broken bar
+ { 0xffe5, NULL, "\xC2\xA5" }, // fullwidth yen sign
+ { 0xffe6, NULL, "\xE2\x82\xA9" }, // fullwidth won sign
+ { 0xffe9, NULL, "\xE2\x86\x90" }, // fullwidth left arrow
+ { 0xffea, NULL, "\xE2\x86\x91" }, // fullwidth up arrow
+ { 0xffeb, NULL, "\xE2\x86\x92" }, // fullwidth right arrow
+ { 0xffec, NULL, "\xE2\x86\x93" }, // fullwidth down arrow
+ { 0xffed, NULL, "\xE2\x96\xAA" }, // fullwidth solid box
+ { 0xffee, NULL, "\xE2\x97\xA6" }, // fullwidth open circle
+ { UCHAR_SHIFT_1, "Shift", NULL }, // Shift key
+ { UCHAR_SHIFT_2, "Ctrl", NULL }, // Ctrl key
+ { UCHAR_MAMEKEY(F1), "F1", NULL }, // F1 function key
+ { UCHAR_MAMEKEY(F2), "F2", NULL }, // F2 function key
+ { UCHAR_MAMEKEY(F3), "F3", NULL }, // F3 function key
+ { UCHAR_MAMEKEY(F4), "F4", NULL }, // F4 function key
+ { UCHAR_MAMEKEY(F5), "F5", NULL }, // F5 function key
+ { UCHAR_MAMEKEY(F6), "F6", NULL }, // F6 function key
+ { UCHAR_MAMEKEY(F7), "F7", NULL }, // F7 function key
+ { UCHAR_MAMEKEY(F8), "F8", NULL }, // F8 function key
+ { UCHAR_MAMEKEY(F9), "F9", NULL }, // F9 function key
+ { UCHAR_MAMEKEY(F10), "F10", NULL }, // F10 function key
+ { UCHAR_MAMEKEY(F11), "F11", NULL }, // F11 function key
+ { UCHAR_MAMEKEY(F12), "F12", NULL }, // F12 function key
+ { UCHAR_MAMEKEY(F13), "F13", NULL }, // F13 function key
+ { UCHAR_MAMEKEY(F14), "F14", NULL }, // F14 function key
+ { UCHAR_MAMEKEY(F15), "F15", NULL }, // F15 function key
+ { UCHAR_MAMEKEY(ESC), "Esc", "\033" }, // Esc key
+ { UCHAR_MAMEKEY(INSERT), "Insert", NULL }, // Insert key
+ { UCHAR_MAMEKEY(DEL), "Delete", "\010" }, // Delete key
+ { UCHAR_MAMEKEY(HOME), "Home", "\014" }, // Home key
+ { UCHAR_MAMEKEY(END), "End", NULL }, // End key
+ { UCHAR_MAMEKEY(PGUP), "Page Up", NULL }, // Page Up key
+ { UCHAR_MAMEKEY(PGDN), "Page Down", NULL }, // Page Down key
+ { UCHAR_MAMEKEY(LEFT), "Cursor Left", NULL }, // Cursor Left
+ { UCHAR_MAMEKEY(RIGHT), "Cursor Right", NULL }, // Cursor Right
+ { UCHAR_MAMEKEY(UP), "Cursor Up", NULL }, // Cursor Up
+ { UCHAR_MAMEKEY(DOWN), "Cursor Down", NULL }, // Cursor Down
+ { UCHAR_MAMEKEY(0_PAD), "Keypad 0", NULL }, // 0 on the numeric keypad
+ { UCHAR_MAMEKEY(1_PAD), "Keypad 1", NULL }, // 1 on the numeric keypad
+ { UCHAR_MAMEKEY(2_PAD), "Keypad 2", NULL }, // 2 on the numeric keypad
+ { UCHAR_MAMEKEY(3_PAD), "Keypad 3", NULL }, // 3 on the numeric keypad
+ { UCHAR_MAMEKEY(4_PAD), "Keypad 4", NULL }, // 4 on the numeric keypad
+ { UCHAR_MAMEKEY(5_PAD), "Keypad 5", NULL }, // 5 on the numeric keypad
+ { UCHAR_MAMEKEY(6_PAD), "Keypad 6", NULL }, // 6 on the numeric keypad
+ { UCHAR_MAMEKEY(7_PAD), "Keypad 7", NULL }, // 7 on the numeric keypad
+ { UCHAR_MAMEKEY(8_PAD), "Keypad 8", NULL }, // 8 on the numeric keypad
+ { UCHAR_MAMEKEY(9_PAD), "Keypad 9", NULL }, // 9 on the numeric keypad
+ { UCHAR_MAMEKEY(SLASH_PAD), "Keypad /", NULL }, // / on the numeric keypad
+ { UCHAR_MAMEKEY(ASTERISK), "Keypad *", NULL }, // * on the numeric keypad
+ { UCHAR_MAMEKEY(MINUS_PAD), "Keypad -", NULL }, // - on the numeric Keypad
+ { UCHAR_MAMEKEY(PLUS_PAD), "Keypad +", NULL }, // + on the numeric Keypad
+ { UCHAR_MAMEKEY(DEL_PAD), "Keypad .", NULL }, // . on the numeric keypad
+ { UCHAR_MAMEKEY(ENTER_PAD), "Keypad Enter", NULL }, // Enter on the numeric keypad
+ { UCHAR_MAMEKEY(PRTSCR), "Print Screen", NULL }, // Print Screen key
+ { UCHAR_MAMEKEY(PAUSE), "Pause", NULL }, // Pause key
+ { UCHAR_MAMEKEY(LSHIFT), "Left Shift", NULL }, // Left Shift key
+ { UCHAR_MAMEKEY(RSHIFT), "Right Shift", NULL }, // Right Shift key
+ { UCHAR_MAMEKEY(LCONTROL), "Left Ctrl", NULL }, // Left Control key
+ { UCHAR_MAMEKEY(RCONTROL), "Right Ctrl", NULL }, // Right Control key
+ { UCHAR_MAMEKEY(LALT), "Left Alt", NULL }, // Left Alt key
+ { UCHAR_MAMEKEY(RALT), "Right Alt", NULL }, // Right Alt key
+ { UCHAR_MAMEKEY(SCRLOCK), "Scroll Lock", NULL }, // Scroll Lock key
+ { UCHAR_MAMEKEY(NUMLOCK), "Num Lock", NULL }, // Num Lock key
+ { UCHAR_MAMEKEY(CAPSLOCK), "Caps Lock", NULL }, // Caps Lock key
+ { UCHAR_MAMEKEY(LWIN), "Left Win", NULL }, // Left Win key
+ { UCHAR_MAMEKEY(RWIN), "Right Win", NULL }, // Right Win key
+ { UCHAR_MAMEKEY(MENU), "Menu", NULL }, // Menu key
+ { UCHAR_MAMEKEY(CANCEL), "Break", NULL } // Break/Pause key
};
-static TIMER_CALLBACK(inputx_timerproc);
-/* Debugging commands and handlers. */
-static void execute_input(running_machine &machine, int ref, int params, const char *param[]);
-static void execute_dumpkbd(running_machine &machine, int ref, int params, const char *param[]);
-
-/***************************************************************************
- COMMON SHARED STRINGS
-***************************************************************************/
+//**************************************************************************
+// COMMON SHARED STRINGS
+//**************************************************************************
static const struct
{
@@ -686,2526 +782,2331 @@ static const struct
-/***************************************************************************
- BUILT-IN CORE MAPPINGS
-***************************************************************************/
+//**************************************************************************
+// BUILT-IN CORE MAPPINGS
+//**************************************************************************
#include "inpttype.h"
-/***************************************************************************
- FUNCTION PROTOTYPES
-***************************************************************************/
-
-/* core system management */
-static void input_port_exit(running_machine &machine);
-
-/* port reading */
-static INT32 apply_analog_settings(INT32 current, analog_field_state *analog);
-
-/* initialization helpers */
-static void init_port_types(running_machine &machine);
-static void init_port_state(running_machine &machine);
-static void init_autoselect_devices(running_machine &machine, int type1, int type2, int type3, const char *option, const char *ananame);
-static device_field_info *init_field_device_info(const input_field_config *field,const char *device_name);
-static analog_field_state *init_field_analog_state(const input_field_config *field);
-
-/* once-per-frame updates */
-static void frame_update_callback(running_machine &machine);
-static void frame_update(running_machine &machine);
-static void frame_update_digital_joysticks(running_machine &machine);
-static void frame_update_analog_field(running_machine &machine, analog_field_state *analog);
-static int frame_get_digital_field_state(const input_field_config *field, int mouse_down);
-
-/* tokenization helpers */
-static int token_to_input_field_type(running_machine &machine, const char *string, int *player);
-static const char *input_field_type_to_token(running_machine &machine, int type, int player);
-static int token_to_seq_type(const char *string);
-
-/* settings load */
-static void load_config_callback(running_machine &machine, int config_type, xml_data_node *parentnode);
-static void load_remap_table(running_machine &machine, xml_data_node *parentnode);
-static int load_default_config(running_machine &machine, xml_data_node *portnode, int type, int player, const input_seq *newseq);
-static int load_game_config(running_machine &machine, xml_data_node *portnode, int type, int player, const input_seq *newseq);
-
-/* settings save */
-static void save_config_callback(running_machine &machine, int config_type, xml_data_node *parentnode);
-static void save_sequence(running_machine &machine, xml_data_node *parentnode, int type, int porttype, const input_seq &seq);
-static int save_this_input_field_type(int type);
-static void save_default_inputs(running_machine &machine, xml_data_node *parentnode);
-static void save_game_inputs(running_machine &machine, xml_data_node *parentnode);
-
-/* input playback */
-static time_t playback_init(running_machine &machine);
-static void playback_end(running_machine &machine, const char *message);
-static void playback_frame(running_machine &machine, attotime curtime);
-static void playback_port(const input_port_config *port);
-
-/* input recording */
-static void record_init(running_machine &machine);
-static void record_end(running_machine &machine, const char *message);
-static void record_frame(running_machine &machine, attotime curtime);
-static void record_port(const input_port_config *port);
+//**************************************************************************
+// PORT CONFIGURATIONS
+//**************************************************************************
+//**************************************************************************
+// I/O PORT LIST
+//**************************************************************************
+//-------------------------------------------------
+// append - append the given device's input ports
+// to the current list
+//-------------------------------------------------
-/***************************************************************************
- INLINE FUNCTIONS
-***************************************************************************/
-
-/*-------------------------------------------------
- apply_analog_min_max - clamp the given input
- value to the appropriate min/max for the
- analog control
--------------------------------------------------*/
-
-INLINE INT32 apply_analog_min_max(const analog_field_state *analog, INT32 value)
+void ioport_list::append(device_t &device, astring &errorbuf)
{
- /* take the analog minimum and maximum values and apply the inverse of the */
- /* sensitivity so that we can clamp against them before applying sensitivity */
- INT32 adjmin = APPLY_INVERSE_SENSITIVITY(analog->minimum, analog->sensitivity);
- INT32 adjmax = APPLY_INVERSE_SENSITIVITY(analog->maximum, analog->sensitivity);
+ // no constructor, no list
+ ioport_constructor constructor = device.input_ports();
+ if (constructor == NULL)
+ return;
- /* for absolute devices, clamp to the bounds absolutely */
- if (!analog->wraps)
- {
- if (value > adjmax)
- value = adjmax;
- else if (value < adjmin)
- value = adjmin;
- }
+ // reset error buffer
+ errorbuf.reset();
- /* for relative devices, wrap around when we go past the edge */
- else
- {
- INT32 range = adjmax - adjmin;
- /* rolls to other end when 1 position past end. */
- value = (value - adjmin) % range;
- if (value < 0)
- value += range;
- value += adjmin;
- }
+ // detokenize into the list
+ (*constructor)(device, *this, errorbuf);
- return value;
+ // collapse fields and sort the list
+ for (ioport_port *port = first(); port != NULL; port = port->next())
+ port->collapse_fields(errorbuf);
}
-/*-------------------------------------------------
- get_port_tag - return a guaranteed tag for
- a port
--------------------------------------------------*/
-
-INLINE const char *get_port_tag(const input_port_config *port, char *tempbuffer)
-{
- return port->tag();
-}
+//**************************************************************************
+// INPUT TYPE ENTRY
+//**************************************************************************
-/*-------------------------------------------------
- condition_equal - TRUE if two conditions are
- equivalent
--------------------------------------------------*/
+//-------------------------------------------------
+// input_type_entry - constructors
+//-------------------------------------------------
-INLINE int condition_equal(const input_condition *cond1, const input_condition *cond2)
+input_type_entry::input_type_entry(ioport_type type, ioport_group group, int player, const char *token, const char *name, input_seq standard)
+ : m_next(NULL),
+ m_type(type),
+ m_group(group),
+ m_player(player),
+ m_token(token),
+ m_name(name)
{
- return (cond1->mask == cond2->mask && cond1->value == cond2->value && cond1->condition == cond2->condition && strcmp(cond1->tag, cond2->tag) == 0);
-}
-
-
-
-/***************************************************************************
- CORE SYSTEM MANAGEMENT
-***************************************************************************/
-
-/*-------------------------------------------------
- input_port_init - initialize the input port
- system
--------------------------------------------------*/
-
-ioport_manager::ioport_manager(running_machine &machine)
- : safe_to_read(false),
- last_frame_time(attotime::zero),
- last_delta_nsec(0),
- record_file(NULL),
- playback_file(NULL),
- playback_accumulated_speed(0),
- playback_accumulated_frames(0),
- codes(NULL),
- inputx_timer(NULL),
- queue_chars(NULL),
- accept_char(NULL),
- charqueue_empty(NULL),
- current_rate(attotime::zero),
- m_machine(machine)
-{
- memset(type_to_entry, 0, sizeof(type_to_entry));
- memset(joystick_info, 0, sizeof(joystick_info));
+ m_defseq[SEQ_TYPE_STANDARD] = m_seq[SEQ_TYPE_STANDARD] = standard;
}
-time_t ioport_manager::initialize()
+input_type_entry::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)
+ : m_next(NULL),
+ m_type(type),
+ m_group(group),
+ m_player(player),
+ m_token(token),
+ m_name(name)
{
- /* add an exit callback and a frame callback */
- machine().add_notifier(MACHINE_NOTIFY_EXIT, machine_notify_delegate(FUNC(input_port_exit), &machine()));
- machine().add_notifier(MACHINE_NOTIFY_FRAME, machine_notify_delegate(FUNC(frame_update_callback), &machine()));
-
- /* initialize the default port info from the OSD */
- init_port_types(machine());
-
- /* if we have a token list, proceed */
- device_iterator iter(machine().root_device());
- for (device_t *device = iter.first(); device != NULL; device = iter.next())
- {
- astring errors;
- input_port_list_init(*device, m_portlist, errors);
- if (errors)
- mame_printf_error("Input port errors:\n%s", errors.cstr());
- }
-
- init_port_state(machine());
- /* register callbacks for when we load configurations */
- config_register(machine(), "input", config_saveload_delegate(FUNC(load_config_callback), &machine()), config_saveload_delegate(FUNC(save_config_callback), &machine()));
-
- /* open playback and record files if specified */
- time_t basetime = playback_init(machine());
- record_init(machine());
-
- return basetime;
+ m_defseq[SEQ_TYPE_STANDARD] = m_seq[SEQ_TYPE_STANDARD] = standard;
+ m_defseq[SEQ_TYPE_INCREMENT] = m_seq[SEQ_TYPE_INCREMENT] = increment;
+ m_defseq[SEQ_TYPE_DECREMENT] = m_seq[SEQ_TYPE_DECREMENT] = decrement;
}
-/*-------------------------------------------------
- input_port_exit - exit callback to ensure
- we clean up and close our files
--------------------------------------------------*/
+//-------------------------------------------------
+// configure_osd - set the token and name of an
+// OSD entry
+//-------------------------------------------------
-static void input_port_exit(running_machine &machine)
+void input_type_entry::configure_osd(const char *token, const char *name)
{
- /* close any playback or recording files */
- playback_end(machine, NULL);
- record_end(machine, NULL);
+ assert(m_type >= IPT_OSD_1 && m_type <= IPT_OSD_16);
+ m_token = token;
+ m_name = name;
}
+//**************************************************************************
+// DIGITAL JOYSTICKS
+//**************************************************************************
-/***************************************************************************
- PORT CONFIGURATIONS
-***************************************************************************/
-
-/*-------------------------------------------------
- input_port_list_init - initialize an input
- port list structure and allocate ports
- according to the given tokens
--------------------------------------------------*/
+//-------------------------------------------------
+// digital_joystick - constructor
+//-------------------------------------------------
-void input_port_list_init(device_t &device, ioport_list &portlist, astring &errorbuf)
+digital_joystick::digital_joystick(int player, int number)
+ : m_player(player),
+ m_number(number),
+ m_current(0),
+ m_current4way(0),
+ m_previous(0)
{
- /* no constructor, no list */
- ioport_constructor constructor = device.input_ports();
- if (constructor == NULL)
- return;
+ memset(m_field, 0, sizeof(m_field));
+}
- /* reset error buffer */
- errorbuf.reset();
- /* detokenize into the list */
- (*constructor)(device, portlist, errorbuf);
+//-------------------------------------------------
+// set_axis - configure a single axis of a
+// digital joystick
+//-------------------------------------------------
- // collapse fields and sort the list
- for (input_port_config *port = portlist.first(); port != NULL; port = port->next())
- port->collapse_fields(errorbuf);
+digital_joystick::direction_t digital_joystick::set_axis(ioport_field &field)
+{
+ direction_t direction = direction_t((field.type() - (IPT_DIGITAL_JOYSTICK_FIRST + 1)) % 4);
+ m_field[direction] = &field;
+ return direction;
}
-/*-------------------------------------------------
- input_field_by_tag_and_mask - return a pointer
- to the first field that intersects the given
- mask on the tagged port
--------------------------------------------------*/
+//-------------------------------------------------
+// frame_update - update the state of digital
+// joysticks prior to accumulating the results
+// in a port
+//-------------------------------------------------
-const input_field_config *input_field_by_tag_and_mask(running_machine &machine, const char *tag, input_port_value mask)
+void digital_joystick::frame_update()
{
- const input_port_config *port = machine.root_device().ioport(tag);
+ // remember previous state and reset current state
+ m_previous = m_current;
+ m_current = 0;
- /* if we got the port, look for the field */
- if (port != NULL)
- for (const input_field_config *field = port->first_field(); field != NULL; field = field->next())
- if ((field->mask & mask) != 0)
- return field;
+ // read all the associated ports
+ running_machine *machine = NULL;
+ for (direction_t direction = JOYDIR_UP; direction < JOYDIR_COUNT; direction++)
+ if (m_field[direction] != NULL)
+ {
+ machine = &m_field[direction]->machine();
+ if (machine->input().seq_pressed(m_field[direction]->seq(SEQ_TYPE_STANDARD)))
+ m_current |= 1 << direction;
+ }
- return NULL;
+ // lock out opposing directions (left + right or up + down)
+ if ((m_current & (UP_BIT | DOWN_BIT)) == (UP_BIT | DOWN_BIT))
+ m_current &= ~(UP_BIT | DOWN_BIT);
+ if ((m_current & (LEFT_BIT | RIGHT_BIT)) == (LEFT_BIT | RIGHT_BIT))
+ m_current &= ~(LEFT_BIT | RIGHT_BIT);
+
+ // only update 4-way case if joystick has moved
+ if (m_current != m_previous)
+ {
+ m_current4way = m_current;
+
+ //
+ // If joystick is pointing at a diagonal, acknowledge that the player moved
+ // the joystick by favoring a direction change. This minimizes frustration
+ // when using a keyboard for input, and maximizes responsiveness.
+ //
+ // For example, if you are holding "left" then switch to "up" (where both left
+ // and up are briefly pressed at the same time), we'll transition immediately
+ // to "up."
+ //
+ // Zero any switches that didn't change from the previous to current state.
+ //
+ if ((m_current4way & (UP_BIT | DOWN_BIT)) &&
+ (m_current4way & (LEFT_BIT | RIGHT_BIT)))
+ {
+ m_current4way ^= m_current4way & m_previous;
+ }
+
+ //
+ // If we are still pointing at a diagonal, we are in an indeterminant state.
+ //
+ // This could happen if the player moved the joystick from the idle position directly
+ // to a diagonal, or from one diagonal directly to an extreme diagonal.
+ //
+ // The chances of this happening with a keyboard are slim, but we still need to
+ // constrain this case.
+ //
+ // For now, just resolve randomly.
+ //
+ if ((m_current4way & (UP_BIT | DOWN_BIT)) &&
+ (m_current4way & (LEFT_BIT | RIGHT_BIT)))
+ {
+ if (machine->rand() & 1)
+ m_current4way &= ~(LEFT_BIT | RIGHT_BIT);
+ else
+ m_current4way &= ~(UP_BIT | DOWN_BIT);
+ }
+ }
}
-/***************************************************************************
- ACCESSORS FOR INPUT FIELDS
-***************************************************************************/
+//**************************************************************************
+// NATURAL KEYBOARD
+//**************************************************************************
-/*-------------------------------------------------
- input_field_name - return the field name for
- a given input field
--------------------------------------------------*/
+//-------------------------------------------------
+// natural_keyboard - constructor
+//-------------------------------------------------
-const char *input_field_name(const input_field_config *field)
+natural_keyboard::natural_keyboard(running_machine &machine)
+ : m_machine(machine),
+ m_bufbegin(0),
+ m_bufend(0),
+ m_status_keydown(false),
+ m_last_cr(false),
+ m_timer(NULL),
+ m_current_rate(attotime::zero)
{
- /* if we have a non-default name, use that */
- if ((field->state != NULL) && (field->state->name != NULL))
- return field->state->name;
- if (field->name != NULL)
- return field->name;
+ // reigster debugger commands
+ if (machine.debug_flags & DEBUG_FLAG_ENABLED)
+ {
+ debug_console_register_command(machine, "input", CMDFLAG_NONE, 0, 1, 1, execute_input);
+ debug_console_register_command(machine, "dumpkbd", CMDFLAG_NONE, 0, 0, 1, execute_dumpkbd);
+ }
- /* otherwise, return the name associated with the type */
- return input_type_name(field->machine(), field->type, field->player);
+ // posting keys directly only makes sense for a computer
+ if (machine.ioport().has_keyboard())
+ {
+ m_buffer.resize(KEY_BUFFER_SIZE);
+ m_timer = machine.scheduler().timer_alloc(timer_expired_delegate(FUNC(natural_keyboard::timer), this));
+ build_codes(machine.ioport());
+ }
}
-/*-------------------------------------------------
- input_field_seq - return the input sequence
- for the given input field
--------------------------------------------------*/
+//-------------------------------------------------
+// configure - configure callbacks for full-
+// featured keyboard support
+//-------------------------------------------------
-const input_seq &input_field_seq(const input_field_config *field, input_seq_type seqtype)
+void natural_keyboard::configure(ioport_queue_chars_delegate queue_chars, ioport_accept_char_delegate accept_char, ioport_charqueue_empty_delegate charqueue_empty)
{
- /* if the field is disabled, return no key */
- if (field->flags & FIELD_FLAG_UNUSED)
- return input_seq::empty_seq;
-
- /* select either the live or config state depending on whether we have live state */
- const input_seq &portseq = (field->state == NULL) ? field->seq[seqtype] : field->state->seq[seqtype];
-
- /* if the portseq is the special default code, return the expanded default value */
- if (portseq.is_default())
- return input_type_seq(field->machine(), field->type, field->player, seqtype);
-
- /* otherwise, return the sequence as-is */
- return portseq;
+ // set the callbacks
+ m_queue_chars = queue_chars;
+ m_accept_char = accept_char;
+ m_charqueue_empty = charqueue_empty;
}
-/*-------------------------------------------------
- input_field_get_user_settings - return the current
- settings for the given input field
--------------------------------------------------*/
+//-------------------------------------------------
+// post - post a single character
+//-------------------------------------------------
-void input_field_get_user_settings(const input_field_config *field, input_field_user_settings *settings)
+void natural_keyboard::post(unicode_char ch)
{
- int seqtype;
-
- /* zap the entire structure */
- memset(settings, 0, sizeof(*settings));
-
- /* copy the basics */
- for (seqtype = 0; seqtype < ARRAY_LENGTH(settings->seq); seqtype++)
- settings->seq[seqtype] = field->state->seq[seqtype];
-
- /* if there's a list of settings or we're an adjuster, copy the current value */
- if (field->settinglist().count() != 0 || field->type == IPT_ADJUSTER)
- settings->value = field->state->value;
-
- /* if there's analog data, extract the analog settings */
- if (field->state->analog != NULL)
+ // ignore any \n that are preceded by \r
+ if (m_last_cr && ch == '\n')
{
- settings->sensitivity = field->state->analog->sensitivity;
- settings->delta = field->state->analog->delta;
- settings->centerdelta = field->state->analog->centerdelta;
- settings->reverse = field->state->analog->reverse;
+ m_last_cr = false;
+ return;
}
-}
+ // change all eolns to '\r'
+ if (ch == '\n')
+ ch = '\r';
+ else
+ m_last_cr = (ch == '\r');
-/*-------------------------------------------------
- input_field_set_user_settings - modify the current
- settings for the given input field
--------------------------------------------------*/
-
-void input_field_set_user_settings(const input_field_config *field, const input_field_user_settings *settings)
-{
- int seqtype;
-
- /* copy the basics */
- for (seqtype = 0; seqtype < ARRAY_LENGTH(settings->seq); seqtype++)
+ // logging
+ if (LOG_NATURAL_KEYBOARD)
{
- const input_seq &defseq = input_type_seq(field->machine(), field->type, field->player, (input_seq_type)seqtype);
- if (defseq == settings->seq[seqtype])
- field->state->seq[seqtype].set_default();
- else
- field->state->seq[seqtype] = settings->seq[seqtype];
+ const keycode_map_entry *code = find_code(ch);
+ astring tempstr;
+ logerror("natural_keyboard::post(): code=%i (%s) field->name='%s'\n", int(ch), unicode_to_string(tempstr, ch), (code != NULL && code->field[0] != NULL) ? code->field[0]->name() : "<null>");
}
- /* if there's a list of settings or we're an adjuster, copy the current value */
- if (field->settinglist().count() != 0 || field->type == IPT_ADJUSTER)
- field->state->value = settings->value;
+ // can we post this key in the queue directly?
+ if (can_post_directly(ch))
+ internal_post(ch);
- /* if there's analog data, extract the analog settings */
- if (field->state->analog != NULL)
+ // can we post this key with an alternate representation?
+ else if (can_post_alternate(ch))
{
- field->state->analog->sensitivity = settings->sensitivity;
- field->state->analog->delta = settings->delta;
- field->state->analog->centerdelta = settings->centerdelta;
- field->state->analog->reverse = settings->reverse;
+ const char_info *info = char_info::find(ch);
+ assert(info != NULL && info->alternate != NULL);
+ const char *altstring = info->alternate;
+ while (*altstring != 0)
+ {
+ altstring += uchar_from_utf8(&ch, altstring, strlen(altstring));
+ internal_post(ch);
+ }
}
}
-/*-------------------------------------------------
- input_field_setting_name - return the expanded
- setting name for a field
--------------------------------------------------*/
+//-------------------------------------------------
+// post - post a unicode encoded string
+//-------------------------------------------------
-const char *input_field_setting_name(const input_field_config *field)
+void natural_keyboard::post(const unicode_char *text, size_t length, attotime rate)
{
- const input_setting_config *setting;
-
- /* only makes sense if we have settings */
- assert(field->settinglist().count() != 0);
+ // set the fixed rate
+ m_current_rate = rate;
+
+ // 0 length means strlen
+ if (length == 0)
+ for (const unicode_char *scan = text; *scan != 0; scan++)
+ length++;
- /* scan the list of settings looking for a match on the current value */
- for (setting = field->settinglist().first(); setting != NULL; setting = setting->next())
- if (input_condition_true(field->machine(), &setting->condition, field->port().owner()))
- if (setting->value == field->state->value)
- return setting->name;
-
- return "INVALID";
+ // iterate over characters or until the buffer is full up
+ while (length > 0 && !full())
+ {
+ // fetch next character
+ post(*text++);
+ length--;
+ }
}
-/*-------------------------------------------------
- input_field_has_previous_setting - return TRUE
- if the given field has a "previous" setting
--------------------------------------------------*/
+//-------------------------------------------------
+// post_utf8 - post a UTF-8 encoded string
+//-------------------------------------------------
-int input_field_has_previous_setting(const input_field_config *field)
+void natural_keyboard::post_utf8(const char *text, size_t length, attotime rate)
{
- const input_setting_config *setting;
-
- /* only makes sense if we have settings */
- assert(field->settinglist().count() != 0);
-
- /* scan the list of settings looking for a match on the current value */
- for (setting = field->settinglist().first(); setting != NULL; setting = setting->next())
- if (input_condition_true(field->machine(), &setting->condition, field->port().owner()))
- return (setting->value != field->state->value);
+ // set the fixed rate
+ m_current_rate = rate;
+
+ // 0-length means strlen
+ if (length == 0)
+ length = strlen(text);
- return FALSE;
+ // iterate until out of characters
+ while (length > 0)
+ {
+ // decode the next character
+ unicode_char uc;
+ int count = uchar_from_utf8(&uc, text, length);
+ if (count < 0)
+ {
+ count = 1;
+ uc = INVALID_CHAR;
+ }
+
+ // append to the buffer
+ post(uc);
+ text += count;
+ length -= count;
+ }
}
-/*-------------------------------------------------
- input_field_select_previous_setting - select
- the previous item for a DIP switch or
- configuration field
--------------------------------------------------*/
+//-------------------------------------------------
+// post_coded - post a coded string
+//-------------------------------------------------
-void input_field_select_previous_setting(const input_field_config *field)
+void natural_keyboard::post_coded(const char *text, size_t length, attotime rate)
{
- const input_setting_config *setting, *prevsetting;
- int found_match = FALSE;
+ static const struct
+ {
+ const char *key;
+ unicode_char code;
+ } codes[] =
+ {
+ { "BACKSPACE", 8 },
+ { "BS", 8 },
+ { "BKSP", 8 },
+ { "DEL", UCHAR_MAMEKEY(DEL) },
+ { "DELETE", UCHAR_MAMEKEY(DEL) },
+ { "END", UCHAR_MAMEKEY(END) },
+ { "ENTER", 13 },
+ { "ESC", '\033' },
+ { "HOME", UCHAR_MAMEKEY(HOME) },
+ { "INS", UCHAR_MAMEKEY(INSERT) },
+ { "INSERT", UCHAR_MAMEKEY(INSERT) },
+ { "PGDN", UCHAR_MAMEKEY(PGDN) },
+ { "PGUP", UCHAR_MAMEKEY(PGUP) },
+ { "SPACE", 32 },
+ { "TAB", 9 },
+ { "F1", UCHAR_MAMEKEY(F1) },
+ { "F2", UCHAR_MAMEKEY(F2) },
+ { "F3", UCHAR_MAMEKEY(F3) },
+ { "F4", UCHAR_MAMEKEY(F4) },
+ { "F5", UCHAR_MAMEKEY(F5) },
+ { "F6", UCHAR_MAMEKEY(F6) },
+ { "F7", UCHAR_MAMEKEY(F7) },
+ { "F8", UCHAR_MAMEKEY(F8) },
+ { "F9", UCHAR_MAMEKEY(F9) },
+ { "F10", UCHAR_MAMEKEY(F10) },
+ { "F11", UCHAR_MAMEKEY(F11) },
+ { "F12", UCHAR_MAMEKEY(F12) },
+ { "QUOTE", '\"' }
+ };
- /* only makes sense if we have settings */
- assert(field->settinglist().count() != 0);
+ // set the fixed rate
+ m_current_rate = rate;
+
+ // 0-length means strlen
+ if (length == 0)
+ length = strlen(text);
- /* scan the list of settings looking for a match on the current value */
- prevsetting = NULL;
- for (setting = field->settinglist().first(); setting != NULL; setting = setting->next())
- if (input_condition_true(field->machine(), &setting->condition, field->port().owner()))
- {
- if (setting->value == field->state->value)
+ // iterate through the source string
+ size_t curpos = 0;
+ while (curpos < length)
+ {
+ // extract next character
+ unicode_char ch = text[curpos];
+ size_t increment = 1;
+
+ // look for escape characters
+ if (ch == '{')
+ for (int codenum = 0; codenum < ARRAY_LENGTH(codes); codenum++)
{
- found_match = TRUE;
- if (prevsetting != NULL)
- break;
+ size_t keylen = strlen(codes[codenum].key);
+ if (curpos + keylen + 2 <= length)
+ if (core_strnicmp(codes[codenum].key, &text[curpos + 1], keylen) == 0 && text[curpos + keylen + 1] == '}')
+ {
+ ch = codes[codenum].code;
+ increment = keylen + 2;
+ }
}
- prevsetting = setting;
- }
- /* if we didn't find a matching value, select the first */
- if (!found_match)
- {
- for (prevsetting = field->settinglist().first(); prevsetting != NULL; prevsetting = prevsetting->next())
- if (input_condition_true(field->machine(), &prevsetting->condition, field->port().owner()))
- break;
+ // if we got a code, post it
+ if (ch != 0)
+ post(ch);
+ curpos += increment;
}
-
- /* update the value to the previous one */
- if (prevsetting != NULL)
- field->state->value = prevsetting->value;
}
-/*-------------------------------------------------
- input_field_has_next_setting - return TRUE
- if the given field has a "next" setting
--------------------------------------------------*/
+//-------------------------------------------------
+// build_codes - given an input port table, create
+// an input code table useful for mapping unicode
+// chars
+//-------------------------------------------------
-int input_field_has_next_setting(const input_field_config *field)
+void natural_keyboard::build_codes(ioport_manager &manager)
{
- const input_setting_config *setting;
- int found = FALSE;
+ // iterate over shift keys
+ ioport_field *shift[UCHAR_SHIFT_END + 1 - UCHAR_SHIFT_BEGIN] = { 0 };
+ for (int curshift = 0; curshift <= ARRAY_LENGTH(shift); curshift++)
+ if (curshift == 0 || shift[curshift - 1] != NULL)
- /* only makes sense if we have settings */
- assert(field->settinglist().count() != 0);
+ // iterate over ports and fields
+ for (ioport_port *port = manager.first_port(); port != NULL; port = port->next())
+ for (ioport_field *field = port->first_field(); field != NULL; field = field->next())
+ if (field->type() == IPT_KEYBOARD)
+ {
+ // fetch the code, ignoring 0
+ unicode_char code = field->keyboard_code(curshift);
+ if (code == 0)
+ continue;
- /* scan the list of settings looking for a match on the current value */
- for (setting = field->settinglist().first(); setting != NULL; setting = setting->next())
- if (input_condition_true(field->machine(), &setting->condition, field->port().owner()))
- {
- if (found)
- return TRUE;
- if (setting->value == field->state->value)
- found = TRUE;
- }
+ // is this a shifter key?
+ if (code >= UCHAR_SHIFT_BEGIN && code <= UCHAR_SHIFT_END)
+ shift[code - UCHAR_SHIFT_BEGIN] = field;
- return FALSE;
+ // not a shifter key; record normally
+ else
+ {
+ keycode_map_entry newcode;
+ if (curshift == 0)
+ newcode.field[0] = field;
+ else
+ {
+ newcode.field[0] = shift[curshift - 1];
+ newcode.field[1] = field;
+ }
+ newcode.ch = code;
+ m_keycode_map.append(newcode);
+
+ if (LOG_NATURAL_KEYBOARD)
+ {
+ astring tempstr;
+ logerror("natural_keyboard: code=%i (%s) port=%p field->name='%s'\n", int(code), unicode_to_string(tempstr, code), port, field->name());
+ }
+ }
+ }
}
-/*-------------------------------------------------
- input_field_select_next_setting - select the
- next item for a DIP switch or
- configuration field
--------------------------------------------------*/
+//-------------------------------------------------
+// can_post_directly - determine if the given
+// unicode character can be directly posted
+//-------------------------------------------------
-void input_field_select_next_setting(const input_field_config *field)
+bool natural_keyboard::can_post_directly(unicode_char ch)
{
- const input_setting_config *setting, *nextsetting;
+ // if we have a queueing callback, then it depends on whether we can accept the character
+ if (!m_queue_chars.isnull())
+ return m_accept_char.isnull() ? true : m_accept_char(ch);
- /* only makes sense if we have settings */
- assert(field->settinglist().count() != 0);
+ // otherwise, it depends on the input codes
+ const keycode_map_entry *code = find_code(ch);
+ return (code != NULL && code->field[0] != NULL);
+}
- /* scan the list of settings looking for a match on the current value */
- nextsetting = NULL;
- for (setting = field->settinglist().first(); setting != NULL; setting = setting->next())
- if (input_condition_true(field->machine(), &setting->condition, field->port().owner()))
- if (setting->value == field->state->value)
- break;
- /* if we found one, scan forward for the next valid one */
- if (setting != NULL)
- for (nextsetting = setting->next(); nextsetting != NULL; nextsetting = nextsetting->next())
- if (input_condition_true(field->machine(), &nextsetting->condition, field->port().owner()))
- break;
+//-------------------------------------------------
+// can_post_alternate - determine if the given
+// unicode character can be posted via translation
+//-------------------------------------------------
- /* if we hit the end, search from the beginning */
- if (nextsetting == NULL)
- for (nextsetting = field->settinglist().first(); nextsetting != NULL; nextsetting = nextsetting->next())
- if (input_condition_true(field->machine(), &nextsetting->condition, field->port().owner()))
- break;
+bool natural_keyboard::can_post_alternate(unicode_char ch)
+{
+ const char_info *info = char_info::find(ch);
+ if (info == NULL)
+ return false;
+
+ const char *altstring = info->alternate;
+ if (altstring == NULL)
+ return false;
- /* update the value to the previous one */
- if (nextsetting != NULL)
- field->state->value = nextsetting->value;
+ while (*altstring != 0)
+ {
+ unicode_char uchar;
+ int count = uchar_from_utf8(&uchar, altstring, strlen(altstring));
+ if (count <= 0)
+ return false;
+ if (!can_post_directly(uchar))
+ return false;
+ altstring += count;
+ }
+ return true;
}
+//-------------------------------------------------
+// choose_delay - determine the delay between
+// posting keyboard events
+//-------------------------------------------------
-/***************************************************************************
- ACCESSORS FOR INPUT TYPES
-***************************************************************************/
+attotime natural_keyboard::choose_delay(unicode_char ch)
+{
+ // if we have a live rate, just use that
+ if (m_current_rate != attotime::zero)
+ return m_current_rate;
-/*-------------------------------------------------
- input_type_is_analog - return TRUE if
- the given type represents an analog control
--------------------------------------------------*/
+ // systems with queue_chars can afford a much smaller delay
+ if (!m_queue_chars.isnull())
+ return attotime::from_msec(10);
-int input_type_is_analog(int type)
-{
- return (type >= __ipt_analog_start && type <= __ipt_analog_end);
+ // otherwise, default to constant delay with a longer delay on CR
+ return attotime::from_msec((ch == '\r') ? 200 : 50);
}
-/*-------------------------------------------------
- input_type_name - return the name
- for the given type/player
--------------------------------------------------*/
+//-------------------------------------------------
+// internal_post - post a keyboard event
+//-------------------------------------------------
-const char *input_type_name(running_machine &machine, int type, int player)
+void natural_keyboard::internal_post(unicode_char ch)
{
- /* if we have a machine, use the live state and quick lookup */
- ioport_manager &portdata = machine.ioport();
- input_type_entry *entry = portdata.type_to_entry[type][player];
- if (entry != NULL)
- return entry->name;
+ // need to start up the timer?
+ if (empty())
+ {
+ m_timer->adjust(choose_delay(ch));
+ m_status_keydown = 0;
+ }
- /* if we find nothing, return an invalid group */
- return "???";
+ // add to the buffer, resizing if necessary
+ m_buffer[m_bufend++] = ch;
+ if ((m_bufend + 1) % m_buffer.count() == m_bufbegin)
+ m_buffer.resize(m_buffer.count() + KEY_BUFFER_SIZE, true);
+ m_bufend %= m_buffer.count();
}
-/*-------------------------------------------------
- input_type_group - return the group
- for the given type/player
--------------------------------------------------*/
+//-------------------------------------------------
+// timer - timer callback to keep things flowing
+// when posting a string of characters
+//-------------------------------------------------
-int input_type_group(running_machine &machine, int type, int player)
+void natural_keyboard::timer(void *ptr, int param)
{
- ioport_manager &portdata = machine.ioport();
- input_type_entry *entry = portdata.type_to_entry[type][player];
- if (entry != NULL)
- return entry->group;
+ // the driver has a queue_chars handler
+ if (!m_queue_chars.isnull())
+ {
+ while (!empty() && m_queue_chars(&m_buffer[m_bufbegin], 1))
+ {
+ m_bufbegin = (m_bufbegin + 1) % m_buffer.count();
+ if (m_current_rate != attotime::zero)
+ break;
+ }
+ }
- /* if we find nothing, return an invalid group */
- return IPG_INVALID;
+ // the driver does not have a queue_chars handler
+ else
+ {
+ if (m_status_keydown)
+ m_bufbegin = (m_bufbegin + 1) % m_buffer.count();
+ m_status_keydown = !m_status_keydown;
+ }
+
+ // need to make sure timerproc is called again if buffer not empty
+ if (!empty())
+ m_timer->adjust(choose_delay(m_buffer[m_bufbegin]));
}
-/*-------------------------------------------------
- input_type_seq - return the input
- sequence for the given type/player
--------------------------------------------------*/
+//-------------------------------------------------
+// unicode_to_string - obtain a string
+// representation of a given code; used for
+// logging and debugging
+//-------------------------------------------------
-const input_seq &input_type_seq(running_machine &machine, int type, int player, input_seq_type seqtype)
+const char *natural_keyboard::unicode_to_string(astring &buffer, unicode_char ch)
{
- assert(type >= 0 && type < __ipt_max);
- assert(player >= 0 && player < MAX_PLAYERS);
+ buffer.reset();
+ switch (ch)
+ {
+ // check some magic values
+ case '\0': buffer.cpy("\\0"); break;
+ case '\r': buffer.cpy("\\r"); break;
+ case '\n': buffer.cpy("\\n"); break;
+ case '\t': buffer.cpy("\\t"); break;
- /* if we have a machine, use the live state and quick lookup */
- ioport_manager &portdata = machine.ioport();
- input_type_entry *entry = portdata.type_to_entry[type][player];
- if (entry != NULL)
- return entry->seq[seqtype];
+ default:
+ // seven bit ASCII is easy
+ if (ch >= 32 && ch < 128)
+ {
+ char temp[2] = { char(ch), 0 };
+ buffer.cpy(temp);
+ }
+ else if (ch >= UCHAR_MAMEKEY_BEGIN)
+ {
+ // try to obtain a codename with code_name(); this can result in an empty string
+ input_code code(DEVICE_CLASS_KEYBOARD, 0, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, input_item_id(ch - UCHAR_MAMEKEY_BEGIN));
+ machine().input().code_name(buffer, code);
+ }
- /* if we find nothing, return an empty sequence */
- return input_seq::empty_seq;
+ // did we fail to resolve? if so, we have a last resort
+ if (buffer.len() == 0)
+ buffer.format("U+%04X", unsigned(ch));
+ break;
+ }
+ return buffer;
}
-/*-------------------------------------------------
- input_type_set_seq - change the input
- sequence for the given type/player
--------------------------------------------------*/
+//-------------------------------------------------
+// find_code - find a code in our lookup table
+//-------------------------------------------------
-void input_type_set_seq(running_machine &machine, int type, int player, input_seq_type seqtype, const input_seq *newseq)
+const natural_keyboard::keycode_map_entry *natural_keyboard::find_code(unicode_char ch) const
{
- ioport_manager &portdata = machine.ioport();
- input_type_entry *entry = portdata.type_to_entry[type][player];
- if (entry != NULL)
- entry->seq[seqtype] = *newseq;
+ for (int code = 0; m_keycode_map[code].ch != 0; code++)
+ if (m_keycode_map[code].ch == ch)
+ return &m_keycode_map[code];
+ return NULL;
}
-/*-------------------------------------------------
- input_type_pressed - return TRUE if
- the sequence for the given input type/player
- is pressed
--------------------------------------------------*/
+//-------------------------------------------------
+// frame_update - once per frame update of the
+// natural keyboard state
+//-------------------------------------------------
-int input_type_pressed(running_machine &machine, int type, int player)
+void natural_keyboard::frame_update(ioport_port &port, ioport_value &digital)
{
- return machine.input().seq_pressed(input_type_seq(machine, type, player, SEQ_TYPE_STANDARD));
+ // is there currently a key down?
+ if (m_status_keydown && !empty())
+ {
+ // loop through this character's component codes
+ const keycode_map_entry *code = find_code(m_buffer[m_bufbegin]);
+ if (code != NULL)
+ for (int fieldnum = 0; fieldnum < ARRAY_LENGTH(code->field) && code->field[fieldnum] != NULL; fieldnum++)
+ if (&code->field[fieldnum]->port() == &port)
+ digital |= code->field[fieldnum]->mask();
+ }
}
-/*-------------------------------------------------
- input_type_list - return the list of types
--------------------------------------------------*/
+//-------------------------------------------------
+// key_name - returns the name of a specific key
+//-------------------------------------------------
-const simple_list<input_type_entry> &input_type_list(running_machine &machine)
+const char *natural_keyboard::key_name(astring &string, unicode_char ch)
{
- ioport_manager &portdata = machine.ioport();
- return portdata.typelist;
-}
-
+ // attempt to get the string from the character info table
+ const char_info *ci = char_info::find(ch);
+ const char *result = (ci != NULL) ? ci->name : NULL;
+ if (result != NULL)
+ string.cpy(result);
+ // if that doesn't work, convert to UTF-8
+ else if (ch > 0x7F || isprint(ch))
+ {
+ char buf[10];
+ int count = utf8_from_uchar(buf, ARRAY_LENGTH(buf), ch);
+ buf[count] = 0;
+ string.cpy(buf);
+ }
-/***************************************************************************
- PORT CHECKING
-***************************************************************************/
-
-
-/*-------------------------------------------------
- input_port_exists - return whether an input
- port exists
--------------------------------------------------*/
-
-bool input_port_exists(running_machine &machine, const char *tag)
-{
- return machine.root_device().ioport(tag) != 0;
+ // otherwise, opt for question marks
+ else
+ string.cpy("???");
+ return string;
}
-/*-------------------------------------------------
- input_port_active - return a bitmask of which
- bits of an input port are active (i.e. not
- unused or unknown)
--------------------------------------------------*/
+//-------------------------------------------------
+// execute_input - debugger command to enter
+// natural keyboard input
+//-------------------------------------------------
-input_port_value input_port_active(running_machine &machine, const char *tag)
+void natural_keyboard::execute_input(running_machine &machine, int ref, int params, const char *param[])
{
- const input_port_config *port = machine.root_device().ioport(tag);
- if (port == NULL)
- fatalerror("Unable to locate input port '%s'", tag);
- return port->active;
+ machine.ioport().natkeyboard().post_coded(param[0]);
}
-/*-------------------------------------------------
- input_port_active_safe - return a bitmask of
- which bits of an input port are active (i.e.
- not unused or unknown), or a default value if
- the port does not exist
--------------------------------------------------*/
+//-------------------------------------------------
+// execute_dumpkbd - debugger command to natural
+// keyboard codes
+//-------------------------------------------------
-input_port_value input_port_active_safe(running_machine &machine, const char *tag, input_port_value defvalue)
+void natural_keyboard::execute_dumpkbd(running_machine &machine, int ref, int params, const char *param[])
{
- const input_port_config *port = machine.root_device().ioport(tag);
- return port == NULL ? defvalue : port->active;
-}
+ // was there a file specified?
+ const char *filename = (params > 0) ? param[0] : NULL;
+ FILE *file = NULL;
+ if (filename != NULL)
+ {
+ // if so, open it
+ file = fopen(filename, "w");
+ if (file == NULL)
+ {
+ debug_console_printf(machine, "Cannot open \"%s\"\n", filename);
+ return;
+ }
+ }
+
+ // loop through all codes
+ natural_keyboard &natkeyboard = machine.ioport().natkeyboard();
+ dynamic_array<keycode_map_entry> &keycode_map = natkeyboard.m_keycode_map;
+ astring buffer, tempstr;
+ const size_t left_column_width = 24;
+ for (int index = 0; index < keycode_map.count(); index++)
+ {
+ // describe the character code
+ const keycode_map_entry &code = keycode_map[index];
+ buffer.printf("%08X (%s) ", code.ch, natkeyboard.unicode_to_string(tempstr, code.ch));
+ // pad with spaces
+ while (buffer.len() < left_column_width)
+ buffer.cat(' ');
+ // identify the keys used
+ for (int field = 0; field < ARRAY_LENGTH(code.field) && code.field[field] != 0; field++)
+ buffer.catprintf("%s'%s'", (field > 0) ? ", " : "", code.field[field]->name());
-/***************************************************************************
- PORT READING
-***************************************************************************/
+ // and output it as appropriate
+ if (file != NULL)
+ fprintf(file, "%s\n", buffer.cstr());
+ else
+ debug_console_printf(machine, "%s\n", buffer.cstr());
+ }
-/*-------------------------------------------------
- input_port_read_direct - return the value of
- an input port
--------------------------------------------------*/
+ // cleanup
+ if (file != NULL)
+ fclose(file);
+}
-input_port_value input_port_read_direct(const input_port_config *port)
-{
- assert(port != NULL);
- ioport_manager &portdata = port->machine().ioport();
- analog_field_state *analog;
- device_field_info *device_field;
- input_port_value result;
- assert_always(portdata.safe_to_read, "Input ports cannot be read at init time!");
+//**************************************************************************
+// I/O PORT CONDITION
+//**************************************************************************
- /* start with the digital */
- result = port->state->digital;
+//-------------------------------------------------
+// eval - evaluate condition
+//-------------------------------------------------
- /* update read values */
- for (device_field = port->state->readdevicelist; device_field != NULL; device_field = device_field->next)
- if (input_condition_true(port->machine(), &device_field->field->condition, port->owner()))
- {
- /* replace the bits with bits from the device */
- input_port_value newval = device_field->field->read(*device_field->field, device_field->field->read_param);
- device_field->oldval = newval;
- result = (result & ~device_field->field->mask) | ((newval << device_field->shift) & device_field->field->mask);
- }
+bool ioport_condition::eval(device_t &device) const
+{
+ // always condition is always true
+ if (m_condition == ALWAYS)
+ return true;
- /* update VBLANK bits */
- if (port->state->vblank != 0)
+ // otherwise, read the referenced port and switch off the condition type
+ ioport_value condvalue = device.ioport(m_tag)->read();
+ switch (m_condition)
{
- if (port->machine().primary_screen->vblank())
- result |= port->state->vblank;
- else
- result &= ~port->state->vblank;
+ case ALWAYS: return true;
+ case EQUALS: return ((condvalue & m_mask) == m_value);
+ case NOTEQUALS: return ((condvalue & m_mask) != m_value);
+ case GREATERTHAN: return ((condvalue & m_mask) > m_value);
+ case NOTGREATERTHAN: return ((condvalue & m_mask) <= m_value);
+ case LESSTHAN: return ((condvalue & m_mask) < m_value);
+ case NOTLESSTHAN: return ((condvalue & m_mask) >= m_value);
}
+ return true;
+}
- /* apply active high/low state to digital, read, and VBLANK inputs */
- result ^= port->state->defvalue;
-
- /* merge in analog portions */
- for (analog = port->state->analoglist; analog != NULL; analog = analog->next)
- if (input_condition_true(port->machine(), &analog->field->condition, port->owner()))
- {
- /* start with the raw value */
- INT32 value = analog->accum;
- /* interpolate if appropriate and if time has passed since the last update */
- if (analog->interpolate && !(analog->field->flags & ANALOG_FLAG_RESET) && portdata.last_delta_nsec != 0)
- {
- attoseconds_t nsec_since_last = (port->machine().time() - portdata.last_frame_time).as_attoseconds() / ATTOSECONDS_PER_NANOSECOND;
- value = analog->previous + ((INT64)(analog->accum - analog->previous) * nsec_since_last / portdata.last_delta_nsec);
- }
- /* apply standard analog settings */
- value = apply_analog_settings(value, analog);
+//**************************************************************************
+// I/O PORT SETTING
+//**************************************************************************
- /* remap the value if needed */
- if (analog->field->remap_table != NULL)
- value = analog->field->remap_table[value];
+//-------------------------------------------------
+// ioport_setting - constructor
+//-------------------------------------------------
- /* invert bits if needed */
- if (analog->field->flags & ANALOG_FLAG_INVERT)
- value = ~value;
+ioport_setting::ioport_setting(ioport_field &field, ioport_value _value, const char *_name)
+ : m_next(NULL),
+ m_field(field),
+ m_value(_value),
+ m_name(_name)
+{
+}
- /* insert into the port */
- result = (result & ~analog->field->mask) | ((value << analog->shift) & analog->field->mask);
- }
- return result;
-}
+//**************************************************************************
+// I/O PORT DIP LOCATION
+//**************************************************************************
-/*-------------------------------------------------
- input_port_read - return the value of
- an input port specified by tag
--------------------------------------------------*/
+//-------------------------------------------------
+// ioport_diplocation - constructor
+//-------------------------------------------------
-input_port_value input_port_read(running_machine &machine, const char *tag)
+ioport_diplocation::ioport_diplocation(const char *name, UINT8 swnum, bool invert)
+ : m_next(NULL),
+ m_name(name),
+ m_number(swnum),
+ m_invert(invert)
{
- const input_port_config *port = machine.root_device().ioport(tag);
- if (port == NULL)
- fatalerror("Unable to locate input port '%s'", tag);
- return input_port_read_direct(port);
}
-/*-------------------------------------------------
- input_port_read - return the value of
- a device input port specified by tag
--------------------------------------------------*/
-input_port_value input_port_read(device_t &device, const char *tag)
-{
- const input_port_config *port = device.ioport(tag);
- if (port == NULL)
- fatalerror("Unable to locate input port '%s'", tag);
- return input_port_read_direct(port);
+//**************************************************************************
+// I/O PORT FIELD
+//**************************************************************************
+
+//-------------------------------------------------
+// ioport_field - constructor
+//-------------------------------------------------
+
+ioport_field::ioport_field(ioport_port &port, ioport_type type, ioport_value defvalue, ioport_value maskbits, const char *name)
+ : m_next(NULL),
+ m_port(port),
+ m_live(NULL),
+ m_modcount(port.modcount()),
+ m_mask(maskbits),
+ m_defvalue(defvalue & maskbits),
+ m_type(type),
+ m_player(0),
+ m_flags(0),
+ m_impulse(0),
+ m_name(name),
+ m_read_param(NULL),
+ m_write_param(NULL),
+ m_min(0),
+ m_max(maskbits),
+ m_sensitivity(0),
+ m_delta(0),
+ m_centerdelta(0),
+ m_crosshair_axis(CROSSHAIR_AXIS_NONE),
+ m_crosshair_scale(1.0),
+ m_crosshair_offset(0),
+ m_crosshair_altaxis(0),
+ m_full_turn_count(0),
+ m_remap_table(NULL),
+ m_way(0)
+{
+ // reset sequences and chars
+ for (input_seq_type seqtype = SEQ_TYPE_STANDARD; seqtype < SEQ_TYPE_TOTAL; seqtype++)
+ m_seq[seqtype].set_default();
+ m_chars[0] = m_chars[1] = m_chars[2] = unicode_char(0);
+
+ // for DIP switches and configs, look for a default value from the owner
+ if (type == IPT_DIPSWITCH || type == IPT_CONFIG)
+ {
+ const input_device_default *def = device().input_ports_defaults();
+ if (def != NULL)
+ {
+ const char *fulltag = port.tag();
+ astring fullpath;
+ for ( ; def->tag != NULL; def++)
+ if (device().subtag(fullpath, def->tag) == fulltag && def->mask == m_mask)
+ m_defvalue = def->defvalue & m_mask;
+ }
+ }
}
-/*-------------------------------------------------
- input_port_read_safe - return the value of
- an input port specified by tag, or a default
- value if the port does not exist
--------------------------------------------------*/
+//-------------------------------------------------
+// ~ioport_field - destructor
+//-------------------------------------------------
-input_port_value input_port_read_safe(running_machine &machine, const char *tag, UINT32 defvalue)
+ioport_field::~ioport_field()
{
- const input_port_config *port = machine.root_device().ioport(tag);
- return (port == NULL) ? defvalue : input_port_read_direct(port);
+ global_free(m_live);
}
-/*-------------------------------------------------
- input_port_read_crosshair - return the
- extracted crosshair values for the given
- player
--------------------------------------------------*/
+//-------------------------------------------------
+// name - return the field name for a given input
+// field
+//-------------------------------------------------
-int input_port_get_crosshair_position(running_machine &machine, int player, float *x, float *y)
+const char *ioport_field::name() const
{
- const input_port_config *port;
- const input_field_config *field;
- int gotx = FALSE, goty = FALSE;
+ // if we have a non-default name, use that
+ if (m_live != NULL && m_live->name)
+ return m_live->name;
+ if (m_name != NULL)
+ return m_name;
- /* read all the lightgun values */
- for (port = machine.ioport().first_port(); port != NULL; port = port->next())
- for (field = port->first_field(); field != NULL; field = field->next())
- if (field->player == player && field->crossaxis != CROSSHAIR_AXIS_NONE)
- if (input_condition_true(machine, &field->condition, port->owner()))
- {
- analog_field_state *analog = field->state->analog;
- INT32 rawvalue = apply_analog_settings(analog->accum, analog) & (analog->field->mask >> analog->shift);
- float value = (float)(rawvalue - field->state->analog->adjmin) / (float)(field->state->analog->adjmax - field->state->analog->adjmin);
+ // otherwise, return the name associated with the type
+ return machine().ioport().type_name(m_type, m_player);
+}
- /* apply the scale and offset */
- if (field->crossscale < 0)
- value = -(1.0 - value) * field->crossscale;
- else
- value *= field->crossscale;
- value += field->crossoffset;
- /* apply custom mapping if necessary */
- if (!field->crossmapper.isnull())
- value = field->crossmapper(*field, value);
+//-------------------------------------------------
+// seq - return the input sequence for the given
+// input field
+//-------------------------------------------------
- /* handle X axis */
- if (field->crossaxis == CROSSHAIR_AXIS_X)
- {
- *x = value;
- gotx = TRUE;
- if (field->crossaltaxis != 0)
- {
- *y = field->crossaltaxis;
- goty = TRUE;
- }
- }
+const input_seq &ioport_field::seq(input_seq_type seqtype) const
+{
+ // if the field is disabled, return no key
+ if (m_flags & FIELD_FLAG_UNUSED)
+ return input_seq::empty_seq;
- /* handle Y axis */
- else
- {
- *y = value;
- goty = TRUE;
- if (field->crossaltaxis != 0)
- {
- *x = field->crossaltaxis;
- gotx = TRUE;
- }
- }
+ // select either the live or config state depending on whether we have live state
+ const input_seq &portseq = (m_live == NULL) ? m_seq[seqtype] : m_live->seq[seqtype];
- /* if we got both, stop */
- if (gotx && goty)
- break;
- }
+ // if the portseq is the special default code, return the expanded default value
+ if (portseq.is_default())
+ return machine().ioport().type_seq(m_type, m_player, seqtype);
- return (gotx && goty);
+ // otherwise, return the sequence as-is
+ return portseq;
}
-/*-------------------------------------------------
- input_port_update_defaults - force an update
- to the input port values based on current
- conditions
--------------------------------------------------*/
+//-------------------------------------------------
+// type_class - return the type class for this
+// field
+//-------------------------------------------------
-void input_port_update_defaults(running_machine &machine)
+ioport_type_class ioport_field::type_class() const
{
- int loopnum;
+ ioport_type_class result;
- /* two passes to catch conditionals properly */
- for (loopnum = 0; loopnum < 2; loopnum++)
+ switch (m_type)
{
- const input_port_config *port;
+ case IPT_JOYSTICK_UP:
+ case IPT_JOYSTICK_DOWN:
+ case IPT_JOYSTICK_LEFT:
+ case IPT_JOYSTICK_RIGHT:
+ case IPT_JOYSTICKLEFT_UP:
+ case IPT_JOYSTICKLEFT_DOWN:
+ case IPT_JOYSTICKLEFT_LEFT:
+ case IPT_JOYSTICKLEFT_RIGHT:
+ case IPT_JOYSTICKRIGHT_UP:
+ case IPT_JOYSTICKRIGHT_DOWN:
+ case IPT_JOYSTICKRIGHT_LEFT:
+ case IPT_JOYSTICKRIGHT_RIGHT:
+ case IPT_BUTTON1:
+ case IPT_BUTTON2:
+ case IPT_BUTTON3:
+ case IPT_BUTTON4:
+ case IPT_BUTTON5:
+ case IPT_BUTTON6:
+ case IPT_BUTTON7:
+ case IPT_BUTTON8:
+ case IPT_BUTTON9:
+ case IPT_BUTTON10:
+ case IPT_AD_STICK_X:
+ case IPT_AD_STICK_Y:
+ case IPT_AD_STICK_Z:
+ case IPT_TRACKBALL_X:
+ case IPT_TRACKBALL_Y:
+ case IPT_LIGHTGUN_X:
+ case IPT_LIGHTGUN_Y:
+ case IPT_MOUSE_X:
+ case IPT_MOUSE_Y:
+ case IPT_START:
+ case IPT_SELECT:
+ result = INPUT_CLASS_CONTROLLER;
+ break;
- /* loop over all input ports */
- for (port = machine.ioport().first_port(); port != NULL; port = port->next())
- {
- const input_field_config *field;
+ case IPT_KEYPAD:
+ case IPT_KEYBOARD:
+ result = INPUT_CLASS_KEYBOARD;
+ break;
- /* only clear on the first pass */
- if (loopnum == 0)
- port->state->defvalue = 0;
+ case IPT_CONFIG:
+ result = INPUT_CLASS_CONFIG;
+ break;
- /* first compute the default value for the entire port */
- for (field = port->first_field(); field != NULL; field = field->next())
- if (input_condition_true(machine, &field->condition, port->owner()))
- port->state->defvalue = (port->state->defvalue & ~field->mask) | (field->state->value & field->mask);
- }
+ case IPT_DIPSWITCH:
+ result = INPUT_CLASS_DIPSWITCH;
+ break;
+
+ case 0:
+ if (m_name != NULL && m_name != (const char *)-1)
+ result = INPUT_CLASS_MISC;
+ else
+ result = INPUT_CLASS_INTERNAL;
+ break;
+
+ default:
+ result = INPUT_CLASS_INTERNAL;
+ break;
}
+ return result;
}
-/*-------------------------------------------------
- apply_analog_settings - return the value of
- an input port
--------------------------------------------------*/
+//-------------------------------------------------
+// keyboard_code - accesses a particular keyboard
+// code
+//-------------------------------------------------
-static INT32 apply_analog_settings(INT32 value, analog_field_state *analog)
+unicode_char ioport_field::keyboard_code(int which) const
{
- /* apply the min/max and then the sensitivity */
- value = apply_analog_min_max(analog, value);
- value = APPLY_SENSITIVITY(value, analog->sensitivity);
+ unicode_char ch = m_chars[which];
- /* apply reversal if needed */
- if (analog->reverse)
- value = analog->reverse_val - value;
- else if (analog->single_scale)
- /* it's a pedal or the default value is equal to min/max */
- /* so we need to adjust the center to the minimum */
- value -= INPUT_ABSOLUTE_MIN;
-
- /* map differently for positive and negative values */
- if (value >= 0)
- value = APPLY_SCALE(value, analog->scalepos);
- else
- value = APPLY_SCALE(value, analog->scaleneg);
- value += analog->adjdefvalue;
-
- return value;
+ // special hack to allow for PORT_CODE('\xA3')
+ if (ch >= 0xffffff80 && ch <= 0xffffffff)
+ ch &= 0xff;
+ return ch;
}
-/***************************************************************************
- PORT WRITING
-***************************************************************************/
-
-/*-------------------------------------------------
- input_port_write_direct - write a value
- to a port
--------------------------------------------------*/
+//-------------------------------------------------
+// get_user_settings - return the current
+// settings for the given input field
+//-------------------------------------------------
-void input_port_write_direct(const input_port_config *port, input_port_value data, input_port_value mem_mask)
+void ioport_field::get_user_settings(user_settings &settings)
{
- /* call device line write handlers */
- device_field_info *device_field;
+ // zap the entire structure
+ memset(&settings, 0, sizeof(settings));
- COMBINE_DATA(&port->state->outputvalue);
+ // copy the basics
+ for (input_seq_type seqtype = SEQ_TYPE_STANDARD; seqtype < SEQ_TYPE_TOTAL; seqtype++)
+ settings.seq[seqtype] = m_live->seq[seqtype];
- for (device_field = port->state->writedevicelist; device_field; device_field = device_field->next)
- if (device_field->field->type == IPT_OUTPUT && input_condition_true(port->machine(), &device_field->field->condition, port->owner()))
- {
- input_port_value newval = ( (port->state->outputvalue ^ device_field->field->defvalue ) & device_field->field->mask) >> device_field->shift;
-
- /* if the bits have write, call the handler */
- if (device_field->oldval != newval)
- {
- device_field->field->write(*device_field->field, device_field->field->write_param, device_field->oldval, newval);
+ // if there's a list of settings or we're an adjuster, copy the current value
+ if (first_setting() != NULL || m_type == IPT_ADJUSTER)
+ settings.value = m_live->value;
- device_field->oldval = newval;
- }
- }
+ // if there's analog data, extract the analog settings
+ if (m_live->analog != NULL)
+ {
+ settings.sensitivity = m_live->analog->sensitivity();
+ settings.delta = m_live->analog->delta();
+ settings.centerdelta = m_live->analog->centerdelta();
+ settings.reverse = m_live->analog->reverse();
+ }
}
-/*-------------------------------------------------
- input_port_write - write a value to a
- port specified by tag
--------------------------------------------------*/
+//-------------------------------------------------
+// set_user_settings - modify the current
+// settings for the given input field
+//-------------------------------------------------
-void input_port_write(running_machine &machine, const char *tag, input_port_value value, input_port_value mask)
+void ioport_field::set_user_settings(const user_settings &settings)
{
- const input_port_config *port = machine.root_device().ioport(tag);
- if (port == NULL)
- fatalerror("Unable to locate input port '%s'", tag);
- input_port_write_direct(port, value, mask);
-}
-
+ // copy the basics
+ for (input_seq_type seqtype = SEQ_TYPE_STANDARD; seqtype < SEQ_TYPE_TOTAL; seqtype++)
+ {
+ const input_seq &defseq = manager().type_seq(m_type, m_player, input_seq_type(seqtype));
+ if (defseq == settings.seq[seqtype])
+ m_live->seq[seqtype].set_default();
+ else
+ m_live->seq[seqtype] = settings.seq[seqtype];
+ }
-/*-------------------------------------------------
- input_port_write_safe - write a value to
- a port, ignore if the port does not exist
--------------------------------------------------*/
+ // if there's a list of settings or we're an adjuster, copy the current value
+ if (first_setting() != NULL || m_type == IPT_ADJUSTER)
+ m_live->value = settings.value;
-void input_port_write_safe(running_machine &machine, const char *tag, input_port_value value, input_port_value mask)
-{
- const input_port_config *port = machine.root_device().ioport(tag);
- if (port != NULL)
- input_port_write_direct(port, value, mask);
+ // if there's analog data, extract the analog settings
+ if (m_live->analog != NULL)
+ {
+ m_live->analog->m_sensitivity = settings.sensitivity;
+ m_live->analog->m_delta = settings.delta;
+ m_live->analog->m_centerdelta = settings.centerdelta;
+ m_live->analog->m_reverse = settings.reverse;
+ }
}
+//-------------------------------------------------
+// setting_name - return the expanded setting
+// name for a field
+//-------------------------------------------------
-/***************************************************************************
- MISC HELPER FUNCTIONS
-***************************************************************************/
-
-/*-------------------------------------------------
- input_condition_true - return the TRUE
- if the given condition attached is true
--------------------------------------------------*/
-
-int input_condition_true(running_machine &machine, const input_condition *condition, device_t &owner)
+const char *ioport_field::setting_name() const
{
- input_port_value condvalue;
-
- /* always condition is always true */
- if (condition->condition == PORTCOND_ALWAYS)
- return TRUE;
+ // only makes sense if we have settings
+ assert(first_setting() != NULL);
- /* otherwise, read the referenced port */
- astring conditiontag;
- owner.subtag(conditiontag, condition->tag);
- condvalue = input_port_read(machine, conditiontag.cstr());
+ // scan the list of settings looking for a match on the current value
+ for (ioport_setting *setting = first_setting(); setting != NULL; setting = setting->next())
+ if (setting->enabled())
+ if (setting->value() == m_live->value)
+ return setting->name();
- /* based on the condition encoded, determine truth */
- switch (condition->condition)
- {
- case PORTCOND_EQUALS:
- return ((condvalue & condition->mask) == condition->value);
+ return "INVALID";
+}
- case PORTCOND_NOTEQUALS:
- return ((condvalue & condition->mask) != condition->value);
- case PORTCOND_GREATERTHAN:
- return ((condvalue & condition->mask) > condition->value);
+//-------------------------------------------------
+// has_previous_setting - return true if the
+// given field has a "previous" setting
+//-------------------------------------------------
- case PORTCOND_NOTGREATERTHAN:
- return ((condvalue & condition->mask) <= condition->value);
+bool ioport_field::has_previous_setting() const
+{
+ // only makes sense if we have settings
+ assert(first_setting() != NULL);
- case PORTCOND_LESSTHAN:
- return ((condvalue & condition->mask) < condition->value);
+ // scan the list of settings looking for a match on the current value
+ for (ioport_setting *setting = first_setting(); setting != NULL; setting = setting->next())
+ if (setting->enabled())
+ return (setting->value() != m_live->value);
- case PORTCOND_NOTLESSTHAN:
- return ((condvalue & condition->mask) >= condition->value);
- }
- return TRUE;
+ return false;
}
-/*-------------------------------------------------
- input_port_string_from_token - convert an
- input_port_token to a default string
--------------------------------------------------*/
+//-------------------------------------------------
+// select_previous_setting - select the previous
+// item for a DIP switch or configuration field
+//-------------------------------------------------
-const char *input_port_string_from_token(const char *string)
+void ioport_field::select_previous_setting()
{
- /* 0 is an invalid index */
- if (string == NULL)
- return NULL;
-
- /* if the index is greater than the count, assume it to be a pointer */
- if (FPTR(string) >= INPUT_STRING_COUNT)
- return string;
+ // only makes sense if we have settings
+ assert(first_setting() != NULL);
-#if FALSE // Set TRUE, If you want to take care missing-token or wrong-sorting
+ // scan the list of settings looking for a match on the current value
+ ioport_setting *prevsetting = NULL;
+ bool found_match = false;
+ for (ioport_setting *setting = first_setting(); setting != NULL; setting = setting->next())
+ if (setting->enabled())
+ {
+ if (setting->value() == m_live->value)
+ {
+ found_match = true;
+ if (prevsetting != NULL)
+ break;
+ }
+ prevsetting = setting;
+ }
- /* otherwise, scan the list for a matching string and return it */
+ // if we didn't find a matching value, select the first
+ if (!found_match)
{
- int index;
- for (index = 0; index < ARRAY_LENGTH(input_port_default_strings); index++)
- if (input_port_default_strings[index].id == FPTR(string))
- return input_port_default_strings[index].string;
+ for (prevsetting = first_setting(); prevsetting != NULL; prevsetting = prevsetting->next())
+ if (prevsetting->enabled())
+ break;
}
- return "(Unknown Default)";
-
-#else
-
- return input_port_default_strings[FPTR(string)-1].string;
-#endif
+ // update the value to the previous one
+ if (prevsetting != NULL)
+ m_live->value = prevsetting->value();
}
+//-------------------------------------------------
+// has_next_setting - return true if the given
+// field has a "next" setting
+//-------------------------------------------------
-/***************************************************************************
- INITIALIZATION HELPERS
-***************************************************************************/
-
-/*-------------------------------------------------
- init_port_types - initialize the default
- type list
--------------------------------------------------*/
-
-static void init_port_types(running_machine &machine)
+bool ioport_field::has_next_setting() const
{
- ioport_manager &portdata = machine.ioport();
+ // only makes sense if we have settings
+ assert(first_setting() != NULL);
- /* convert the array into a list of type states that can be modified */
- construct_core_types(portdata.typelist);
-
- /* ask the OSD to customize the list */
- machine.osd().customize_input_type_list(portdata.typelist);
-
- /* now iterate over the OSD-modified types */
- for (input_type_entry *curtype = portdata.typelist.first(); curtype != NULL; curtype = curtype->next())
- {
- /* first copy all the OSD-updated sequences into our current state */
- for (int seqtype = 0; seqtype < ARRAY_LENGTH(curtype->seq); seqtype++)
- curtype->seq[seqtype] = curtype->defseq[seqtype];
+ // scan the list of settings looking for a match on the current value
+ bool found = false;
+ for (ioport_setting *setting = first_setting(); setting != NULL; setting = setting->next())
+ if (setting->enabled())
+ {
+ if (found)
+ return true;
+ if (setting->value() == m_live->value)
+ found = true;
+ }
- /* also make a lookup table mapping type/player to the appropriate type list entry */
- portdata.type_to_entry[curtype->type][curtype->player] = curtype;
- }
+ return false;
}
-/*-------------------------------------------------
- get_keyboard_code - accesses a particular
- keyboard code
--------------------------------------------------*/
+//-------------------------------------------------
+// select_next_setting - select the next item for
+// a DIP switch or configuration field
+//-------------------------------------------------
-static unicode_char get_keyboard_code(const input_field_config *field, int i)
+void ioport_field::select_next_setting()
{
- unicode_char ch = field->chars[i];
+ // only makes sense if we have settings
+ assert(first_setting() != NULL);
- /* special hack to allow for PORT_CODE('\xA3') */
- if ((ch >= 0xFFFFFF80) && (ch <= 0xFFFFFFFF))
- ch &= 0xFF;
- return ch;
-}
+ // scan the list of settings looking for a match on the current value
+ ioport_setting *nextsetting = NULL;
+ ioport_setting *setting;
+ for (setting = first_setting(); setting != NULL; setting = setting->next())
+ if (setting->enabled())
+ if (setting->value() == m_live->value)
+ break;
+ // if we found one, scan forward for the next valid one
+ if (setting != NULL)
+ for (nextsetting = setting->next(); nextsetting != NULL; nextsetting = nextsetting->next())
+ if (nextsetting->enabled())
+ break;
-/***************************************************************************
- MISCELLANEOUS
-***************************************************************************/
+ // if we hit the end, search from the beginning
+ if (nextsetting == NULL)
+ for (nextsetting = first_setting(); nextsetting != NULL; nextsetting = nextsetting->next())
+ if (nextsetting->enabled())
+ break;
+
+ // update the value to the previous one
+ if (nextsetting != NULL)
+ m_live->value = nextsetting->value();
+}
-/*-------------------------------------------------
- find_charinfo - looks up information about a
- particular character
--------------------------------------------------*/
-static const char_info *find_charinfo(unicode_char target_char)
+//-------------------------------------------------
+// frame_update_digital - get the state of a
+// digital field
+//-------------------------------------------------
+
+void ioport_field::frame_update(ioport_value &result, bool mouse_down)
{
- int low = 0;
- int high = ARRAY_LENGTH(charinfo);
- int i;
- unicode_char ch;
+ // skip if not enabled
+ if (!enabled())
+ return;
- /* perform a simple binary search to find the proper alternate */
- while(high > low)
+ // handle analog inputs first
+ if (m_live->analog != NULL)
{
- i = (high + low) / 2;
- ch = charinfo[i].ch;
- if (ch < target_char)
- low = i + 1;
- else if (ch > target_char)
- high = i;
- else
- return &charinfo[i];
+ m_live->analog->frame_update(machine());
+ return;
}
- return NULL;
-}
-
-/*-------------------------------------------------
- inputx_key_name - returns the name of a
- specific key
--------------------------------------------------*/
+
+ // if UI is active, ignore digital inputs
+ if (ui_is_menu_active())
+ return;
-static const char *inputx_key_name(unicode_char ch)
-{
- static char buf[UTF8_CHAR_MAX + 1];
- const char_info *ci;
- const char *result;
- int pos;
+ // if the state changed, look for switch down/switch up
+ bool curstate = mouse_down || machine().input().seq_pressed(seq());
+ bool changed = false;
+ if (curstate != m_live->last)
+ {
+ m_live->last = curstate;
+ changed = true;
+ }
- ci = find_charinfo(ch);
- result = ci ? ci->name : NULL;
+ // if we're a keyboard type and using natural keyboard, bail
+ if (m_type == IPT_KEYBOARD && ui_get_use_natural_keyboard(machine()))
+ return;
- if (ci && ci->name)
+ // coin impulse option
+ int effective_impulse = m_impulse;
+ int impulse_option_val = machine().options().coin_impulse();
+ if (impulse_option_val != 0)
{
- result = ci->name;
+ if (impulse_option_val < 0)
+ effective_impulse = 0;
+ else if ((m_type >= IPT_COIN1 && m_type <= IPT_COIN12) || m_impulse != 0)
+ effective_impulse = impulse_option_val;
}
- else
+
+ // if this is a switch-down event, handle impulse and toggle
+ if (changed && curstate)
{
- if ((ch > 0x7F) || isprint(ch))
+ // impluse controls: reset the impulse counter
+ if (effective_impulse != 0 && m_live->impulse == 0)
+ m_live->impulse = effective_impulse;
+
+ // toggle controls: flip the toggle state or advance to the next setting
+ if (toggle())
{
- pos = utf8_from_uchar(buf, ARRAY_LENGTH(buf), ch);
- buf[pos] = '\0';
- result = buf;
+ if (m_settinglist.count() == 0)
+ m_live->value ^= m_mask;
+ else
+ select_next_setting();
}
- else
- result = "???";
}
- return result;
-}
-/*-------------------------------------------------
- get_keyboard_key_name - builds the name of
- a key based on natural keyboard characters
--------------------------------------------------*/
-
-static astring &get_keyboard_key_name(astring &name, const input_field_config *field)
-{
- int i;
- unicode_char ch;
-
- name.reset();
- /* loop through each character on the field*/
- for (i = 0; i < ARRAY_LENGTH(field->chars) && (field->chars[i] != '\0'); i++)
+ // update the current state with the impulse state
+ if (effective_impulse != 0)
{
- ch = get_keyboard_code(field, i);
- name.catprintf("%-*s ", MAX(SPACE_COUNT - 1, 0), inputx_key_name(ch));
+ curstate = (m_live->impulse != 0);
+ if (curstate)
+ m_live->impulse--;
}
- /* trim extra spaces */
- name.trimspace();
-
- /* special case */
- if (name.len() == 0)
- name.cpy("Unnamed Key");
-
- return name;
-}
-
-/*-------------------------------------------------
- init_port_state - initialize the live port
- states based on the tokens
--------------------------------------------------*/
+ // for toggle switches, the current value is folded into the port's default value
+ // so we always return FALSE here
+ if (toggle())
+ curstate = false;
-static void init_port_state(running_machine &machine)
-{
- const char *joystick_map_default = machine.options().joystick_map();
- ioport_manager &portdata = machine.ioport();
- input_field_config *field;
- input_port_config *port;
+ // additional logic to restrict digital joysticks
+ if (curstate && !mouse_down && m_live->joystick != NULL && m_way != 16 && !machine().options().joystick_contradictory())
+ {
+ UINT8 mask = (m_way == 4) ? m_live->joystick->current4way() : m_live->joystick->current();
+ if (!(mask & (1 << m_live->joydir)))
+ curstate = false;
+ }
- /* allocate live structures to mirror the configuration */
- for (port = machine.ioport().first_port(); port != NULL; port = port->next())
+ // skip locked-out coin inputs
+ if (curstate && m_type >= IPT_COIN1 && m_type <= IPT_COIN12 && coin_lockout_get_state(machine(), m_type - IPT_COIN1))
{
- analog_field_state **analogstatetail;
- device_field_info **readdevicetail;
- device_field_info **writedevicetail;
- input_port_state *portstate;
-
- /* allocate a new input_port_info structure */
- portstate = auto_alloc_clear(machine, input_port_state);
- ((input_port_config *)port)->state = portstate;
-
- /* start with tail pointers to all the data */
- analogstatetail = &portstate->analoglist;
- readdevicetail = &portstate->readdevicelist;
- writedevicetail = &portstate->writedevicelist;
-
- /* iterate over fields */
- for (field = port->first_field(); field != NULL; field = field->next())
+ bool verbose = machine().options().verbose();
+#ifdef MAME_DEBUG
+ verbose = true;
+#endif
+ if (machine().options().coin_lockout())
{
- input_field_state *fieldstate;
- int seqtype;
-
- /* allocate a new input_field_info structure */
- fieldstate = auto_alloc_clear(machine, input_field_state);
- ((input_field_config *)field)->state = fieldstate;
-
- /* fill in the basic values */
- for (seqtype = 0; seqtype < ARRAY_LENGTH(fieldstate->seq); seqtype++)
- fieldstate->seq[seqtype] = field->seq[seqtype];
- fieldstate->value = field->defvalue;
-
- /* if this is an analog field, allocate memory for the analog data */
- if (field->type >= __ipt_analog_start && field->type <= __ipt_analog_end)
- {
- *analogstatetail = fieldstate->analog = init_field_analog_state(field);
- analogstatetail = &(*analogstatetail)->next;
- }
-
- /* if this is a digital joystick field, make a note of it */
- if (field->type >= __ipt_digital_joystick_start && field->type <= __ipt_digital_joystick_end)
- {
- fieldstate->joystick = &portdata.joystick_info[field->player][(field->type - __ipt_digital_joystick_start) / 4];
- fieldstate->joydir = (field->type - __ipt_digital_joystick_start) % 4;
- fieldstate->joystick->field[fieldstate->joydir] = field;
- fieldstate->joystick->inuse = TRUE;
- }
-
- /* if this entry has device input, allocate memory for the tracking structure */
- astring devicetag;
- if (!field->read.isnull())
- {
- *readdevicetail = init_field_device_info(field, port->owner().subtag(devicetag, field->read_device));
- field->read.late_bind(*(*readdevicetail)->device);
- if (!field->read.has_object())
- fatalerror("Input port %s, unable to find valid device with tag '%s'", port->tag(), devicetag.cstr());
- readdevicetail = &(*readdevicetail)->next;
- }
-
- /* if this entry has device output, allocate memory for the tracking structure */
- if (!field->write.isnull())
- {
- *writedevicetail = init_field_device_info(field, port->owner().subtag(devicetag, field->write_device));
- field->write.late_bind(*(*writedevicetail)->device);
- if (!field->write.has_object())
- fatalerror("Input port %s, unable to find valid device with tag '%s'", port->tag(), devicetag.cstr());
- writedevicetail = &(*writedevicetail)->next;
- }
-
- /* if this entry has device output, allocate memory for the tracking structure */
- if (!field->crossmapper.isnull())
- {
- device_t *device = machine.device(port->owner().subtag(devicetag, field->crossmapper_device));
- field->crossmapper.late_bind(*device);
- }
-
- /* Name keyboard key names */
- if ((field->type == IPT_KEYBOARD || field->type == IPT_KEYPAD) && (field->name == NULL))
- {
- astring name;
- field->state->name = auto_strdup(machine, get_keyboard_key_name(name, field));
- }
+ if (verbose)
+ ui_popup_time(3, "Coinlock disabled %s.", name());
+ curstate = false;
}
+ else
+ if (verbose)
+ ui_popup_time(3, "Coinlock disabled, but broken through %s.", name());
}
- /* handle autoselection of devices */
- init_autoselect_devices(machine, IPT_AD_STICK_X, IPT_AD_STICK_Y, IPT_AD_STICK_Z, OPTION_ADSTICK_DEVICE, "analog joystick");
- init_autoselect_devices(machine, IPT_PADDLE, IPT_PADDLE_V, 0, OPTION_PADDLE_DEVICE, "paddle");
- init_autoselect_devices(machine, IPT_PEDAL, IPT_PEDAL2, IPT_PEDAL3, OPTION_PEDAL_DEVICE, "pedal");
- init_autoselect_devices(machine, IPT_LIGHTGUN_X, IPT_LIGHTGUN_Y, 0, OPTION_LIGHTGUN_DEVICE, "lightgun");
- init_autoselect_devices(machine, IPT_POSITIONAL, IPT_POSITIONAL_V, 0, OPTION_POSITIONAL_DEVICE, "positional");
- init_autoselect_devices(machine, IPT_DIAL, IPT_DIAL_V, 0, OPTION_DIAL_DEVICE, "dial");
- init_autoselect_devices(machine, IPT_TRACKBALL_X, IPT_TRACKBALL_Y, 0, OPTION_TRACKBALL_DEVICE, "trackball");
- init_autoselect_devices(machine, IPT_MOUSE_X, IPT_MOUSE_Y, 0, OPTION_MOUSE_DEVICE, "mouse");
-
- /* look for 4-way joysticks and change the default map if we find any */
- if (joystick_map_default[0] == 0 || strcmp(joystick_map_default, "auto") == 0)
- for (port = machine.ioport().first_port(); port != NULL; port = port->next())
- for (field = port->first_field(); field != NULL; field = field->next())
- if (field->state->joystick != NULL && field->way == 4)
- {
- machine.input().set_global_joystick_map((field->flags & FIELD_FLAG_ROTATED) ? joystick_map_4way_diagonal : joystick_map_4way_sticky);
- break;
- }
+ // if we're active, set the appropriate bits in the digital state
+ if (curstate)
+ result |= m_mask;
}
-/*-------------------------------------------------
- init_autoselect_devices - autoselect a single
- device based on the input port list passed
- in and the corresponding option
--------------------------------------------------*/
+//-------------------------------------------------
+// crosshair_position - compute the crosshair
+// position
+//-------------------------------------------------
-static void init_autoselect_devices(running_machine &machine, int type1, int type2, int type3, const char *option, const char *ananame)
+void ioport_field::crosshair_position(float &x, float &y, bool &gotx, bool &goty)
{
- const char *stemp = machine.options().value(option);
- input_device_class autoenable = DEVICE_CLASS_KEYBOARD;
- const char *autostring = "keyboard";
- const input_field_config *field;
- const input_port_config *port;
+ float value = m_live->analog->crosshair_read();
- /* if nothing specified, ignore the option */
- if (stemp[0] == 0)
- return;
+ // apply the scale and offset
+ if (m_crosshair_scale < 0)
+ value = -(1.0 - value) * m_crosshair_scale;
+ else
+ value *= m_crosshair_scale;
+ value += m_crosshair_offset;
- /* extract valid strings */
- if (strcmp(stemp, "mouse") == 0)
- {
- autoenable = DEVICE_CLASS_MOUSE;
- autostring = "mouse";
- }
- else if (strcmp(stemp, "joystick") == 0)
- {
- autoenable = DEVICE_CLASS_JOYSTICK;
- autostring = "joystick";
- }
- else if (strcmp(stemp, "lightgun") == 0)
+ // apply custom mapping if necessary
+ if (!m_crosshair_mapper.isnull())
+ value = m_crosshair_mapper(*this, value);
+
+ // handle X axis
+ if (m_crosshair_axis == CROSSHAIR_AXIS_X)
{
- autoenable = DEVICE_CLASS_LIGHTGUN;
- autostring = "lightgun";
+ x = value;
+ gotx = true;
+ if (m_crosshair_altaxis != 0)
+ {
+ y = m_crosshair_altaxis;
+ goty = true;
+ }
}
- else if (strcmp(stemp, "none") == 0)
+
+ // handle Y axis
+ else
{
- /* nothing specified */
- return;
+ y = value;
+ goty = true;
+ if (m_crosshair_altaxis != 0)
+ {
+ x = m_crosshair_altaxis;
+ gotx = true;
+ }
}
- else if (strcmp(stemp, "keyboard") != 0)
- mame_printf_error("Invalid %s value %s; reverting to keyboard\n", option, stemp);
-
- /* only scan the list if we haven't already enabled this class of control */
- if (machine.ioport().first_port() != NULL && !machine.input().device_class(autoenable).enabled())
- for (port = machine.ioport().first_port(); port != NULL; port = port->next())
- for (field = port->first_field(); field != NULL; field = field->next())
-
- /* if this port type is in use, apply the autoselect criteria */
- if ((type1 != 0 && field->type == type1) ||
- (type2 != 0 && field->type == type2) ||
- (type3 != 0 && field->type == type3))
- {
- mame_printf_verbose("Input: Autoenabling %s due to presence of a %s\n", autostring, ananame);
- machine.input().device_class(autoenable).enable();
- break;
- }
}
-/*-------------------------------------------------
- init_field_device_info - allocate and populate
- information about a device callback
--------------------------------------------------*/
+//-------------------------------------------------
+// expand_diplocation - expand a string-based
+// DIP location into a linked list of
+// descriptions
+//-------------------------------------------------
-static device_field_info *init_field_device_info(const input_field_config *field, const char *device_name)
+void ioport_field::expand_diplocation(const char *location, astring &errorbuf)
{
- device_field_info *info;
- input_port_value mask;
-
- /* allocate memory */
- info = auto_alloc_clear(field->machine(), device_field_info);
-
- /* fill in the data */
- info->field = field;
- for (mask = field->mask; !(mask & 1); mask >>= 1)
- info->shift++;
+ // if nothing present, bail
+ if (location == NULL)
+ return;
- info->device = (device_name != NULL) ? field->machine().device(device_name) : &field->port().owner();
+ m_diploclist.reset();
- info->oldval = field->defvalue >> info->shift;
- return info;
-}
+ // parse the string
+ astring name; // Don't move this variable inside the loop, lastname's lifetime depends on it being outside
+ const char *lastname = NULL;
+ const char *curentry = location;
+ int entries = 0;
+ while (*curentry != 0)
+ {
+ // find the end of this entry
+ const char *comma = strchr(curentry, ',');
+ if (comma == NULL)
+ comma = curentry + strlen(curentry);
+ // extract it to tempbuf
+ astring tempstr;
+ tempstr.cpy(curentry, comma - curentry);
-/*-------------------------------------------------
- init_field_analog_state - allocate and populate
- information about an analog port
--------------------------------------------------*/
+ // first extract the switch name if present
+ const char *number = tempstr;
+ const char *colon = strchr(tempstr, ':');
-static analog_field_state *init_field_analog_state(const input_field_config *field)
-{
- analog_field_state *state;
- input_port_value mask;
+ // allocate and copy the name if it is present
+ if (colon != NULL)
+ {
+ lastname = name.cpy(number, colon - number);
+ number = colon + 1;
+ }
- /* allocate memory */
- state = auto_alloc_clear(field->machine(), analog_field_state);
+ // otherwise, just copy the last name
+ else
+ {
+ if (lastname == NULL)
+ {
+ errorbuf.catprintf("Switch location '%s' missing switch name!\n", location);
+ lastname = (char *)"UNK";
+ }
+ name.cpy(lastname);
+ }
- /* compute the shift amount and number of bits */
- for (mask = field->mask; !(mask & 1); mask >>= 1)
- state->shift++;
+ // if the number is preceded by a '!' it's active high
+ bool invert = false;
+ if (*number == '!')
+ {
+ invert = true;
+ number++;
+ }
- /* initialize core data */
- state->field = field;
- state->adjdefvalue = (field->defvalue & field->mask) >> state->shift;
- state->adjmin = (field->min & field->mask) >> state->shift;
- state->adjmax = (field->max & field->mask) >> state->shift;
- state->sensitivity = field->sensitivity;
- state->reverse = ((field->flags & ANALOG_FLAG_REVERSE) != 0);
- state->delta = field->delta;
- state->centerdelta = field->centerdelta;
- state->minimum = INPUT_ABSOLUTE_MIN;
- state->maximum = INPUT_ABSOLUTE_MAX;
+ // now scan the switch number
+ int swnum = -1;
+ if (sscanf(number, "%d", &swnum) != 1)
+ errorbuf.catprintf("Switch location '%s' has invalid format!\n", location);
- /* set basic parameters based on the configured type */
- switch (field->type)
- {
- /* paddles and analog joysticks are absolute and autocenter */
- case IPT_AD_STICK_X:
- case IPT_AD_STICK_Y:
- case IPT_AD_STICK_Z:
- case IPT_PADDLE:
- case IPT_PADDLE_V:
- state->absolute = TRUE;
- state->autocenter = TRUE;
- state->interpolate = TRUE;
- break;
+ // allocate a new entry
+ m_diploclist.append(*global_alloc(ioport_diplocation(name, swnum, invert)));
+ entries++;
- /* pedals start at and autocenter to the min range */
- case IPT_PEDAL:
- case IPT_PEDAL2:
- case IPT_PEDAL3:
- state->center = INPUT_ABSOLUTE_MIN;
- state->accum = APPLY_INVERSE_SENSITIVITY(state->center, state->sensitivity);
- state->absolute = TRUE;
- state->autocenter = TRUE;
- state->interpolate = TRUE;
- break;
+ // advance to the next item
+ curentry = comma;
+ if (*curentry != 0)
+ curentry++;
+ }
- /* lightguns are absolute as well, but don't autocenter and don't interpolate their values */
- case IPT_LIGHTGUN_X:
- case IPT_LIGHTGUN_Y:
- state->absolute = TRUE;
- state->autocenter = FALSE;
- state->interpolate = FALSE;
- break;
+ // then verify the number of bits in the mask matches
+ ioport_value temp;
+ int bits;
+ for (bits = 0, temp = m_mask; temp != 0 && bits < 32; bits++)
+ temp &= temp - 1;
+ if (bits != entries)
+ errorbuf.catprintf("Switch location '%s' does not describe enough bits for mask %X\n", location, m_mask);
+}
- /* positional devices are absolute, but can also wrap like relative devices */
- /* set each position to be 512 units */
- case IPT_POSITIONAL:
- case IPT_POSITIONAL_V:
- state->positionalscale = COMPUTE_SCALE(field->max, INPUT_ABSOLUTE_MAX - INPUT_ABSOLUTE_MIN);
- state->adjmin = 0;
- state->adjmax = field->max - 1;
- state->wraps = ((field->flags & ANALOG_FLAG_WRAPS) != 0);
- state->autocenter = !state->wraps;
- break;
- /* dials, mice and trackballs are relative devices */
- /* these have fixed "min" and "max" values based on how many bits are in the port */
- /* in addition, we set the wrap around min/max values to 512 * the min/max values */
- /* this takes into account the mapping that one mouse unit ~= 512 analog units */
- case IPT_DIAL:
- case IPT_DIAL_V:
- case IPT_TRACKBALL_X:
- case IPT_TRACKBALL_Y:
- case IPT_MOUSE_X:
- case IPT_MOUSE_Y:
- state->absolute = FALSE;
- state->wraps = TRUE;
- state->interpolate = TRUE;
- break;
+//-------------------------------------------------
+// init_live_state - create live state structures
+//-------------------------------------------------
- default:
- fatalerror("Unknown analog port type -- don't know if it is absolute or not");
- break;
- }
+void ioport_field::init_live_state(analog_field *analog)
+{
+ // resolve callbacks
+ m_read.bind_relative_to(device());
+ m_write.bind_relative_to(device());
+ m_crosshair_mapper.bind_relative_to(device());
- /* further processing for absolute controls */
- if (state->absolute)
- {
- /* if the default value is pegged at the min or max, use a single scale value for the whole axis */
- state->single_scale = (state->adjdefvalue == state->adjmin) || (state->adjdefvalue == state->adjmax);
+ // allocate live state
+ m_live = global_alloc(ioport_field_live(*this, analog));
+}
- /* if not "single scale", compute separate scales for each side of the default */
- if (!state->single_scale)
- {
- /* unsigned */
- state->scalepos = COMPUTE_SCALE(state->adjmax - state->adjdefvalue, INPUT_ABSOLUTE_MAX - 0);
- state->scaleneg = COMPUTE_SCALE(state->adjdefvalue - state->adjmin, 0 - INPUT_ABSOLUTE_MIN);
- if (state->adjmin > state->adjmax)
- state->scaleneg = -state->scaleneg;
- /* reverse point is at center */
- state->reverse_val = 0;
- }
- else
- {
- /* single axis that increases from default */
- state->scalepos = COMPUTE_SCALE(state->adjmax - state->adjmin, INPUT_ABSOLUTE_MAX - INPUT_ABSOLUTE_MIN);
+//**************************************************************************
+// I/O PORT FIELD LIVE
+//**************************************************************************
- /* move from default */
- if (state->adjdefvalue == state->adjmax)
- state->scalepos = -state->scalepos;
+//-------------------------------------------------
+// ioport_field_live - constructor
+//-------------------------------------------------
- /* make the scaling the same for easier coding when we need to scale */
- state->scaleneg = state->scalepos;
+ioport_field_live::ioport_field_live(ioport_field &field, analog_field *analog)
+ : analog(analog),
+ joystick(NULL),
+ value(field.defvalue()),
+ impulse(0),
+ last(0),
+ joydir(digital_joystick::JOYDIR_COUNT)
+{
+ // fill in the basic values
+ for (input_seq_type seqtype = SEQ_TYPE_STANDARD; seqtype < SEQ_TYPE_TOTAL; seqtype++)
+ seq[seqtype] = field.seq(seqtype);
- /* reverse point is at max */
- state->reverse_val = state->maximum;
- }
+ // if this is a digital joystick field, make a note of it
+ if (field.is_digital_joystick())
+ {
+ joystick = &field.manager().digjoystick(field.player(), (field.type() - (IPT_DIGITAL_JOYSTICK_FIRST + 1)) / 4);
+ joydir = joystick->set_axis(field);
}
- /* relative and positional controls all map directly with a 512x scale factor */
- else
+ // Name keyboard key names
+ if (field.type_class() == INPUT_CLASS_KEYBOARD && field.specific_name() == NULL)
{
- /* The relative code is set up to allow specifing PORT_MINMAX and default values. */
- /* The validity checks are purposely set up to not allow you to use anything other */
- /* a default of 0 and PORT_MINMAX(0,mask). This is in case the need arises to use */
- /* this feature in the future. Keeping the code in does not hurt anything. */
- if (state->adjmin > state->adjmax)
- /* adjust for signed */
- state->adjmin = -state->adjmin;
-
- if (state->wraps)
- state->adjmax++;
-
- state->minimum = (state->adjmin - state->adjdefvalue) * INPUT_RELATIVE_PER_PIXEL;
- state->maximum = (state->adjmax - state->adjdefvalue) * INPUT_RELATIVE_PER_PIXEL;
-
- /* make the scaling the same for easier coding when we need to scale */
- state->scaleneg = state->scalepos = COMPUTE_SCALE(1, INPUT_RELATIVE_PER_PIXEL);
-
- if (field->flags & ANALOG_FLAG_RESET)
- /* delta values reverse from center */
- state->reverse_val = 0;
- else
+ // loop through each character on the field
+ astring tempstr;
+ for (int which = 0; ; which++)
{
- /* positional controls reverse from their max range */
- state->reverse_val = state->maximum + state->minimum;
-
- /* relative controls reverse from 1 past their max range */
- if (state->wraps)
- state->reverse_val -= INPUT_RELATIVE_PER_PIXEL;
+ unicode_char ch = field.keyboard_code(which);
+ if (ch == 0)
+ break;
+ name.catprintf("%-*s ", MAX(SPACE_COUNT - 1, 0), field.manager().natkeyboard().key_name(tempstr, ch));
}
- }
- /* compute scale for keypresses */
- state->keyscalepos = RECIP_SCALE(state->scalepos);
- state->keyscaleneg = RECIP_SCALE(state->scaleneg);
+ // trim extra spaces
+ name.trimspace();
- return state;
+ // special case
+ if (name.len() == 0)
+ name.cpy("Unnamed Key");
+ }
}
-/***************************************************************************
- ONCE-PER-FRAME UPDATES
-***************************************************************************/
+//**************************************************************************
+// I/O PORT
+//**************************************************************************
-/*-------------------------------------------------
- frame_update_callback - system-wide callback to
- update the input ports once per frame, but
- only if we are not paused
--------------------------------------------------*/
+//-------------------------------------------------
+// ioport_port - constructor
+//-------------------------------------------------
-static void frame_update_callback(running_machine &machine)
+ioport_port::ioport_port(device_t &owner, const char *tag)
+ : m_next(NULL),
+ m_device(owner),
+ m_tag(tag),
+ m_modcount(0),
+ m_active(0),
+ m_live(NULL)
{
- /* if we're paused, don't do anything */
- if (machine.paused())
- return;
-
- /* otherwise, use the common code */
- frame_update(machine);
}
-static key_buffer *get_buffer(running_machine &machine)
+
+//-------------------------------------------------
+// ~ioport_port - destructor
+//-------------------------------------------------
+
+ioport_port::~ioport_port()
{
- ioport_manager &portdata = machine.ioport();
- assert(inputx_can_post(machine));
- return (key_buffer *)&portdata.keybuffer;
+ global_free(m_live);
}
+//-------------------------------------------------
+// machine - return a reference to the running
+// machine
+//-------------------------------------------------
-static const inputx_code *find_code(inputx_code *codes, unicode_char ch)
+running_machine &ioport_port::machine() const
{
- int i;
-
- assert(codes);
- for (i = 0; codes[i].ch; i++)
- {
- if (codes[i].ch == ch)
- return &codes[i];
- }
- return NULL;
+ return m_device.machine();
}
-/*-------------------------------------------------
- input_port_update_hook - hook function
- called from core to allow for natural keyboard
--------------------------------------------------*/
-static void input_port_update_hook(running_machine &machine, const input_port_config *port, input_port_value *digital)
+//-------------------------------------------------
+// manager - return a reference to the
+// ioport_manager on the running machine
+//-------------------------------------------------
+
+ioport_manager &ioport_port::manager() const
{
- ioport_manager &portdata = machine.ioport();
- const key_buffer *keybuf;
- const inputx_code *code;
- unicode_char ch;
- int i;
- UINT32 value;
+ return machine().ioport();
+}
- if (inputx_can_post(machine))
- {
- keybuf = get_buffer(machine);
- /* is the key down right now? */
- if (keybuf && keybuf->status_keydown && (keybuf->begin_pos != keybuf->end_pos))
- {
- /* identify the character that is down right now, and its component codes */
- ch = keybuf->buffer[keybuf->begin_pos];
- code = find_code(portdata.codes, ch);
+//-------------------------------------------------
+// field - return a pointer to the first field
+// that intersects the given mask
+//-------------------------------------------------
- /* loop through this character's component codes */
- if (code != NULL)
- {
- for (i = 0; i < ARRAY_LENGTH(code->field) && (code->field[i] != NULL); i++)
- {
- if (&code->field[i]->port() == port)
- {
- value = code->field[i]->mask;
- *digital |= value;
- }
- }
- }
- }
- }
+ioport_field *ioport_port::field(ioport_value mask)
+{
+ // if we got the port, look for the field
+ for (ioport_field *field = first_field(); field != NULL; field = field->next())
+ if ((field->mask() & mask) != 0)
+ return field;
+ return NULL;
}
-/*-------------------------------------------------
- frame_update - core logic for per-frame input
- port updating
--------------------------------------------------*/
+//-------------------------------------------------
+// read - return the value of an I/O port
+//-------------------------------------------------
-static void frame_update(running_machine &machine)
+ioport_value ioport_port::read()
{
- ioport_manager &portdata = machine.ioport();
- const input_field_config *mouse_field = NULL;
- int ui_visible = ui_is_menu_active();
- attotime curtime = machine.time();
- const input_port_config *port;
- render_target *mouse_target;
- INT32 mouse_target_x;
- INT32 mouse_target_y;
- int mouse_button;
+ assert_always(manager().safe_to_read(), "Input ports cannot be read at init time!");
-g_profiler.start(PROFILER_INPUT);
+ // start with the digital state
+ ioport_value result = m_live->digital;
- /* record/playback information about the current frame */
- playback_frame(machine, curtime);
- record_frame(machine, curtime);
+ // insert dynamic read values
+ for (dynamic_field *dynfield = m_live->readlist.first(); dynfield != NULL; dynfield = dynfield->next())
+ dynfield->read(result);
- /* track the duration of the previous frame */
- portdata.last_delta_nsec = (curtime - portdata.last_frame_time).as_attoseconds() / ATTOSECONDS_PER_NANOSECOND;
- portdata.last_frame_time = curtime;
+ // apply active high/low state to digital and dynamic read inputs
+ result ^= m_live->defvalue;
- /* update the digital joysticks */
- frame_update_digital_joysticks(machine);
+ // insert analog portions
+ for (analog_field *analog = m_live->analoglist.first(); analog != NULL; analog = analog->next())
+ analog->read(result);
- /* compute default values for all the ports */
- input_port_update_defaults(machine);
+ return result;
+}
- /* perform the mouse hit test */
- mouse_target = ui_input_find_mouse(machine, &mouse_target_x, &mouse_target_y, &mouse_button);
- if (mouse_button && mouse_target)
- {
- const char *tag = NULL;
- input_port_value mask;
- float x, y;
- if (mouse_target->map_point_input(mouse_target_x, mouse_target_y, tag, mask, x, y))
- mouse_field = input_field_by_tag_and_mask(machine, tag, mask);
- }
- /* loop over all input ports */
- for (port = machine.ioport().first_port(); port != NULL; port = port->next())
- {
- const input_field_config *field;
- device_field_info *device_field;
- input_port_value newvalue;
+//-------------------------------------------------
+// write - write a value to a port
+//-------------------------------------------------
- /* start with 0 values for the digital and VBLANK bits */
- port->state->digital = 0;
- port->state->vblank = 0;
+void ioport_port::write(ioport_value data, ioport_value mem_mask)
+{
+ // call device line write handlers
+ COMBINE_DATA(&m_live->outputvalue);
+ for (dynamic_field *dynfield = m_live->writelist.first(); dynfield != NULL; dynfield = dynfield->next())
+ if (dynfield->field().type() == IPT_OUTPUT)
+ dynfield->write(m_live->outputvalue);
+}
- /* now loop back and modify based on the inputs */
- for (field = port->first_field(); field != NULL; field = field->next())
- if (input_condition_true(port->machine(), &field->condition, port->owner()))
- {
- /* accumulate VBLANK bits */
- if (field->type == IPT_VBLANK)
- port->state->vblank ^= field->mask;
- /* handle analog inputs */
- else if (field->state->analog != NULL)
- frame_update_analog_field(machine, field->state->analog);
+//-------------------------------------------------
+// frame_update - once/frame update
+//-------------------------------------------------
- /* handle non-analog types, but only when the UI isn't visible */
- else if (!ui_visible && frame_get_digital_field_state(field, field == mouse_field))
- port->state->digital |= field->mask;
- }
+void ioport_port::frame_update(ioport_field *mouse_field)
+{
+ // start with 0 values for the digital bits
+ m_live->digital = 0;
- /* hook for MESS's natural keyboard support */
- input_port_update_hook(machine, port, &port->state->digital);
+ // now loop back and modify based on the inputs
+ for (ioport_field *field = first_field(); field != NULL; field = field->next())
+ field->frame_update(m_live->digital, field == mouse_field);
- /* handle playback/record */
- playback_port(port);
- record_port(port);
+ // hook for MESS's natural keyboard support
+ manager().natkeyboard().frame_update(*this, m_live->digital);
- /* call device line write handlers */
- newvalue = input_port_read_direct(port);
- for (device_field = port->state->writedevicelist; device_field; device_field = device_field->next)
- if (device_field->field->type != IPT_OUTPUT && input_condition_true(port->machine(), &device_field->field->condition, port->owner()))
- {
- input_port_value newval = (newvalue & device_field->field->mask) >> device_field->shift;
+ // call device line write handlers
+ ioport_value newvalue = read();
+ for (dynamic_field *dynfield = m_live->writelist.first(); dynfield != NULL; dynfield = dynfield->next())
+ if (dynfield->field().type() != IPT_OUTPUT)
+ dynfield->write(newvalue);
+}
- /* if the bits have write, call the handler */
- if (device_field->oldval != newval)
- {
- device_field->field->write(*device_field->field, device_field->field->write_param, device_field->oldval, newval);
- device_field->oldval = newval;
- }
- }
- }
+//-------------------------------------------------
+// collapse_fields - remove any fields that are
+// wholly overlapped by other fields
+//-------------------------------------------------
-g_profiler.stop();
+void ioport_port::collapse_fields(astring &errorbuf)
+{
+ ioport_value maskbits = 0;
+ int lastmodcount = -1;
+
+ // remove the whole list and start from scratch
+ ioport_field *field = m_fieldlist.detach_all();
+ while (field != NULL)
+ {
+ // if this modcount doesn't match, reset
+ if (field->modcount() != lastmodcount)
+ {
+ lastmodcount = field->modcount();
+ maskbits = 0;
+ }
+
+ // reinsert this field
+ ioport_field *current = field;
+ field = field->next();
+ insert_field(*current, maskbits, errorbuf);
+ }
}
-/*-------------------------------------------------
- frame_update_digital_joysticks - update the
- state of digital joysticks prior to
- accumulating the results in a port
--------------------------------------------------*/
+//-------------------------------------------------
+// insert_field - insert a new field, checking
+// for errors
+//-------------------------------------------------
-static void frame_update_digital_joysticks(running_machine &machine)
+void ioport_port::insert_field(ioport_field &newfield, ioport_value &disallowedbits, astring &errorbuf)
{
- ioport_manager &portdata = machine.ioport();
- int player, joyindex;
+ // verify against the disallowed bits, but only if we are condition-free
+ if (newfield.condition().none())
+ {
+ if ((newfield.mask() & disallowedbits) != 0)
+ errorbuf.catprintf("INPUT_TOKEN_FIELD specifies duplicate port bits (port=%s mask=%X)\n", tag(), newfield.mask());
+ disallowedbits |= newfield.mask();
+ }
- /* loop over all the joysticks */
- for (player = 0; player < MAX_PLAYERS; player++)
- for (joyindex = 0; joyindex < DIGITAL_JOYSTICKS_PER_PLAYER; joyindex++)
+ // first modify/nuke any entries that intersect our maskbits
+ ioport_field *nextfield;
+ for (ioport_field *field = first_field(); field != NULL; field = nextfield)
+ {
+ nextfield = field->next();
+ if ((field->mask() & newfield.mask()) != 0 &&
+ (newfield.condition().none() || field->condition().none() || field->condition() == newfield.condition()))
{
- digital_joystick_state *joystick = &portdata.joystick_info[player][joyindex];
- if (joystick->inuse)
- {
- joystick->previous = joystick->current;
- joystick->current = 0;
-
- /* read all the associated ports */
- if (joystick->field[JOYDIR_UP] != NULL && machine.input().seq_pressed(input_field_seq(joystick->field[JOYDIR_UP], SEQ_TYPE_STANDARD)))
- joystick->current |= JOYDIR_UP_BIT;
- if (joystick->field[JOYDIR_DOWN] != NULL && machine.input().seq_pressed(input_field_seq(joystick->field[JOYDIR_DOWN], SEQ_TYPE_STANDARD)))
- joystick->current |= JOYDIR_DOWN_BIT;
- if (joystick->field[JOYDIR_LEFT] != NULL && machine.input().seq_pressed(input_field_seq(joystick->field[JOYDIR_LEFT], SEQ_TYPE_STANDARD)))
- joystick->current |= JOYDIR_LEFT_BIT;
- if (joystick->field[JOYDIR_RIGHT] != NULL && machine.input().seq_pressed(input_field_seq(joystick->field[JOYDIR_RIGHT], SEQ_TYPE_STANDARD)))
- joystick->current |= JOYDIR_RIGHT_BIT;
-
- /* lock out opposing directions (left + right or up + down) */
- if ((joystick->current & (JOYDIR_UP_BIT | JOYDIR_DOWN_BIT)) == (JOYDIR_UP_BIT | JOYDIR_DOWN_BIT))
- joystick->current &= ~(JOYDIR_UP_BIT | JOYDIR_DOWN_BIT);
- if ((joystick->current & (JOYDIR_LEFT_BIT | JOYDIR_RIGHT_BIT)) == (JOYDIR_LEFT_BIT | JOYDIR_RIGHT_BIT))
- joystick->current &= ~(JOYDIR_LEFT_BIT | JOYDIR_RIGHT_BIT);
-
- /* only update 4-way case if joystick has moved */
- if (joystick->current != joystick->previous)
- {
- joystick->current4way = joystick->current;
+ // reduce the mask of the field we found
+ field->reduce_mask(newfield.mask());
- /*
- If joystick is pointing at a diagonal, acknowledge that the player moved
- the joystick by favoring a direction change. This minimizes frustration
- when using a keyboard for input, and maximizes responsiveness.
+ // if the new entry fully overrides the previous one, we nuke
+ if (INPUT_PORT_OVERRIDE_FULLY_NUKES_PREVIOUS || field->mask() == 0)
+ m_fieldlist.remove(*field);
+ }
+ }
- For example, if you are holding "left" then switch to "up" (where both left
- and up are briefly pressed at the same time), we'll transition immediately
- to "up."
+ // make a mask of just the low bit
+ ioport_value lowbit = (newfield.mask() ^ (newfield.mask() - 1)) & newfield.mask();
- Zero any switches that didn't change from the previous to current state.
- */
- if ((joystick->current4way & (JOYDIR_UP_BIT | JOYDIR_DOWN_BIT)) &&
- (joystick->current4way & (JOYDIR_LEFT_BIT | JOYDIR_RIGHT_BIT)))
- {
- joystick->current4way ^= joystick->current4way & joystick->previous;
- }
+ // scan forward to find where to insert ourselves
+ ioport_field *field;
+ for (field = first_field(); field != NULL; field = field->next())
+ if (field->mask() > lowbit)
+ break;
- /*
- If we are still pointing at a diagonal, we are in an indeterminant state.
+ // insert it into the list
+ m_fieldlist.insert_before(newfield, field);
+}
- This could happen if the player moved the joystick from the idle position directly
- to a diagonal, or from one diagonal directly to an extreme diagonal.
- The chances of this happening with a keyboard are slim, but we still need to
- constrain this case.
+//-------------------------------------------------
+// init_live_state - create the live state
+//-------------------------------------------------
- For now, just resolve randomly.
- */
- if ((joystick->current4way & (JOYDIR_UP_BIT | JOYDIR_DOWN_BIT)) &&
- (joystick->current4way & (JOYDIR_LEFT_BIT | JOYDIR_RIGHT_BIT)))
- {
- if (machine.rand() & 1)
- joystick->current4way &= ~(JOYDIR_LEFT_BIT | JOYDIR_RIGHT_BIT);
- else
- joystick->current4way &= ~(JOYDIR_UP_BIT | JOYDIR_DOWN_BIT);
- }
- }
- }
- }
+void ioport_port::init_live_state()
+{
+ m_live = global_alloc(ioport_port_live(*this));
}
-/*-------------------------------------------------
- frame_update_analog_field - update the
- internals of a single analog field
--------------------------------------------------*/
-
-static void frame_update_analog_field(running_machine &machine, analog_field_state *analog)
-{
- input_item_class itemclass;
- int keypressed = FALSE;
- INT64 keyscale;
- INT32 rawvalue;
- INT32 delta = 0;
- /* clamp the previous value to the min/max range and remember it */
- analog->previous = analog->accum = apply_analog_min_max(analog, analog->accum);
+//**************************************************************************
+// I/O PORT LIVE STATE
+//**************************************************************************
- /* get the new raw analog value and its type */
- rawvalue = machine.input().seq_axis_value(input_field_seq(analog->field, SEQ_TYPE_STANDARD), itemclass);
+//-------------------------------------------------
+// ioport_port_live - constructor
+//-------------------------------------------------
- /* if we got an absolute input, it overrides everything else */
- if (itemclass == ITEM_CLASS_ABSOLUTE)
+ioport_port_live::ioport_port_live(ioport_port &port)
+ : defvalue(0),
+ digital(0),
+ outputvalue(0)
+{
+ // iterate over fields
+ for (ioport_field *field = port.first_field(); field != NULL; field = field->next())
{
- if (analog->previousanalog != rawvalue)
- {
- /* only update if analog value changed */
- analog->previousanalog = rawvalue;
+ // allocate analog state if it's analog
+ analog_field *analog = NULL;
+ if (field->is_analog())
+ analog = &analoglist.append(*global_alloc(analog_field(*field)));
+
+ // allocate a dynamic field for reading
+ if (field->has_dynamic_read())
+ readlist.append(*global_alloc(dynamic_field(*field)));
+
+ // allocate a dynamic field for writing
+ if (field->has_dynamic_write())
+ writelist.append(*global_alloc(dynamic_field(*field)));
+
+ // let the field initialize its live state
+ field->init_live_state(analog);
+ }
+}
- /* apply the inverse of the sensitivity to the raw value so that */
- /* it will still cover the full min->max range requested after */
- /* we apply the sensitivity adjustment */
- if (analog->absolute || (analog->field->flags & ANALOG_FLAG_RESET))
- {
- /* if port is absolute, then just return the absolute data supplied */
- analog->accum = APPLY_INVERSE_SENSITIVITY(rawvalue, analog->sensitivity);
- }
- else if (analog->positionalscale != 0)
- {
- /* if port is positional, we will take the full analog control and divide it */
- /* into positions, that way as the control is moved full scale, */
- /* it moves through all the positions */
- rawvalue = APPLY_SCALE(rawvalue - INPUT_ABSOLUTE_MIN, analog->positionalscale) * INPUT_RELATIVE_PER_PIXEL + analog->minimum;
-
- /* clamp the high value so it does not roll over */
- rawvalue = MIN(rawvalue, analog->maximum);
- analog->accum = APPLY_INVERSE_SENSITIVITY(rawvalue, analog->sensitivity);
- }
- else
- /* if port is relative, we use the value to simulate the speed of relative movement */
- /* sensitivity adjustment is allowed for this mode */
- analog->accum += rawvalue;
- analog->lastdigital = FALSE;
- /* do not bother with other control types if the analog data is changing */
- return;
- }
- else
- {
- /* we still have to update fake relative from joystick control */
- if (!analog->absolute && analog->positionalscale == 0)
- analog->accum += rawvalue;
- }
- }
- /* if we got it from a relative device, use that as the starting delta */
- /* also note that the last input was not a digital one */
- if (itemclass == ITEM_CLASS_RELATIVE && rawvalue != 0)
- {
- delta = rawvalue;
- analog->lastdigital = FALSE;
- }
+//**************************************************************************
+// I/O PORT MANAGER
+//**************************************************************************
- keyscale = (analog->accum >= 0) ? analog->keyscalepos : analog->keyscaleneg;
+//-------------------------------------------------
+// ioport_manager - constructor
+//-------------------------------------------------
- /* if the decrement code sequence is pressed, add the key delta to */
- /* the accumulated delta; also note that the last input was a digital one */
- if (machine.input().seq_pressed(input_field_seq(analog->field, SEQ_TYPE_DECREMENT)))
- {
- keypressed = TRUE;
- if (analog->delta != 0)
- delta -= APPLY_SCALE(analog->delta, keyscale);
- else if (!analog->lastdigital)
- /* decrement only once when first pressed */
- delta -= APPLY_SCALE(1, keyscale);
- analog->lastdigital = TRUE;
- }
+ioport_manager::ioport_manager(running_machine &machine)
+ : m_machine(machine),
+ m_safe_to_read(false),
+ m_natkeyboard(machine),
+ m_last_frame_time(attotime::zero),
+ m_last_delta_nsec(0),
+ m_record_file(machine.options().input_directory(), OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS),
+ m_playback_file(machine.options().input_directory(), OPEN_FLAG_READ),
+ m_playback_accumulated_speed(0),
+ m_playback_accumulated_frames(0)
+{
+ memset(m_type_to_entry, 0, sizeof(m_type_to_entry));
+}
- /* same for the increment code sequence */
- if (machine.input().seq_pressed(input_field_seq(analog->field, SEQ_TYPE_INCREMENT)))
- {
- keypressed = TRUE;
- if (analog->delta)
- delta += APPLY_SCALE(analog->delta, keyscale);
- else if (!analog->lastdigital)
- /* increment only once when first pressed */
- delta += APPLY_SCALE(1, keyscale);
- analog->lastdigital = TRUE;
- }
- /* if resetting is requested, clear the accumulated position to 0 before */
- /* applying the deltas so that we only return this frame's delta */
- /* note that centering only works for relative controls */
- /* no need to check if absolute here because it is checked by the validity tests */
- if (analog->field->flags & ANALOG_FLAG_RESET)
- analog->accum = 0;
+//-------------------------------------------------
+// initialize - walk the configured ports and
+// create live state information
+//-------------------------------------------------
+
+time_t ioport_manager::initialize()
+{
+ // add an exit callback and a frame callback
+ machine().add_notifier(MACHINE_NOTIFY_EXIT, machine_notify_delegate(FUNC(ioport_manager::exit), this));
+ machine().add_notifier(MACHINE_NOTIFY_FRAME, machine_notify_delegate(FUNC(ioport_manager::frame_update), this));
- /* apply the delta to the accumulated value */
- analog->accum += delta;
+ // initialize the default port info from the OSD
+ init_port_types();
- /* if our last movement was due to a digital input, and if this control */
- /* type autocenters, and if neither the increment nor the decrement seq */
- /* was pressed, apply autocentering */
- if (analog->autocenter)
+ // if we have a token list, proceed
+ device_iterator iter(machine().root_device());
+ for (device_t *device = iter.first(); device != NULL; device = iter.next())
{
- INT32 center = APPLY_INVERSE_SENSITIVITY(analog->center, analog->sensitivity);
- if (analog->lastdigital && !keypressed)
- {
- /* autocenter from positive values */
- if (analog->accum >= center)
- {
- analog->accum -= APPLY_SCALE(analog->centerdelta, analog->keyscalepos);
- if (analog->accum < center)
- {
- analog->accum = center;
- analog->lastdigital = FALSE;
- }
- }
+ astring errors;
+ m_portlist.append(*device, errors);
+ if (errors)
+ mame_printf_error("Input port errors:\n%s", errors.cstr());
+ }
- /* autocenter from negative values */
- else
- {
- analog->accum += APPLY_SCALE(analog->centerdelta, analog->keyscaleneg);
- if (analog->accum > center)
+ // allocate live structures to mirror the configuration
+ for (ioport_port *port = first_port(); port != NULL; port = port->next())
+ port->init_live_state();
+
+ // handle autoselection of devices
+ init_autoselect_devices(IPT_AD_STICK_X, IPT_AD_STICK_Y, IPT_AD_STICK_Z, OPTION_ADSTICK_DEVICE, "analog joystick");
+ init_autoselect_devices(IPT_PADDLE, IPT_PADDLE_V, 0, OPTION_PADDLE_DEVICE, "paddle");
+ init_autoselect_devices(IPT_PEDAL, IPT_PEDAL2, IPT_PEDAL3, OPTION_PEDAL_DEVICE, "pedal");
+ init_autoselect_devices(IPT_LIGHTGUN_X, IPT_LIGHTGUN_Y, 0, OPTION_LIGHTGUN_DEVICE, "lightgun");
+ init_autoselect_devices(IPT_POSITIONAL, IPT_POSITIONAL_V, 0, OPTION_POSITIONAL_DEVICE, "positional");
+ init_autoselect_devices(IPT_DIAL, IPT_DIAL_V, 0, OPTION_DIAL_DEVICE, "dial");
+ init_autoselect_devices(IPT_TRACKBALL_X, IPT_TRACKBALL_Y, 0, OPTION_TRACKBALL_DEVICE, "trackball");
+ init_autoselect_devices(IPT_MOUSE_X, IPT_MOUSE_Y, 0, OPTION_MOUSE_DEVICE, "mouse");
+
+ // look for 4-way joysticks and change the default map if we find any
+ const char *joystick_map_default = machine().options().joystick_map();
+ if (joystick_map_default[0] == 0 || strcmp(joystick_map_default, "auto") == 0)
+ for (ioport_port *port = first_port(); port != NULL; port = port->next())
+ for (ioport_field *field = port->first_field(); field != NULL; field = field->next())
+ if (field->live().joystick != NULL && field->way() == 4)
{
- analog->accum = center;
- analog->lastdigital = FALSE;
+ machine().input().set_global_joystick_map(field->rotated() ? joystick_map_4way_diagonal : joystick_map_4way_sticky);
+ break;
}
- }
- }
- }
- else if (!keypressed)
- analog->lastdigital = FALSE;
+
+ // register callbacks for when we load configurations
+ config_register(machine(), "input", config_saveload_delegate(FUNC(ioport_manager::load_config), this), config_saveload_delegate(FUNC(ioport_manager::save_config), this));
+
+ // open playback and record files if specified
+ time_t basetime = playback_init();
+ record_init();
+ return basetime;
}
-/*-------------------------------------------------
- frame_get_digital_field_state - get the state
- of a digital field
--------------------------------------------------*/
+//-------------------------------------------------
+// init_port_types - initialize the default
+// type list
+//-------------------------------------------------
-static int frame_get_digital_field_state(const input_field_config *field, int mouse_down)
+void ioport_manager::init_port_types()
{
- int curstate = mouse_down || field->machine().input().seq_pressed(input_field_seq(field, SEQ_TYPE_STANDARD));
- int changed = FALSE;
- int temp_field_impulse;
+ // convert the array into a list of type states that can be modified
+ construct_core_types(m_typelist);
- /* if the state changed, look for switch down/switch up */
- if (curstate != field->state->last)
+ // ask the OSD to customize the list
+ machine().osd().customize_input_type_list(m_typelist);
+
+ // now iterate over the OSD-modified types
+ for (input_type_entry *curtype = first_type(); curtype != NULL; curtype = curtype->next())
{
- field->state->last = curstate;
- changed = TRUE;
+ // first copy all the OSD-updated sequences into our current state
+ for (input_seq_type seqtype = SEQ_TYPE_STANDARD; seqtype < SEQ_TYPE_TOTAL; seqtype++)
+ curtype->m_seq[seqtype] = curtype->defseq(seqtype);
+
+ // also make a lookup table mapping type/player to the appropriate type list entry
+ m_type_to_entry[curtype->type()][curtype->player()] = curtype;
}
+}
- if (field->type == IPT_KEYBOARD && ui_get_use_natural_keyboard(field->machine()))
- return FALSE;
- /* coin impulse option */
- {
- int temp_option_impulse = field->machine().options().coin_impulse();
- temp_field_impulse = field->impulse;
- if ( temp_option_impulse != 0)
- {
- if (temp_option_impulse < 0)
- temp_field_impulse = 0;
- else if ((field->type >= IPT_COIN1 && field->type <= IPT_COIN12) || field->impulse != 0)
- temp_field_impulse = temp_option_impulse;
- }
- }
+//-------------------------------------------------
+// init_autoselect_devices - autoselect a single
+// device based on the input port list passed
+// in and the corresponding option
+//-------------------------------------------------
- /* if this is a switch-down event, handle impulse and toggle */
- if (changed && curstate)
- {
- /* impluse controls: reset the impulse counter */
- if (temp_field_impulse != 0 && field->state->impulse == 0)
- field->state->impulse = temp_field_impulse;
+void ioport_manager::init_autoselect_devices(int type1, int type2, int type3, const char *option, const char *ananame)
+{
+ // if nothing specified, ignore the option
+ const char *stemp = machine().options().value(option);
+ if (stemp[0] == 0)
+ return;
- /* toggle controls: flip the toggle state or advance to the next setting */
- if (field->flags & FIELD_FLAG_TOGGLE)
- {
- if (field->settinglist().count() == 0)
- field->state->value ^= field->mask;
- else
- input_field_select_next_setting(field);
- }
+ // extract valid strings
+ const char *autostring = "keyboard";
+ input_device_class autoenable = DEVICE_CLASS_KEYBOARD;
+ if (strcmp(stemp, "mouse") == 0)
+ {
+ autoenable = DEVICE_CLASS_MOUSE;
+ autostring = "mouse";
}
-
- /* update the current state with the impulse state */
- if (temp_field_impulse != 0)
+ else if (strcmp(stemp, "joystick") == 0)
{
- if (field->state->impulse != 0)
- {
- field->state->impulse--;
- curstate = TRUE;
- }
- else
- curstate = FALSE;
+ autoenable = DEVICE_CLASS_JOYSTICK;
+ autostring = "joystick";
}
-
- /* for toggle switches, the current value is folded into the port's default value */
- /* so we always return FALSE here */
- if (field->flags & FIELD_FLAG_TOGGLE)
- curstate = FALSE;
-
- /* additional logic to restrict digital joysticks */
- if (curstate && !mouse_down && field->state->joystick != NULL && field->way != 16 && !field->machine().options().joystick_contradictory())
+ else if (strcmp(stemp, "lightgun") == 0)
{
- UINT8 mask = (field->way == 4) ? field->state->joystick->current4way : field->state->joystick->current;
- if (!(mask & (1 << field->state->joydir)))
- curstate = FALSE;
+ autoenable = DEVICE_CLASS_LIGHTGUN;
+ autostring = "lightgun";
}
-
- /* skip locked-out coin inputs */
- if (curstate && field->type >= IPT_COIN1 && field->type <= IPT_COIN12 && coin_lockout_get_state(field->machine(), field->type - IPT_COIN1))
+ else if (strcmp(stemp, "none") == 0)
{
- int verbose = field->machine().options().verbose();
-#ifdef MAME_DEBUG
- verbose = 1;
-#endif
- if (field->machine().options().coin_lockout())
- {
- if (verbose)
- ui_popup_time(3, "Coinlock disabled %s.", input_field_name(field));
- return FALSE; /* curstate = FALSE; */
- }
- else
- if (verbose)
- ui_popup_time(3, "Coinlock disabled, but broken through %s.", input_field_name(field));
+ // nothing specified
+ return;
}
+ else if (strcmp(stemp, "keyboard") != 0)
+ mame_printf_error("Invalid %s value %s; reverting to keyboard\n", option, stemp);
+
+ // only scan the list if we haven't already enabled this class of control
+ if (first_port() != NULL && !machine().input().device_class(autoenable).enabled())
+ for (ioport_port *port = first_port(); port != NULL; port = port->next())
+ for (ioport_field *field = port->first_field(); field != NULL; field = field->next())
- return curstate;
+ // if this port type is in use, apply the autoselect criteria
+ if ((type1 != 0 && field->type() == type1) || (type2 != 0 && field->type() == type2) || (type3 != 0 && field->type() == type3))
+ {
+ mame_printf_verbose("Input: Autoenabling %s due to presence of a %s\n", autostring, ananame);
+ machine().input().device_class(autoenable).enable();
+ break;
+ }
}
+//-------------------------------------------------
+// exit - exit callback to ensure we clean up
+// and close our files
+//-------------------------------------------------
-/***************************************************************************
- PORT CONFIGURATION HELPERS
-***************************************************************************/
-
-/*-------------------------------------------------
- port_default_value - updates default value
- of port settings according to device settings
--------------------------------------------------*/
-
-UINT32 port_default_value(const char *fulltag, UINT32 mask, UINT32 defval, device_t &owner)
+void ioport_manager::exit()
{
- const input_device_default *def = owner.input_ports_defaults();
- if (def != NULL)
- {
- astring fullpath;
- for ( ; def->tag != NULL; def++)
- if (owner.subtag(fullpath, def->tag) == fulltag && def->mask == mask)
- return def->defvalue;
- }
- return defval;
+ // close any playback or recording files
+ playback_end();
+ record_end();
}
-/*-------------------------------------------------
- input_port_config - constructor for an
- I/O port configuration object
--------------------------------------------------*/
+//-------------------------------------------------
+// type_name - return the name for the given
+// type/player
+//-------------------------------------------------
-input_port_config::input_port_config(device_t &owner, const char *tag)
- : state(NULL),
- active(0),
- m_next(NULL),
- m_owner(owner),
- m_tag(tag),
- m_modcount(0)
+const char *ioport_manager::type_name(ioport_type type, UINT8 player)
{
+ // if we have a machine, use the live state and quick lookup
+ input_type_entry *entry = m_type_to_entry[type][player];
+ if (entry != NULL)
+ return entry->name();
+
+ // if we find nothing, return an invalid group
+ return "???";
}
-running_machine &input_port_config::machine() const
+//-------------------------------------------------
+// type_group - return the group for the given
+// type/player
+//-------------------------------------------------
+
+ioport_group ioport_manager::type_group(ioport_type type, int player)
{
- return m_owner.machine();
+ input_type_entry *entry = m_type_to_entry[type][player];
+ if (entry != NULL)
+ return entry->group();
+
+ // if we find nothing, return an invalid group
+ return IPG_INVALID;
}
-/*-------------------------------------------------
- field_config_alloc - allocate a new input
- port field config
--------------------------------------------------*/
+//-------------------------------------------------
+// type_seq - return the input sequence for the
+// given type/player
+//-------------------------------------------------
-input_field_config::input_field_config(input_port_config &port, int _type, input_port_value _defvalue, input_port_value _maskbits, const char *_name)
- : mask(_maskbits),
- defvalue(_defvalue & _maskbits),
- type(_type),
- player(0),
- flags(0),
- impulse(0),
- name(_name),
- read_param(NULL),
- read_device(DEVICE_SELF),
- write_param(NULL),
- write_device(DEVICE_SELF),
- min(0),
- max(_maskbits),
- sensitivity(0),
- delta(0),
- centerdelta(0),
- crossaxis(0),
- crossscale(0),
- crossoffset(0),
- crossaltaxis(0),
- crossmapper_device(DEVICE_SELF),
- full_turn_count(0),
- remap_table(NULL),
- way(0),
- state(NULL),
- m_next(NULL),
- m_port(port),
- m_modcount(port.modcount())
+const input_seq &ioport_manager::type_seq(ioport_type type, int player, input_seq_type seqtype)
{
- memset(&condition, 0, sizeof(condition));
- for (int seqtype = 0; seqtype < ARRAY_LENGTH(seq); seqtype++)
- seq[seqtype].set_default();
- chars[0] = chars[1] = chars[2] = (unicode_char) 0;
+ assert(type >= 0 && type < IPT_COUNT);
+ assert(player >= 0 && player < MAX_PLAYERS);
+
+ // if we have a machine, use the live state and quick lookup
+ input_type_entry *entry = m_type_to_entry[type][player];
+ if (entry != NULL)
+ return entry->seq(seqtype);
+
+ // if we find nothing, return an empty sequence
+ return input_seq::empty_seq;
}
-input_setting_config::input_setting_config(input_field_config &field, input_port_value _value, const char *_name)
- : value(_value),
- name(_name),
- m_field(field),
- m_next(NULL)
+//-------------------------------------------------
+// set_type_seq - change the input sequence for
+// the given type/player
+//-------------------------------------------------
+
+void ioport_manager::set_type_seq(ioport_type type, int player, input_seq_type seqtype, const input_seq &newseq)
{
- memset(&condition, 0, sizeof(condition));
+ input_type_entry *entry = m_type_to_entry[type][player];
+ if (entry != NULL)
+ entry->m_seq[seqtype] = newseq;
}
-input_field_diplocation::input_field_diplocation(const char *string, UINT8 _swnum, bool _invert)
- : swname(string),
- swnum(_swnum),
- invert(_invert)
+
+//-------------------------------------------------
+// type_pressed - return true if the sequence for
+// the given input type/player is pressed
+//-------------------------------------------------
+
+bool ioport_manager::type_pressed(ioport_type type, int player)
{
+ return machine().input().seq_pressed(type_seq(type, player));
}
-/*-------------------------------------------------
- field_config_insert - insert an allocated
- input port field config, replacing any
- intersecting fields already present and
- inserting at the correct sorted location
--------------------------------------------------*/
-void input_port_config::collapse_fields(astring &errorbuf)
+//-------------------------------------------------
+// type_class_present - return true if the given
+// ioport_type_class exists in at least one port
+//-------------------------------------------------
+
+bool ioport_manager::type_class_present(ioport_type_class inputclass)
{
- input_field_config *list = m_fieldlist.detach_all();
- input_port_value maskbits = 0;
- int lastmodcount = -1;
- while (list != NULL)
- {
- if (list->modcount() != lastmodcount)
- {
- lastmodcount = list->modcount();
- maskbits = 0;
- }
- input_field_config *current = list;
- list = list->next();
- field_config_insert(*current, maskbits, errorbuf);
- }
+ for (ioport_port *port = first_port(); port != NULL; port = port->next())
+ for (ioport_field *field = port->first_field(); field != NULL; field = field->next())
+ if (field->type_class() == inputclass)
+ return true;
+ return false;
}
-void field_config_insert(input_field_config &newfield, input_port_value &disallowedbits, astring &errorbuf)
-{
- input_port_value lowbit;
- /* verify against the disallowed bits, but only if we are condition-free */
- if (newfield.condition.condition == PORTCOND_ALWAYS)
- {
- if ((newfield.mask & disallowedbits) != 0)
- errorbuf.catprintf("INPUT_TOKEN_FIELD specifies duplicate port bits (port=%s mask=%X)\n", newfield.port().tag(), newfield.mask);
- disallowedbits |= newfield.mask;
- }
+//-------------------------------------------------
+// has_keyboard - determine if there is a
+// keyboard present in the control list
+//-------------------------------------------------
- /* first modify/nuke any entries that intersect our maskbits */
- input_field_config *nextfield;
- for (input_field_config *field = newfield.port().fieldlist().first(); field != NULL; field = nextfield)
- {
- nextfield = field->next();
- if ((field->mask & newfield.mask) != 0 && (newfield.condition.condition == PORTCOND_ALWAYS ||
- field->condition.condition == PORTCOND_ALWAYS ||
- condition_equal(&field->condition, &newfield.condition)))
+bool ioport_manager::has_keyboard() const
+{
+ // iterate over ports and fields
+ for (ioport_port *port = first_port(); port != NULL; port = port->next())
+ for (ioport_field *field = port->first_field(); field != NULL; field = field->next())
{
- /* reduce the mask of the field we found */
- field->mask &= ~newfield.mask;
+ // if we are at init, check IPT_KEYBOARD
+ if (!m_safe_to_read && field->type() == IPT_KEYBOARD)
+ return true;
- /* if the new entry fully overrides the previous one, we nuke */
- if (INPUT_PORT_OVERRIDE_FULLY_NUKES_PREVIOUS || field->mask == 0)
- newfield.port().fieldlist().remove(*field);
+ // else, check if there is a keyboard and if such a keyboard is enabled
+ if (field->type() == IPT_KEYBOARD && field->enabled())
+ return true;
}
- }
- /* make a mask of just the low bit */
- lowbit = (newfield.mask ^ (newfield.mask - 1)) & newfield.mask;
+ return false;
+}
+
+//-------------------------------------------------
+// count_players - counts the number of active
+// players
+//-------------------------------------------------
- /* scan forward to find where to insert ourselves */
- input_field_config *field;
- for (field = newfield.port().fieldlist().first(); field != NULL; field = field->next())
- if (field->mask > lowbit)
- break;
+int ioport_manager::count_players() const
+{
+ int max_player = 0;
+ for (ioport_port *port = first_port(); port != NULL; port = port->next())
+ for (ioport_field *field = port->first_field(); field != NULL; field = field->next())
+ if (field->type_class() == INPUT_CLASS_CONTROLLER && max_player <= field->player() + 1)
+ max_player = field->player() + 1;
- /* insert it into the list */
- newfield.port().fieldlist().insert_before(newfield, field);
+ return max_player;
}
-/*-------------------------------------------------
- diplocation_expand - expand a string-based
- DIP location into a linked list of
- descriptions
--------------------------------------------------*/
+//-------------------------------------------------
+// crosshair_position - return the extracted
+// crosshair values for the given player
+//-------------------------------------------------
-void diplocation_list_alloc(input_field_config &field, const char *location, astring &errorbuf)
+bool ioport_manager::crosshair_position(int player, float &x, float &y)
{
- /* if nothing present, bail */
- if (location == NULL)
- return;
-
- field.diploclist().reset();
+ // read all the lightgun values
+ bool gotx = false, goty = false;
+ for (ioport_port *port = first_port(); port != NULL; port = port->next())
+ for (ioport_field *field = port->first_field(); field != NULL; field = field->next())
+ if (field->player() == player && field->crosshair_axis() != CROSSHAIR_AXIS_NONE && field->enabled())
+ {
+ field->crosshair_position(x, y, gotx, goty);
- /* parse the string */
- astring name; // Don't move this variable inside the loop, lastname's lifetime depends on it being outside
- const char *lastname = NULL;
- const char *curentry = location;
- int entries = 0;
- while (*curentry != 0)
- {
- /* find the end of this entry */
- const char *comma = strchr(curentry, ',');
- if (comma == NULL)
- comma = curentry + strlen(curentry);
+ // if we got both, stop
+ if (gotx && goty)
+ break;
+ }
- /* extract it to tempbuf */
- astring tempstr;
- tempstr.cpy(curentry, comma - curentry);
+ return (gotx && goty);
+}
- /* first extract the switch name if present */
- const char *number = tempstr;
- const char *colon = strchr(tempstr, ':');
- /* allocate and copy the name if it is present */
- if (colon != NULL)
- {
- lastname = name.cpy(number, colon - number);
- number = colon + 1;
- }
+//-------------------------------------------------
+// update_defaults - force an update to the input
+// port values based on current conditions
+//-------------------------------------------------
- /* otherwise, just copy the last name */
- else
+void ioport_manager::update_defaults()
+{
+ // two passes to catch conditionals properly
+ for (int loopnum = 0; loopnum < 2; loopnum++)
+ {
+ // loop over all input ports
+ for (ioport_port *port = first_port(); port != NULL; port = port->next())
{
- if (lastname == NULL)
- {
- errorbuf.catprintf("Switch location '%s' missing switch name!\n", location);
- lastname = (char *)"UNK";
- }
- name.cpy(lastname);
- }
+ // only clear on the first pass
+ if (loopnum == 0)
+ port->live().defvalue = 0;
- /* if the number is preceded by a '!' it's active high */
- bool invert = false;
- if (*number == '!')
- {
- invert = true;
- number++;
+ // first compute the default value for the entire port
+ for (ioport_field *field = port->first_field(); field != NULL; field = field->next())
+ if (field->enabled())
+ port->live().defvalue = (port->live().defvalue & ~field->mask()) | (field->live().value & field->mask());
}
+ }
+}
- /* now scan the switch number */
- int swnum = -1;
- if (sscanf(number, "%d", &swnum) != 1)
- errorbuf.catprintf("Switch location '%s' has invalid format!\n", location);
-
- /* allocate a new entry */
- field.diploclist().append(*global_alloc(input_field_diplocation(name, swnum, invert)));
- entries++;
- /* advance to the next item */
- curentry = comma;
- if (*curentry != 0)
- curentry++;
- }
+//-------------------------------------------------
+// frame_update - core logic for per-frame input
+// port updating
+//-------------------------------------------------
- /* then verify the number of bits in the mask matches */
- input_port_value temp;
- int bits;
- for (bits = 0, temp = field.mask; temp != 0 && bits < 32; bits++)
- temp &= temp - 1;
- if (bits != entries)
- errorbuf.catprintf("Switch location '%s' does not describe enough bits for mask %X\n", location, field.mask);
+digital_joystick &ioport_manager::digjoystick(int player, int number)
+{
+ // find it in the list
+ for (digital_joystick *joystick = m_joystick_list.first(); joystick != NULL; joystick = joystick->next())
+ if (joystick->player() == player && joystick->number() == number)
+ return *joystick;
+
+ // create a new one
+ return m_joystick_list.append(*global_alloc(digital_joystick(player, number)));
}
+//-------------------------------------------------
+// frame_update - core logic for per-frame input
+// port updating
+//-------------------------------------------------
-/***************************************************************************
- TOKENIZATION HELPERS
-***************************************************************************/
+void ioport_manager::frame_update()
+{
+ // if we're paused, don't do anything
+ if (machine().paused())
+ return;
-/*-------------------------------------------------
- token_to_input_field_type - convert a string
- token to an input field type and player
--------------------------------------------------*/
+g_profiler.start(PROFILER_INPUT);
-static int token_to_input_field_type(running_machine &machine, const char *string, int *player)
-{
- ioport_manager &portdata = machine.ioport();
- int ipnum;
+ // record/playback information about the current frame
+ attotime curtime = machine().time();
+ playback_frame(curtime);
+ record_frame(curtime);
- /* check for our failsafe case first */
- if (sscanf(string, "TYPE_OTHER(%d,%d)", &ipnum, player) == 2)
- return ipnum;
+ // track the duration of the previous frame
+ m_last_delta_nsec = (curtime - m_last_frame_time).as_attoseconds() / ATTOSECONDS_PER_NANOSECOND;
+ m_last_frame_time = curtime;
- /* find the token in the list */
- for (input_type_entry *entry = portdata.typelist.first(); entry != NULL; entry = entry->next())
- if (entry->token != NULL && !strcmp(entry->token, string))
- {
- *player = entry->player;
- return entry->type;
- }
+ // update the digital joysticks
+ for (digital_joystick *joystick = m_joystick_list.first(); joystick != NULL; joystick = joystick->next())
+ joystick->frame_update();
- /* if we fail, return IPT_UNKNOWN */
- *player = 0;
- return IPT_UNKNOWN;
-}
+ // compute default values for all the ports
+ update_defaults();
+ // perform mouse hit testing
+ INT32 mouse_target_x, mouse_target_y;
+ int mouse_button;
+ render_target *mouse_target = ui_input_find_mouse(machine(), &mouse_target_x, &mouse_target_y, &mouse_button);
-/*-------------------------------------------------
- input_field_type_to_token - convert an input
- field type and player to a string token
--------------------------------------------------*/
+ // if the button is pressed, map the point and determine what was hit
+ ioport_field *mouse_field = NULL;
+ if (mouse_button && mouse_target != NULL)
+ {
+ const char *tag = NULL;
+ ioport_value mask;
+ float x, y;
+ if (mouse_target->map_point_input(mouse_target_x, mouse_target_y, tag, mask, x, y))
+ {
+ ioport_port *port = machine().root_device().ioport(tag);
+ if (port != NULL)
+ mouse_field = port->field(mask);
+ }
+ }
-static const char *input_field_type_to_token(running_machine &machine, int type, int player)
-{
- ioport_manager &portdata = machine.ioport();
- static char tempbuf[32];
+ // loop over all input ports
+ for (ioport_port *port = first_port(); port != NULL; port = port->next())
+ {
+ port->frame_update(mouse_field);
- /* look up the port and return the token */
- input_type_entry *entry = portdata.type_to_entry[type][player];
- if (entry != NULL)
- return entry->token;
+ // handle playback/record
+ playback_port(*port);
+ record_port(*port);
+ }
- /* if that fails, carry on */
- sprintf(tempbuf, "TYPE_OTHER(%d,%d)", type, player);
- return tempbuf;
+g_profiler.stop();
}
-/*-------------------------------------------------
- token_to_seq_type - convert a string to
- a sequence type
--------------------------------------------------*/
+//-------------------------------------------------
+// frame_interpolate - interpolate between two
+// values based on the time between frames
+//-------------------------------------------------
-static int token_to_seq_type(const char *string)
+ioport_value ioport_manager::frame_interpolate(ioport_value oldval, ioport_value newval)
{
- int seqindex;
+ // if no last delta, just use new value
+ if (m_last_delta_nsec == 0)
+ return newval;
- /* look up the string in the table of possible sequence types and return the index */
- for (seqindex = 0; seqindex < ARRAY_LENGTH(seqtypestrings); seqindex++)
- if (!mame_stricmp(string, seqtypestrings[seqindex]))
- return seqindex;
-
- return -1;
+ // otherwise, interpolate
+ attoseconds_t nsec_since_last = (machine().time() - m_last_frame_time).as_attoseconds() / ATTOSECONDS_PER_NANOSECOND;
+ return oldval + (INT64(newval - oldval) * nsec_since_last / m_last_delta_nsec);
}
+//-------------------------------------------------
+// load_config - callback to extract configuration
+// data from the XML nodes
+//-------------------------------------------------
-/***************************************************************************
- SETTINGS LOAD
-***************************************************************************/
-
-/*-------------------------------------------------
- load_config_callback - callback to extract
- configuration data from the XML nodes
--------------------------------------------------*/
-
-static void load_config_callback(running_machine &machine, int config_type, xml_data_node *parentnode)
+void ioport_manager::load_config(int config_type, xml_data_node *parentnode)
{
- ioport_manager &portdata = machine.ioport();
- xml_data_node *portnode;
- int seqtype;
-
- /* in the completion phase, we finish the initialization with the final ports */
+ // in the completion phase, we finish the initialization with the final ports
if (config_type == CONFIG_TYPE_FINAL)
{
- portdata.safe_to_read = TRUE;
- frame_update(machine);
+ m_safe_to_read = true;
+ frame_update();
}
- /* early exit if no data to parse */
+ // early exit if no data to parse
if (parentnode == NULL)
return;
- /* iterate over all the remap nodes for controller configs only */
+ // iterate over all the remap nodes for controller configs only
if (config_type == CONFIG_TYPE_CONTROLLER)
- load_remap_table(machine, parentnode);
+ load_remap_table(parentnode);
- /* iterate over all the port nodes */
- for (portnode = xml_get_sibling(parentnode->child, "port"); portnode; portnode = xml_get_sibling(portnode->next, "port"))
+ // iterate over all the port nodes
+ for (xml_data_node *portnode = xml_get_sibling(parentnode->child, "port"); portnode; portnode = xml_get_sibling(portnode->next, "port"))
{
- input_seq newseq[SEQ_TYPE_TOTAL], tempseq;
- xml_data_node *seqnode;
- int type, player;
+ // get the basic port info from the attributes
+ int player;
+ int type = token_to_input_type(xml_get_attribute_string(portnode, "type", ""), player);
- /* get the basic port info from the attributes */
- type = token_to_input_field_type(machine, xml_get_attribute_string(portnode, "type", ""), &player);
-
- /* initialize sequences to invalid defaults */
- for (seqtype = 0; seqtype < ARRAY_LENGTH(newseq); seqtype++)
+ // initialize sequences to invalid defaults
+ input_seq newseq[SEQ_TYPE_TOTAL];
+ for (input_seq_type seqtype = SEQ_TYPE_STANDARD; seqtype < SEQ_TYPE_TOTAL; seqtype++)
newseq[seqtype].set(INPUT_CODE_INVALID);
- /* loop over new sequences */
- for (seqnode = xml_get_sibling(portnode->child, "newseq"); seqnode; seqnode = xml_get_sibling(seqnode->next, "newseq"))
+ // loop over new sequences
+ for (xml_data_node *seqnode = xml_get_sibling(portnode->child, "newseq"); seqnode; seqnode = xml_get_sibling(seqnode->next, "newseq"))
{
- /* with a valid type, parse out the new sequence */
- seqtype = token_to_seq_type(xml_get_attribute_string(seqnode, "type", ""));
+ // with a valid type, parse out the new sequence
+ input_seq_type seqtype = token_to_seq_type(xml_get_attribute_string(seqnode, "type", ""));
if (seqtype != -1 && seqnode->value != NULL)
{
if (strcmp(seqnode->value, "NONE") == 0)
newseq[seqtype].set();
else
- machine.input().seq_from_tokens(newseq[seqtype], seqnode->value);
+ machine().input().seq_from_tokens(newseq[seqtype], seqnode->value);
}
}
- /* if we're loading default ports, apply to the defaults */
+ // if we're loading default ports, apply to the defaults
if (config_type != CONFIG_TYPE_GAME)
- load_default_config(machine, portnode, type, player, newseq);
+ load_default_config(portnode, type, player, newseq);
else
- load_game_config(machine, portnode, type, player, newseq);
+ load_game_config(portnode, type, player, newseq);
}
- /* after applying the controller config, push that back into the backup, since that is */
- /* what we will diff against */
+ // after applying the controller config, push that back into the backup, since that is
+ // what we will diff against
if (config_type == CONFIG_TYPE_CONTROLLER)
- for (input_type_entry *entry = portdata.typelist.first(); entry != NULL; entry = entry->next())
- for (seqtype = 0; seqtype < ARRAY_LENGTH(entry->seq); seqtype++)
- entry->defseq[seqtype] = entry->seq[seqtype];
+ for (input_type_entry *entry = m_typelist.first(); entry != NULL; entry = entry->next())
+ for (input_seq_type seqtype = SEQ_TYPE_STANDARD; seqtype < SEQ_TYPE_TOTAL; seqtype++)
+ entry->defseq(seqtype) = entry->seq(seqtype);
}
-/*-------------------------------------------------
- load_remap_table - extract and apply the
- global remapping table
--------------------------------------------------*/
+//-------------------------------------------------
+// load_remap_table - extract and apply the
+// global remapping table
+//-------------------------------------------------
-static void load_remap_table(running_machine &machine, xml_data_node *parentnode)
+void ioport_manager::load_remap_table(xml_data_node *parentnode)
{
- ioport_manager &portdata = machine.ioport();
- input_code *oldtable, *newtable;
- xml_data_node *remapnode;
- int count;
-
- /* count items first so we can allocate */
- count = 0;
- for (remapnode = xml_get_sibling(parentnode->child, "remap"); remapnode != NULL; remapnode = xml_get_sibling(remapnode->next, "remap"))
+ // count items first so we can allocate
+ int count = 0;
+ for (xml_data_node *remapnode = xml_get_sibling(parentnode->child, "remap"); remapnode != NULL; remapnode = xml_get_sibling(remapnode->next, "remap"))
count++;
- /* if we have some, deal with them */
+ // if we have some, deal with them
if (count > 0)
{
- int remapnum;
-
- /* allocate tables */
- oldtable = global_alloc_array(input_code, count);
- newtable = global_alloc_array(input_code, count);
+ // allocate tables
+ dynamic_array<input_code> oldtable(count);
+ dynamic_array<input_code> newtable(count);
- /* build up the remap table */
+ // build up the remap table
count = 0;
- for (remapnode = xml_get_sibling(parentnode->child, "remap"); remapnode != NULL; remapnode = xml_get_sibling(remapnode->next, "remap"))
+ for (xml_data_node *remapnode = xml_get_sibling(parentnode->child, "remap"); remapnode != NULL; remapnode = xml_get_sibling(remapnode->next, "remap"))
{
- input_code origcode = machine.input().code_from_token(xml_get_attribute_string(remapnode, "origcode", ""));
- input_code newcode = machine.input().code_from_token(xml_get_attribute_string(remapnode, "newcode", ""));
+ input_code origcode = machine().input().code_from_token(xml_get_attribute_string(remapnode, "origcode", ""));
+ input_code newcode = machine().input().code_from_token(xml_get_attribute_string(remapnode, "newcode", ""));
if (origcode != INPUT_CODE_INVALID && newcode != INPUT_CODE_INVALID)
{
oldtable[count] = origcode;
@@ -3214,214 +3115,187 @@ static void load_remap_table(running_machine &machine, xml_data_node *parentnode
}
}
- /* loop over the remapping table, operating only if something was specified */
- for (remapnum = 0; remapnum < count; remapnum++)
- {
- input_code oldcode = oldtable[remapnum];
- input_code newcode = newtable[remapnum];
-
- /* loop over all default ports, remapping the requested keys */
- for (input_type_entry *entry = portdata.typelist.first(); entry != NULL; entry = entry->next())
- {
- /* remap anything in the default sequences */
- for (int seqtype = 0; seqtype < ARRAY_LENGTH(entry->seq); seqtype++)
- entry->seq[seqtype].replace(oldcode, newcode);
- }
- }
-
- /* release the tables */
- global_free(oldtable);
- global_free(newtable);
+ // loop over the remapping table, then over default ports, replacing old with new
+ for (int remapnum = 0; remapnum < count; remapnum++)
+ for (input_type_entry *entry = m_typelist.first(); entry != NULL; entry = entry->next())
+ for (input_seq_type seqtype = SEQ_TYPE_STANDARD; seqtype < SEQ_TYPE_TOTAL; seqtype++)
+ entry->m_seq[seqtype].replace(oldtable[remapnum], newtable[remapnum]);
}
}
-/*-------------------------------------------------
- load_default_config - apply configuration
- data to the default mappings
--------------------------------------------------*/
+//-------------------------------------------------
+// load_default_config - apply configuration
+// data to the default mappings
+//-------------------------------------------------
-static int load_default_config(running_machine &machine, xml_data_node *portnode, int type, int player, const input_seq *newseq)
+bool ioport_manager::load_default_config(xml_data_node *portnode, int type, int player, const input_seq *newseq)
{
- ioport_manager &portdata = machine.ioport();
-
- /* find a matching port in the list */
- for (input_type_entry *entry = portdata.typelist.first(); entry != NULL; entry = entry->next())
- if (entry->type == type && entry->player == player)
+ // find a matching port in the list
+ for (input_type_entry *entry = m_typelist.first(); entry != NULL; entry = entry->next())
+ if (entry->type() == type && entry->player() == player)
{
- for (int seqtype = 0; seqtype < ARRAY_LENGTH(entry->seq); seqtype++)
+ for (input_seq_type seqtype = SEQ_TYPE_STANDARD; seqtype < SEQ_TYPE_TOTAL; seqtype++)
if (newseq[seqtype][0] != INPUT_CODE_INVALID)
- entry->seq[seqtype] = newseq[seqtype];
- return TRUE;
+ entry->m_seq[seqtype] = newseq[seqtype];
+ return true;
}
- return FALSE;
+ return false;
}
-/*-------------------------------------------------
- load_game_config - apply configuration
- data to the current set of input ports
--------------------------------------------------*/
+//-------------------------------------------------
+// load_game_config - apply configuration
+// data to the current set of input ports
+//-------------------------------------------------
-static int load_game_config(running_machine &machine, xml_data_node *portnode, int type, int player, const input_seq *newseq)
+bool ioport_manager::load_game_config(xml_data_node *portnode, int type, int player, const input_seq *newseq)
{
- input_port_value mask, defvalue;
- const input_field_config *field;
- const input_port_config *port;
- char tempbuffer[20];
- const char *tag;
-
- /* read the mask, index, and defvalue attributes */
- tag = xml_get_attribute_string(portnode, "tag", NULL);
- mask = xml_get_attribute_int(portnode, "mask", 0);
- defvalue = xml_get_attribute_int(portnode, "defvalue", 0);
+ // read the mask, index, and defvalue attributes
+ const char *tag = xml_get_attribute_string(portnode, "tag", NULL);
+ ioport_value mask = xml_get_attribute_int(portnode, "mask", 0);
+ ioport_value defvalue = xml_get_attribute_int(portnode, "defvalue", 0);
- /* find the port we want; if no tag, search them all */
- for (port = machine.ioport().first_port(); port != NULL; port = port->next())
- if (tag == NULL || strcmp(get_port_tag(port, tempbuffer), tag) == 0)
- for (field = port->first_field(); field != NULL; field = field->next())
+ // find the port we want; if no tag, search them all
+ for (ioport_port *port = first_port(); port != NULL; port = port->next())
+ if (tag == NULL || strcmp(port->tag(), tag) == 0)
+ for (ioport_field *field = port->first_field(); field != NULL; field = field->next())
- /* find the matching mask and defvalue */
- if (field->type == type && field->player == player &&
- field->mask == mask && (field->defvalue & mask) == (defvalue & mask))
+ // find the matching mask and defvalue
+ if (field->type() == type && field->player() == player &&
+ field->mask() == mask && (field->defvalue() & mask) == (defvalue & mask))
{
- const char *revstring;
- int seqtype;
-
- /* if a sequence was specified, copy it in */
- for (seqtype = 0; seqtype < ARRAY_LENGTH(field->state->seq); seqtype++)
+ // if a sequence was specified, copy it in
+ for (input_seq_type seqtype = SEQ_TYPE_STANDARD; seqtype < SEQ_TYPE_TOTAL; seqtype++)
if (newseq[seqtype][0] != INPUT_CODE_INVALID)
- field->state->seq[seqtype] = newseq[seqtype];
+ field->live().seq[seqtype] = newseq[seqtype];
- /* for non-analog fields, fetch the value */
- if (field->state->analog == NULL)
- field->state->value = xml_get_attribute_int(portnode, "value", field->defvalue);
+ // for non-analog fields, fetch the value
+ if (field->live().analog == NULL)
+ field->live().value = xml_get_attribute_int(portnode, "value", field->defvalue());
- /* for analog fields, fetch configurable analog attributes */
+ // for analog fields, fetch configurable analog attributes
else
{
- /* get base attributes */
- field->state->analog->delta = xml_get_attribute_int(portnode, "keydelta", field->delta);
- field->state->analog->centerdelta = xml_get_attribute_int(portnode, "centerdelta", field->centerdelta);
- field->state->analog->sensitivity = xml_get_attribute_int(portnode, "sensitivity", field->sensitivity);
+ // get base attributes
+ field->live().analog->m_delta = xml_get_attribute_int(portnode, "keydelta", field->delta());
+ field->live().analog->m_centerdelta = xml_get_attribute_int(portnode, "centerdelta", field->centerdelta());
+ field->live().analog->m_sensitivity = xml_get_attribute_int(portnode, "sensitivity", field->sensitivity());
- /* fetch yes/no for reverse setting */
- revstring = xml_get_attribute_string(portnode, "reverse", NULL);
+ // fetch yes/no for reverse setting
+ const char *revstring = xml_get_attribute_string(portnode, "reverse", NULL);
if (revstring != NULL)
- field->state->analog->reverse = (strcmp(revstring, "yes") == 0);
+ field->live().analog->m_reverse = (strcmp(revstring, "yes") == 0);
}
- return TRUE;
+ return true;
}
- return FALSE;
+ return false;
}
-/***************************************************************************
- SETTINGS SAVE
-***************************************************************************/
+//**************************************************************************
+// SETTINGS SAVE
+//**************************************************************************
-/*-------------------------------------------------
- save_config_callback - config callback for
- saving input port configuration
--------------------------------------------------*/
+//-------------------------------------------------
+// save_config - config callback for saving input
+// port configuration
+//-------------------------------------------------
-static void save_config_callback(running_machine &machine, int config_type, xml_data_node *parentnode)
+void ioport_manager::save_config(int config_type, xml_data_node *parentnode)
{
- /* if no parentnode, ignore */
+ // if no parentnode, ignore
if (parentnode == NULL)
return;
- /* default ports save differently */
+ // default ports save differently
if (config_type == CONFIG_TYPE_DEFAULT)
- save_default_inputs(machine, parentnode);
+ save_default_inputs(parentnode);
else
- save_game_inputs(machine, parentnode);
+ save_game_inputs(parentnode);
}
-/*-------------------------------------------------
- save_sequence - add a node for an input
- sequence
--------------------------------------------------*/
+//-------------------------------------------------
+// save_sequence - add a node for an input
+// sequence
+//-------------------------------------------------
-static void save_sequence(running_machine &machine, xml_data_node *parentnode, int type, int porttype, const input_seq &seq)
+void ioport_manager::save_sequence(xml_data_node *parentnode, input_seq_type type, ioport_type porttype, const input_seq &seq)
{
+ // get the string for the sequence
astring seqstring;
- xml_data_node *seqnode;
-
- /* get the string for the sequence */
if (seq.length() == 0)
seqstring.cpy("NONE");
else
- machine.input().seq_to_tokens(seqstring, seq);
+ machine().input().seq_to_tokens(seqstring, seq);
- /* add the new node */
- seqnode = xml_add_child(parentnode, "newseq", seqstring);
+ // add the new node
+ xml_data_node *seqnode = xml_add_child(parentnode, "newseq", seqstring);
if (seqnode != NULL)
xml_set_attribute(seqnode, "type", seqtypestrings[type]);
}
-/*-------------------------------------------------
- save_this_input_field_type - determine if the given
- port type is worth saving
--------------------------------------------------*/
+//-------------------------------------------------
+// save_this_input_field_type - determine if the
+// given port type is worth saving
+//-------------------------------------------------
-static int save_this_input_field_type(int type)
+bool ioport_manager::save_this_input_field_type(ioport_type type)
{
switch (type)
{
case IPT_UNUSED:
case IPT_END:
case IPT_PORT:
- case IPT_VBLANK:
case IPT_UNKNOWN:
- return FALSE;
+ return false;
+
+ default:
+ break;
}
- return TRUE;
+ return true;
}
-/*-------------------------------------------------
- save_default_inputs - add nodes for any default
- mappings that have changed
--------------------------------------------------*/
+//-------------------------------------------------
+// save_default_inputs - add nodes for any default
+// mappings that have changed
+//-------------------------------------------------
-static void save_default_inputs(running_machine &machine, xml_data_node *parentnode)
+void ioport_manager::save_default_inputs(xml_data_node *parentnode)
{
- ioport_manager &portdata = machine.ioport();
- input_type_entry *entry;
-
- /* iterate over ports */
- for (entry = portdata.typelist.first(); entry != NULL; entry = entry->next())
+ // iterate over ports
+ for (input_type_entry *entry = m_typelist.first(); entry != NULL; entry = entry->next())
{
- /* only save if this port is a type we save */
- if (save_this_input_field_type(entry->type))
+ // only save if this port is a type we save
+ if (save_this_input_field_type(entry->type()))
{
- int seqtype;
-
- /* see if any of the sequences have changed */
- for (seqtype = 0; seqtype < ARRAY_LENGTH(entry->seq); seqtype++)
- if (entry->seq[seqtype] != entry->defseq[seqtype])
+ // see if any of the sequences have changed
+ input_seq_type seqtype;
+ for (seqtype = SEQ_TYPE_STANDARD; seqtype < SEQ_TYPE_TOTAL; seqtype++)
+ if (entry->seq(seqtype) != entry->defseq(seqtype))
break;
- /* if so, we need to add a node */
- if (seqtype < ARRAY_LENGTH(entry->seq))
+ // if so, we need to add a node
+ if (seqtype < SEQ_TYPE_TOTAL)
{
- /* add a new port node */
+ // add a new port node
xml_data_node *portnode = xml_add_child(parentnode, "port", NULL);
if (portnode != NULL)
{
- /* add the port information and attributes */
- xml_set_attribute(portnode, "type", input_field_type_to_token(machine, entry->type, entry->player));
-
- /* add only the sequences that have changed from the defaults */
- for (seqtype = 0; seqtype < ARRAY_LENGTH(entry->seq); seqtype++)
- if (entry->seq[seqtype] != entry->defseq[seqtype])
- save_sequence(machine, portnode, seqtype, entry->type, entry->seq[seqtype]);
+ // add the port information and attributes
+ astring tempstr;
+ xml_set_attribute(portnode, "type", input_type_to_token(tempstr, entry->type(), entry->player()));
+
+ // add only the sequences that have changed from the defaults
+ for (input_seq_type seqtype = SEQ_TYPE_STANDARD; seqtype < SEQ_TYPE_TOTAL; seqtype++)
+ if (entry->seq(seqtype) != entry->defseq(seqtype))
+ save_sequence(portnode, seqtype, entry->type(), entry->seq(seqtype));
}
}
}
@@ -3429,79 +3303,73 @@ static void save_default_inputs(running_machine &machine, xml_data_node *parentn
}
-/*-------------------------------------------------
- save_game_inputs - add nodes for any game
- mappings that have changed
--------------------------------------------------*/
+//-------------------------------------------------
+// save_game_inputs - add nodes for any game
+// mappings that have changed
+//-------------------------------------------------
-static void save_game_inputs(running_machine &machine, xml_data_node *parentnode)
+void ioport_manager::save_game_inputs(xml_data_node *parentnode)
{
- const input_field_config *field;
- const input_port_config *port;
-
- /* iterate over ports */
- for (port = machine.ioport().first_port(); port != NULL; port = port->next())
- for (field = port->first_field(); field != NULL; field = field->next())
- if (save_this_input_field_type(field->type))
+ // iterate over ports
+ for (ioport_port *port = machine().ioport().first_port(); port != NULL; port = port->next())
+ for (ioport_field *field = port->first_field(); field != NULL; field = field->next())
+ if (save_this_input_field_type(field->type()))
{
+ // determine if we changed
bool changed = false;
- int seqtype;
+ for (input_seq_type seqtype = SEQ_TYPE_STANDARD; seqtype < SEQ_TYPE_TOTAL; seqtype++)
+ changed |= (field->live().seq[seqtype] != field->seq(seqtype));
- /* determine if we changed */
- for (seqtype = 0; seqtype < ARRAY_LENGTH(field->state->seq); seqtype++)
- changed |= (field->state->seq[seqtype] != field->seq[seqtype]);
+ // non-analog changes
+ if (field->live().analog == NULL)
+ changed |= ((field->live().value & field->mask()) != (field->defvalue() & field->mask()));
- /* non-analog changes */
- if (field->state->analog == NULL)
- changed |= ((field->state->value & field->mask) != (field->defvalue & field->mask));
-
- /* analog changes */
+ // analog changes
else
{
- changed |= (field->state->analog->delta != field->delta);
- changed |= (field->state->analog->centerdelta != field->centerdelta);
- changed |= (field->state->analog->sensitivity != field->sensitivity);
- changed |= (field->state->analog->reverse != ((field->flags & ANALOG_FLAG_REVERSE) != 0));
+ changed |= (field->live().analog->m_delta != field->delta());
+ changed |= (field->live().analog->m_centerdelta != field->centerdelta());
+ changed |= (field->live().analog->m_sensitivity != field->sensitivity());
+ changed |= (field->live().analog->m_reverse != field->analog_reverse());
}
- /* if we did change, add a new node */
+ // if we did change, add a new node
if (changed)
{
- /* add a new port node */
+ // add a new port node
xml_data_node *portnode = xml_add_child(parentnode, "port", NULL);
if (portnode != NULL)
{
- char tempbuffer[20];
-
- /* add the identifying information and attributes */
- xml_set_attribute(portnode, "tag", get_port_tag(port, tempbuffer));
- xml_set_attribute(portnode, "type", input_field_type_to_token(machine, field->type, field->player));
- xml_set_attribute_int(portnode, "mask", field->mask);
- xml_set_attribute_int(portnode, "defvalue", field->defvalue & field->mask);
-
- /* add sequences if changed */
- for (seqtype = 0; seqtype < ARRAY_LENGTH(field->state->seq); seqtype++)
- if (field->state->seq[seqtype] != field->seq[seqtype])
- save_sequence(machine, portnode, seqtype, field->type, field->state->seq[seqtype]);
-
- /* write out non-analog changes */
- if (field->state->analog == NULL)
+ // add the identifying information and attributes
+ astring tempstr;
+ xml_set_attribute(portnode, "tag", port->tag());
+ xml_set_attribute(portnode, "type", input_type_to_token(tempstr, field->type(), field->player()));
+ xml_set_attribute_int(portnode, "mask", field->mask());
+ xml_set_attribute_int(portnode, "defvalue", field->defvalue() & field->mask());
+
+ // add sequences if changed
+ for (input_seq_type seqtype = SEQ_TYPE_STANDARD; seqtype < SEQ_TYPE_TOTAL; seqtype++)
+ if (field->live().seq[seqtype] != field->seq(seqtype))
+ save_sequence(portnode, seqtype, field->type(), field->live().seq[seqtype]);
+
+ // write out non-analog changes
+ if (field->live().analog == NULL)
{
- if ((field->state->value & field->mask) != (field->defvalue & field->mask))
- xml_set_attribute_int(portnode, "value", field->state->value & field->mask);
+ if ((field->live().value & field->mask()) != (field->defvalue() & field->mask()))
+ xml_set_attribute_int(portnode, "value", field->live().value & field->mask());
}
- /* write out analog changes */
+ // write out analog changes
else
{
- if (field->state->analog->delta != field->delta)
- xml_set_attribute_int(portnode, "keydelta", field->state->analog->delta);
- if (field->state->analog->centerdelta != field->centerdelta)
- xml_set_attribute_int(portnode, "centerdelta", field->state->analog->centerdelta);
- if (field->state->analog->sensitivity != field->sensitivity)
- xml_set_attribute_int(portnode, "sensitivity", field->state->analog->sensitivity);
- if (field->state->analog->reverse != ((field->flags & ANALOG_FLAG_REVERSE) != 0))
- xml_set_attribute(portnode, "reverse", field->state->analog->reverse ? "yes" : "no");
+ if (field->live().analog->m_delta != field->delta())
+ xml_set_attribute_int(portnode, "keydelta", field->live().analog->m_delta);
+ if (field->live().analog->m_centerdelta != field->centerdelta())
+ xml_set_attribute_int(portnode, "centerdelta", field->live().analog->m_centerdelta);
+ if (field->live().analog->m_sensitivity != field->sensitivity())
+ xml_set_attribute_int(portnode, "sensitivity", field->live().analog->m_sensitivity);
+ if (field->live().analog->m_reverse != field->analog_reverse())
+ xml_set_attribute(portnode, "reverse", field->live().analog->m_reverse ? "yes" : "no");
}
}
}
@@ -3510,311 +3378,212 @@ static void save_game_inputs(running_machine &machine, xml_data_node *parentnode
-/***************************************************************************
- INPUT PLAYBACK
-***************************************************************************/
+//**************************************************************************
+// INPUT PLAYBACK
+//**************************************************************************
-/*-------------------------------------------------
- playback_read_uint8 - read an 8-bit value
- from the playback file
--------------------------------------------------*/
+//-------------------------------------------------
+// playback_read - read a value from the playback
+// file
+//-------------------------------------------------
-static UINT8 playback_read_uint8(running_machine &machine)
+template<typename _Type>
+_Type ioport_manager::playback_read(_Type &result)
{
- ioport_manager &portdata = machine.ioport();
- UINT8 result;
+ // protect against NULL handles if previous reads fail
+ if (!m_playback_file.is_open())
+ result = 0;
- /* protect against NULL handles if previous reads fail */
- if (portdata.playback_file == NULL)
- return 0;
-
- /* read the value; if we fail, end playback */
- if (portdata.playback_file->read(&result, sizeof(result)) != sizeof(result))
+ // read the value; if we fail, end playback
+ else if (m_playback_file.read(&result, sizeof(result)) != sizeof(result))
{
- playback_end(machine, "End of file");
- return 0;
+ playback_end("End of file");
+ result = 0;
}
- /* return the appropriate value */
+ // return the appropriate value
+ else if (sizeof(result) == 8)
+ result = LITTLE_ENDIANIZE_INT64(result);
+ else if (sizeof(result) == 4)
+ result = LITTLE_ENDIANIZE_INT32(result);
+ else if (sizeof(result) == 2)
+ result = LITTLE_ENDIANIZE_INT16(result);
return result;
}
-
-/*-------------------------------------------------
- playback_read_uint32 - read a 32-bit value
- from the playback file
--------------------------------------------------*/
-
-static UINT32 playback_read_uint32(running_machine &machine)
-{
- ioport_manager &portdata = machine.ioport();
- UINT32 result;
-
- /* protect against NULL handles if previous reads fail */
- if (portdata.playback_file == NULL)
- return 0;
-
- /* read the value; if we fail, end playback */
- if (portdata.playback_file->read(&result, sizeof(result)) != sizeof(result))
- {
- playback_end(machine, "End of file");
- return 0;
- }
-
- /* return the appropriate value */
- return LITTLE_ENDIANIZE_INT32(result);
-}
-
-
-/*-------------------------------------------------
- playback_read_uint64 - read a 64-bit value
- from the playback file
--------------------------------------------------*/
-
-static UINT64 playback_read_uint64(running_machine &machine)
+template<>
+bool ioport_manager::playback_read<bool>(bool &result)
{
- ioport_manager &portdata = machine.ioport();
- UINT64 result;
-
- /* protect against NULL handles if previous reads fail */
- if (portdata.playback_file == NULL)
- return 0;
-
- /* read the value; if we fail, end playback */
- if (portdata.playback_file->read(&result, sizeof(result)) != sizeof(result))
- {
- playback_end(machine, "End of file");
- return 0;
- }
-
- /* return the appropriate value */
- return LITTLE_ENDIANIZE_INT64(result);
+ UINT8 temp;
+ playback_read(temp);
+ return result = bool(temp);
}
-/*-------------------------------------------------
- playback_init - initialize INP playback
--------------------------------------------------*/
+//-------------------------------------------------
+// playback_init - initialize INP playback
+//-------------------------------------------------
-static time_t playback_init(running_machine &machine)
+time_t ioport_manager::playback_init()
{
- const char *filename = machine.options().playback();
- ioport_manager &portdata = machine.ioport();
- UINT8 header[INP_HEADER_SIZE];
- time_t basetime;
-
- /* if no file, nothing to do */
+ // if no file, nothing to do
+ const char *filename = machine().options().playback();
if (filename[0] == 0)
return 0;
- /* open the playback file */
- portdata.playback_file = auto_alloc(machine, emu_file(machine.options().input_directory(), OPEN_FLAG_READ));
- file_error filerr = portdata.playback_file->open(filename);
+ // open the playback file
+ file_error filerr = m_playback_file.open(filename);
assert_always(filerr == FILERR_NONE, "Failed to open file for playback");
- /* read the header and verify that it is a modern version; if not, print an error */
- if (portdata.playback_file->read(header, sizeof(header)) != sizeof(header))
+ // read the header and verify that it is a modern version; if not, print an error
+ UINT8 header[INP_HEADER_SIZE];
+ if (m_playback_file.read(header, sizeof(header)) != sizeof(header))
fatalerror("Input file is corrupt or invalid (missing header)");
if (memcmp(header, "MAMEINP\0", 8) != 0)
fatalerror("Input file invalid or in an older, unsupported format");
if (header[0x10] != INP_HEADER_MAJVERSION)
fatalerror("Input file format version mismatch");
- /* output info to console */
+ // output info to console
mame_printf_info("Input file: %s\n", filename);
mame_printf_info("INP version %d.%d\n", header[0x10], header[0x11]);
- basetime = header[0x08] | (header[0x09] << 8) | (header[0x0a] << 16) | (header[0x0b] << 24) |
- ((UINT64)header[0x0c] << 32) | ((UINT64)header[0x0d] << 40) | ((UINT64)header[0x0e] << 48) | ((UINT64)header[0x0f] << 56);
+ time_t basetime = header[0x08] | (header[0x09] << 8) | (header[0x0a] << 16) | (header[0x0b] << 24) |
+ ((UINT64)header[0x0c] << 32) | ((UINT64)header[0x0d] << 40) | ((UINT64)header[0x0e] << 48) | ((UINT64)header[0x0f] << 56);
mame_printf_info("Created %s", ctime(&basetime));
mame_printf_info("Recorded using %s\n", header + 0x20);
- /* verify the header against the current game */
- if (memcmp(machine.system().name, header + 0x14, strlen(machine.system().name) + 1) != 0)
- mame_printf_info("Input file is for %s '%s', not for current %s '%s'\n", emulator_info::get_gamenoun(), header + 0x14, emulator_info::get_gamenoun(), machine.system().name);
-
- /* enable compression */
- portdata.playback_file->compress(FCOMPRESS_MEDIUM);
+ // verify the header against the current game
+ if (memcmp(machine().system().name, header + 0x14, strlen(machine().system().name) + 1) != 0)
+ mame_printf_info("Input file is for %s '%s', not for current %s '%s'\n", emulator_info::get_gamenoun(), header + 0x14, emulator_info::get_gamenoun(), machine().system().name);
+ // enable compression
+ m_playback_file.compress(FCOMPRESS_MEDIUM);
return basetime;
}
-/*-------------------------------------------------
- playback_end - end INP playback
--------------------------------------------------*/
+//-------------------------------------------------
+// playback_end - end INP playback
+//-------------------------------------------------
-static void playback_end(running_machine &machine, const char *message)
+void ioport_manager::playback_end(const char *message)
{
- ioport_manager &portdata = machine.ioport();
-
- /* only applies if we have a live file */
- if (portdata.playback_file != NULL)
+ // only applies if we have a live file
+ if (m_playback_file.is_open())
{
- /* close the file */
- auto_free(machine, portdata.playback_file);
- portdata.playback_file = NULL;
+ // close the file
+ m_playback_file.close();
- /* pop a message */
+ // pop a message
if (message != NULL)
popmessage("Playback Ended\nReason: %s", message);
- /* display speed stats */
- portdata.playback_accumulated_speed /= portdata.playback_accumulated_frames;
- mame_printf_info("Total playback frames: %d\n", (UINT32)portdata.playback_accumulated_frames);
- mame_printf_info("Average recorded speed: %d%%\n", (UINT32)((portdata.playback_accumulated_speed * 200 + 1) >> 21));
+ // display speed stats
+ m_playback_accumulated_speed /= m_playback_accumulated_frames;
+ mame_printf_info("Total playback frames: %d\n", UINT32(m_playback_accumulated_frames));
+ mame_printf_info("Average recorded speed: %d%%\n", UINT32((m_playback_accumulated_speed * 200 + 1) >> 21));
}
}
-/*-------------------------------------------------
- playback_frame - start of frame callback for
- playback
--------------------------------------------------*/
+//-------------------------------------------------
+// playback_frame - start of frame callback for
+// playback
+//-------------------------------------------------
-static void playback_frame(running_machine &machine, attotime curtime)
+void ioport_manager::playback_frame(attotime curtime)
{
- ioport_manager &portdata = machine.ioport();
-
- /* if playing back, fetch the information and verify */
- if (portdata.playback_file != NULL)
+ // if playing back, fetch the information and verify
+ if (m_playback_file.is_open())
{
+ // first the absolute time
attotime readtime;
-
- /* first the absolute time */
- readtime.seconds = playback_read_uint32(machine);
- readtime.attoseconds = playback_read_uint64(machine);
+ playback_read(readtime.seconds);
+ playback_read(readtime.attoseconds);
if (readtime != curtime)
- playback_end(machine, "Out of sync");
+ playback_end("Out of sync");
- /* then the speed */
- portdata.playback_accumulated_speed += playback_read_uint32(machine);
- portdata.playback_accumulated_frames++;
+ // then the speed
+ UINT32 curspeed;
+ m_playback_accumulated_speed += playback_read(curspeed);
+ m_playback_accumulated_frames++;
}
}
-/*-------------------------------------------------
- playback_port - per-port callback for playback
--------------------------------------------------*/
+//-------------------------------------------------
+// playback_port - per-port callback for playback
+//-------------------------------------------------
-static void playback_port(const input_port_config *port)
+void ioport_manager::playback_port(ioport_port &port)
{
- ioport_manager &portdata = port->machine().ioport();
-
- /* if playing back, fetch information about this port */
- if (portdata.playback_file != NULL)
+ // if playing back, fetch information about this port
+ if (m_playback_file.is_open())
{
- analog_field_state *analog;
-
- /* read the default value and the digital state */
- port->state->defvalue = playback_read_uint32(port->machine());
- port->state->digital = playback_read_uint32(port->machine());
+ // read the default value and the digital state
+ playback_read(port.live().defvalue);
+ playback_read(port.live().digital);
- /* loop over analog ports and save their data */
- for (analog = port->state->analoglist; analog != NULL; analog = analog->next)
+ // loop over analog ports and save their data
+ for (analog_field *analog = port.live().analoglist.first(); analog != NULL; analog = analog->next())
{
- /* read current and previous values */
- analog->accum = playback_read_uint32(port->machine());
- analog->previous = playback_read_uint32(port->machine());
+ // read current and previous values
+ playback_read(analog->m_accum);
+ playback_read(analog->m_previous);
- /* read configuration information */
- analog->sensitivity = playback_read_uint32(port->machine());
- analog->reverse = playback_read_uint8(port->machine());
+ // read configuration information
+ playback_read(analog->m_sensitivity);
+ playback_read(analog->m_reverse);
}
}
}
+//-------------------------------------------------
+// record_write - write a value to the record file
+//-------------------------------------------------
-/***************************************************************************
- INPUT RECORDING
-***************************************************************************/
-
-/*-------------------------------------------------
- record_write_uint8 - write an 8-bit value
- to the record file
--------------------------------------------------*/
-
-static void record_write_uint8(running_machine &machine, UINT8 data)
+template<typename _Type>
+void ioport_manager::record_write(_Type value)
{
- ioport_manager &portdata = machine.ioport();
- UINT8 result = data;
-
- /* protect against NULL handles if previous reads fail */
- if (portdata.record_file == NULL)
- return;
-
- /* read the value; if we fail, end playback */
- if (portdata.record_file->write(&result, sizeof(result)) != sizeof(result))
- record_end(machine, "Out of space");
-}
-
-
-/*-------------------------------------------------
- record_write_uint32 - write a 32-bit value
- to the record file
--------------------------------------------------*/
-
-static void record_write_uint32(running_machine &machine, UINT32 data)
-{
- ioport_manager &portdata = machine.ioport();
- UINT32 result = LITTLE_ENDIANIZE_INT32(data);
-
- /* protect against NULL handles if previous reads fail */
- if (portdata.record_file == NULL)
+ // protect against NULL handles if previous reads fail
+ if (!m_record_file.is_open())
return;
- /* read the value; if we fail, end playback */
- if (portdata.record_file->write(&result, sizeof(result)) != sizeof(result))
- record_end(machine, "Out of space");
+ // read the value; if we fail, end playback
+ if (m_record_file.write(&value, sizeof(value)) != sizeof(value))
+ record_end("Out of space");
}
-
-/*-------------------------------------------------
- record_write_uint64 - write a 64-bit value
- to the record file
--------------------------------------------------*/
-
-static void record_write_uint64(running_machine &machine, UINT64 data)
+template<>
+void ioport_manager::record_write<bool>(bool value)
{
- ioport_manager &portdata = machine.ioport();
- UINT64 result = LITTLE_ENDIANIZE_INT64(data);
-
- /* protect against NULL handles if previous reads fail */
- if (portdata.record_file == NULL)
- return;
-
- /* read the value; if we fail, end playback */
- if (portdata.record_file->write(&result, sizeof(result)) != sizeof(result))
- record_end(machine, "Out of space");
+ UINT8 byte = UINT8(value);
+ record_write(byte);
}
-/*-------------------------------------------------
- record_init - initialize INP recording
--------------------------------------------------*/
+//-------------------------------------------------
+// record_init - initialize INP recording
+//-------------------------------------------------
-static void record_init(running_machine &machine)
+void ioport_manager::record_init()
{
- const char *filename = machine.options().record();
- ioport_manager &portdata = machine.ioport();
- UINT8 header[INP_HEADER_SIZE];
- system_time systime;
-
- /* if no file, nothing to do */
+ // if no file, nothing to do
+ const char *filename = machine().options().record();
if (filename[0] == 0)
return;
- /* open the record file */
- portdata.record_file = auto_alloc(machine, emu_file(machine.options().input_directory(), OPEN_FLAG_WRITE | OPEN_FLAG_CREATE | OPEN_FLAG_CREATE_PATHS));
- file_error filerr = portdata.record_file->open(filename);
+ // open the record file
+ file_error filerr = m_record_file.open(filename);
assert_always(filerr == FILERR_NONE, "Failed to open file for recording");
- /* get the base time */
- machine.base_datetime(systime);
+ // get the base time
+ system_time systime;
+ machine().base_datetime(systime);
- /* fill in the header */
- memset(header, 0, sizeof(header));
+ // fill in the header
+ UINT8 header[INP_HEADER_SIZE] = { 0 };
memcpy(header, "MAMEINP\0", 8);
header[0x08] = systime.time >> 0;
header[0x09] = systime.time >> 8;
@@ -3826,1042 +3595,922 @@ static void record_init(running_machine &machine)
header[0x0f] = systime.time >> 56;
header[0x10] = INP_HEADER_MAJVERSION;
header[0x11] = INP_HEADER_MINVERSION;
- strcpy((char *)header + 0x14, machine.system().name);
+ strcpy((char *)header + 0x14, machine().system().name);
sprintf((char *)header + 0x20, "%s %s", emulator_info::get_appname(), build_version);
- /* write it */
- portdata.record_file->write(header, sizeof(header));
+ // write it
+ m_record_file.write(header, sizeof(header));
- /* enable compression */
- portdata.record_file->compress(FCOMPRESS_MEDIUM);
+ // enable compression
+ m_record_file.compress(FCOMPRESS_MEDIUM);
}
-/*-------------------------------------------------
- record_end - end INP recording
--------------------------------------------------*/
+//-------------------------------------------------
+// record_end - end INP recording
+//-------------------------------------------------
-static void record_end(running_machine &machine, const char *message)
+void ioport_manager::record_end(const char *message)
{
- ioport_manager &portdata = machine.ioport();
-
- /* only applies if we have a live file */
- if (portdata.record_file != NULL)
+ // only applies if we have a live file
+ if (m_record_file.is_open())
{
- /* close the file */
- auto_free(machine, portdata.record_file);
- portdata.record_file = NULL;
+ // close the file
+ m_record_file.close();
- /* pop a message */
+ // pop a message
if (message != NULL)
popmessage("Recording Ended\nReason: %s", message);
}
}
-/*-------------------------------------------------
- record_frame - start of frame callback for
- recording
--------------------------------------------------*/
+//-------------------------------------------------
+// record_frame - start of frame callback for
+// recording
+//-------------------------------------------------
-static void record_frame(running_machine &machine, attotime curtime)
+void ioport_manager::record_frame(attotime curtime)
{
- ioport_manager &portdata = machine.ioport();
-
- /* if recording, record information about the current frame */
- if (portdata.record_file != NULL)
+ // if recording, record information about the current frame
+ if (m_record_file.is_open())
{
- /* first the absolute time */
- record_write_uint32(machine, curtime.seconds);
- record_write_uint64(machine, curtime.attoseconds);
+ // first the absolute time
+ record_write(curtime.seconds);
+ record_write(curtime.attoseconds);
- /* then the current speed */
- record_write_uint32(machine, machine.video().speed_percent() * (double)(1 << 20));
+ // then the current speed
+ record_write(UINT32(machine().video().speed_percent() * double(1 << 20)));
}
}
-/*-------------------------------------------------
- record_port - per-port callback for record
--------------------------------------------------*/
+//-------------------------------------------------
+// record_port - per-port callback for record
+//-------------------------------------------------
-static void record_port(const input_port_config *port)
+void ioport_manager::record_port(ioport_port &port)
{
- ioport_manager &portdata = port->machine().ioport();
-
- /* if recording, store information about this port */
- if (portdata.record_file != NULL)
+ // if recording, store information about this port
+ if (m_record_file.is_open())
{
- analog_field_state *analog;
+ // store the default value and digital state
+ record_write(port.live().defvalue);
+ record_write(port.live().digital);
- /* store the default value and digital state */
- record_write_uint32(port->machine(), port->state->defvalue);
- record_write_uint32(port->machine(), port->state->digital);
-
- /* loop over analog ports and save their data */
- for (analog = port->state->analoglist; analog != NULL; analog = analog->next)
+ // loop over analog ports and save their data
+ for (analog_field *analog = port.live().analoglist.first(); analog != NULL; analog = analog->next())
{
- /* store current and previous values */
- record_write_uint32(port->machine(), analog->accum);
- record_write_uint32(port->machine(), analog->previous);
+ // store current and previous values
+ record_write(analog->m_accum);
+ record_write(analog->m_previous);
- /* store configuration information */
- record_write_uint32(port->machine(), analog->sensitivity);
- record_write_uint8(port->machine(), analog->reverse);
+ // store configuration information
+ record_write(analog->m_sensitivity);
+ record_write(analog->m_reverse);
}
}
}
-int input_machine_has_keyboard(running_machine &machine)
-{
- int have_keyboard = FALSE;
- const input_field_config *field;
- const input_port_config *port;
- for (port = machine.ioport().first_port(); port != NULL; port = port->next())
- {
- for (field = port->first_field(); field != NULL; field = field->next())
- {
- // if we are at init, check IPT_KEYBOARD for inputx_init
- if (!port->machine().ioport().safe_to_read && field->type == IPT_KEYBOARD)
- {
- have_keyboard = TRUE;
- break;
- }
- // else, check if there is a keyboard and if such a keyboard is enabled
- if (field->type == IPT_KEYBOARD && input_condition_true(field->machine(), &field->condition, field->port().owner()))
- {
- have_keyboard = TRUE;
- break;
- }
- }
- }
- return have_keyboard;
-}
-/***************************************************************************
- CODE ASSEMBLING
-***************************************************************************/
+//**************************************************************************
+// I/O PORT CONFIGURER
+//**************************************************************************
-/*-------------------------------------------------
- code_point_string - obtain a string representation of a
- given code; used for logging and debugging
--------------------------------------------------*/
+//-------------------------------------------------
+// ioport_configurer - constructor
+//-------------------------------------------------
-static const char *code_point_string(running_machine &machine, unicode_char ch)
+ioport_configurer::ioport_configurer(device_t &owner, ioport_list &portlist, astring &errorbuf)
+ : m_owner(owner),
+ m_portlist(portlist),
+ m_errorbuf(errorbuf),
+ m_curport(NULL),
+ m_curfield(NULL),
+ m_cursetting(NULL)
{
- static char buf[16];
- const char *result = buf;
-
- switch(ch)
- {
- /* check some magic values */
- case '\0': strcpy(buf, "\\0"); break;
- case '\r': strcpy(buf, "\\r"); break;
- case '\n': strcpy(buf, "\\n"); break;
- case '\t': strcpy(buf, "\\t"); break;
-
- default:
- if ((ch >= 32) && (ch < 128))
- {
- /* seven bit ASCII is easy */
- buf[0] = (char) ch;
- buf[1] = '\0';
- }
- else if (ch >= UCHAR_MAMEKEY_BEGIN)
- {
- /* try to obtain a codename with code_name(); this can result in an empty string */
- input_code code(DEVICE_CLASS_KEYBOARD, 0, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, input_item_id(ch - UCHAR_MAMEKEY_BEGIN));
- astring tempstr;
- snprintf(buf, ARRAY_LENGTH(buf), "%s", machine.input().code_name(tempstr, code));
- }
- else
- {
- /* empty string; resolve later */
- buf[0] = '\0';
- }
-
- /* did we fail to resolve? if so, we have a last resort */
- if (buf[0] == '\0')
- snprintf(buf, ARRAY_LENGTH(buf), "U+%04X", (unsigned) ch);
- break;
- }
- return result;
}
-/*-------------------------------------------------
- scan_keys - scans through input ports and
- sets up natural keyboard input mapping
--------------------------------------------------*/
+//-------------------------------------------------
+// string_from_token - convert an
+// ioport_token to a default string
+//-------------------------------------------------
-static int scan_keys(running_machine &machine, const input_port_config *portconfig, inputx_code *codes, const input_port_config * *ports, const input_field_config * *shift_ports, int keys, int shift)
+const char *ioport_configurer::string_from_token(const char *string)
{
- int code_count = 0;
- const input_port_config *port;
- const input_field_config *field;
- unicode_char code;
+ // 0 is an invalid index
+ if (string == NULL)
+ return NULL;
+
+ // if the index is greater than the count, assume it to be a pointer
+ if (FPTR(string) >= INPUT_STRING_COUNT)
+ return string;
- assert(keys < NUM_SIMUL_KEYS);
+#if FALSE // Set TRUE, If you want to take care missing-token or wrong-sorting
- for (port = portconfig; port != NULL; port = port->next())
+ // otherwise, scan the list for a matching string and return it
{
- for (field = port->first_field(); field != NULL; field = field->next())
- {
- if (field->type == IPT_KEYBOARD)
- {
- code = get_keyboard_code(field, shift);
- if (code != 0)
- {
- /* is this a shifter key? */
- if ((code >= UCHAR_SHIFT_BEGIN) && (code <= UCHAR_SHIFT_END))
- {
- shift_ports[keys] = field;
- code_count += scan_keys(machine,
- portconfig,
- codes ? &codes[code_count] : NULL,
- ports,
- shift_ports,
- keys+1,
- code - UCHAR_SHIFT_1 + 1);
- }
- else
- {
- /* not a shifter key; record normally */
- if (codes)
- {
- /* if we have a destination, record the codes used here */
- memcpy((void *) codes[code_count].field, shift_ports, sizeof(shift_ports[0]) * keys);
- codes[code_count].ch = code;
- codes[code_count].field[keys] = field;
- }
+ int index;
+ for (index = 0; index < ARRAY_LENGTH(input_port_default_strings); index++)
+ if (input_port_default_strings[index].id == FPTR(string))
+ return input_port_default_strings[index].string;
+ }
+ return "(Unknown Default)";
- /* increment the count */
- code_count++;
+#else
- if (LOG_INPUTX)
- logerror("inputx: code=%i (%s) port=%p field->name='%s'\n", (int) code, code_point_string(machine, code), port, field->name);
- }
- }
- }
- }
- }
- return code_count;
-}
+ return input_port_default_strings[FPTR(string)-1].string;
+#endif
+}
-/*-------------------------------------------------
- build_codes - given an input port table, create
- a input code table useful for mapping unicode
- chars
--------------------------------------------------*/
+//-------------------------------------------------
+// port_alloc - allocate a new port
+//-------------------------------------------------
-static inputx_code *build_codes(running_machine &machine, const input_port_config *portconfig)
+void ioport_configurer::port_alloc(const char *tag)
{
- inputx_code *codes = NULL;
- const input_port_config *ports[NUM_SIMUL_KEYS];
- const input_field_config *fields[NUM_SIMUL_KEYS];
- int code_count;
+ // create the full tag
+ astring fulltag;
+ m_owner.subtag(fulltag, tag);
+
+ // add it to the list, and reset current field/setting
+ m_curport = &m_portlist.append(fulltag, *global_alloc(ioport_port(m_owner, fulltag)));
+ m_curfield = NULL;
+ m_cursetting = NULL;
+}
- /* first count the number of codes */
- code_count = scan_keys(machine, portconfig, NULL, ports, fields, 0, 0);
- if (code_count > 0)
- {
- /* allocate the codes */
- codes = auto_alloc_array_clear(machine, inputx_code, code_count + 1);
- /* and populate them */
- scan_keys(machine, portconfig, codes, ports, fields, 0, 0);
- }
- return codes;
-}
+//-------------------------------------------------
+// port_modify - find an existing port and
+// modify it
+//-------------------------------------------------
+void ioport_configurer::port_modify(const char *tag)
+{
+ // create the full tag
+ astring fulltag;
+ m_owner.subtag(fulltag, tag);
+ // find the existing port
+ m_curport = m_portlist.find(fulltag.cstr());
+ if (m_curport == NULL)
+ throw emu_fatalerror("Requested to modify nonexistent port '%s'", fulltag.cstr());
+
+ // bump the modification count, and reset current field/setting
+ m_curport->m_modcount++;
+ m_curfield = NULL;
+ m_cursetting = NULL;
+}
-/***************************************************************************
- VALIDITY CHECKS
-***************************************************************************/
-/*-------------------------------------------------
- validate_natural_keyboard_statics -
- validates natural keyboard static data
--------------------------------------------------*/
+//-------------------------------------------------
+// field_alloc - allocate a new field
+//-------------------------------------------------
-int validate_natural_keyboard_statics(void)
+void ioport_configurer::field_alloc(ioport_type type, ioport_value defval, ioport_value mask, const char *name)
{
- int i;
- int error = FALSE;
- unicode_char last_char = 0;
- const char_info *ci;
+ // make sure we have a port
+ if (m_curport == NULL)
+ throw emu_fatalerror("alloc_field called with no active port (mask=%X defval=%X)\n", mask, defval); \
- /* check to make sure that charinfo is in order */
- for (i = 0; i < ARRAY_LENGTH(charinfo); i++)
- {
- if (last_char >= charinfo[i].ch)
- {
- mame_printf_error("inputx: charinfo is out of order; 0x%08x should be higher than 0x%08x\n", charinfo[i].ch, last_char);
- error = TRUE;
- }
- last_char = charinfo[i].ch;
- }
+ // append the field
+ if (type != IPT_UNKNOWN && type != IPT_UNUSED)
+ m_curport->m_active |= mask;
+ m_curfield = &m_curport->m_fieldlist.append(*global_alloc(ioport_field(*m_curport, type, defval, mask, string_from_token(name))));
- /* check to make sure that I can look up everything on alternate_charmap */
- for (i = 0; i < ARRAY_LENGTH(charinfo); i++)
- {
- ci = find_charinfo(charinfo[i].ch);
- if (ci != &charinfo[i])
- {
- mame_printf_error("inputx: expected find_charinfo(0x%08x) to work properly\n", charinfo[i].ch);
- error = TRUE;
- }
- }
- return error;
+ // reset the current setting
+ m_cursetting = NULL;
}
+//-------------------------------------------------
+// field_add_char - add a character to a field
+//-------------------------------------------------
-/***************************************************************************
- CORE IMPLEMENTATION
-***************************************************************************/
-
-static void clear_keybuffer(running_machine &machine)
+void ioport_configurer::field_add_char(unicode_char ch)
{
- ioport_manager &portdata = machine.ioport();
- portdata.keybuffer.buffer = NULL;
- portdata.queue_chars = NULL;
- portdata.codes = NULL;
+ for (int index = 0; index < ARRAY_LENGTH(m_curfield->m_chars); index++)
+ if (m_curfield->m_chars[index] == 0)
+ {
+ m_curfield->m_chars[index] = ch;
+ break;
+ }
}
+//-------------------------------------------------
+// field_add_code - add a character to a field
+//-------------------------------------------------
-static void setup_keybuffer(running_machine &machine)
+void ioport_configurer::field_add_code(input_seq_type which, input_code code)
{
- ioport_manager &portdata = machine.ioport();
- portdata.inputx_timer = machine.scheduler().timer_alloc(FUNC(inputx_timerproc));
- portdata.keybuffer.begin_pos = 0;
- portdata.keybuffer.end_pos = 0;
- portdata.keybuffer.status_keydown = 0;
- portdata.keybuffer.size = KEY_BUFFER_SIZE;
- portdata.keybuffer.buffer = auto_alloc_array(machine, unicode_char, portdata.keybuffer.size);
- machine.add_notifier(MACHINE_NOTIFY_EXIT, machine_notify_delegate(FUNC(clear_keybuffer), &machine));
+ m_curfield->m_seq[which] |= code;
}
+//-------------------------------------------------
+// setting_alloc - allocate a new setting
+//-------------------------------------------------
-void inputx_init(running_machine &machine)
+void ioport_configurer::setting_alloc(ioport_value value, const char *name)
{
- ioport_manager &portdata = machine.ioport();
- portdata.inputx_timer = NULL;
- portdata.accept_char = NULL;
- portdata.charqueue_empty = NULL;
- clear_keybuffer(machine);
+ // make sure we have a field
+ if (m_curfield == NULL)
+ throw emu_fatalerror("alloc_setting called with no active field (value=%X name=%s)\n", value, name);
- if (machine.debug_flags & DEBUG_FLAG_ENABLED)
- {
- debug_console_register_command(machine, "input", CMDFLAG_NONE, 0, 1, 1, execute_input);
- debug_console_register_command(machine, "dumpkbd", CMDFLAG_NONE, 0, 0, 1, execute_dumpkbd);
- }
-
- /* posting keys directly only makes sense for a computer */
- if (input_machine_has_keyboard(machine))
- {
- portdata.codes = build_codes(machine, machine.ioport().first_port());
- setup_keybuffer(machine);
- }
+ // append a new setting
+ m_curfield->m_settinglist.append(*global_alloc(ioport_setting(*m_curfield, value & m_curfield->mask(), string_from_token(name))));
}
+//-------------------------------------------------
+// set_condition - set the condition for either
+// the current setting or field
+//-------------------------------------------------
-void inputx_setup_natural_keyboard(
- running_machine &machine,
- int (*queue_chars)(running_machine &machine, const unicode_char *text, size_t text_len),
- int (*accept_char)(running_machine &machine, unicode_char ch),
- int (*charqueue_empty)(running_machine &machine))
+void ioport_configurer::set_condition(ioport_condition::condition_t condition, const char *tag, ioport_value mask, ioport_value value)
{
- ioport_manager &portdata = machine.ioport();
- portdata.queue_chars = queue_chars;
- portdata.accept_char = accept_char;
- portdata.charqueue_empty = charqueue_empty;
+ ioport_condition &target = (m_cursetting != NULL) ? m_cursetting->condition() : m_curfield->condition();
+ target.set(condition, tag, mask, value);
}
-int inputx_can_post(running_machine &machine)
-{
- ioport_manager &portdata = machine.ioport();
- return portdata.queue_chars || portdata.codes;
-}
+//-------------------------------------------------
+// onoff_alloc - allocate an on/off DIP switch
+//-------------------------------------------------
-static int can_post_key_directly(running_machine &machine, unicode_char ch)
+void ioport_configurer::onoff_alloc(const char *name, ioport_value defval, ioport_value mask, const char *diplocation)
{
- ioport_manager &portdata = machine.ioport();
- int rc = FALSE;
- const inputx_code *code;
+ // allocate a field normally
+ field_alloc(IPT_DIPSWITCH, defval, mask, name);
- if (portdata.queue_chars)
- {
- rc = portdata.accept_char ? (*portdata.accept_char)(machine, ch) : TRUE;
- }
- else
+ // special case service mode
+ if (name == DEF_STR(Service_Mode))
{
- code = find_code(portdata.codes, ch);
- if (code)
- rc = code->field[0] != NULL;
+ field_set_toggle();
+ m_curfield->m_seq[SEQ_TYPE_STANDARD].set(KEYCODE_F2);
}
- return rc;
+
+ // expand the diplocation
+ if (diplocation != NULL)
+ field_set_diplocation(diplocation);
+
+ // allocate settings
+ setting_alloc(defval & mask, DEF_STR(Off));
+ setting_alloc(~defval & mask, DEF_STR(On));
}
-static int can_post_key_alternate(running_machine &machine, unicode_char ch)
-{
- const char *s;
- const char_info *ci;
- unicode_char uchar;
- int rc;
+/***************************************************************************
+ MISCELLANEOUS
+***************************************************************************/
- ci = find_charinfo(ch);
- s = ci ? ci->alternate : NULL;
- if (!s)
- return 0;
+//-------------------------------------------------
+// find - look up information about a particular
+// character
+//-------------------------------------------------
- while(*s)
+const char_info *char_info::find(unicode_char target)
+{
+ // perform a simple binary search to find the proper alternate
+ int low = 0;
+ int high = ARRAY_LENGTH(charinfo);
+ while (high > low)
{
- rc = uchar_from_utf8(&uchar, s, strlen(s));
- if (rc <= 0)
- return 0;
- if (!can_post_key_directly(machine, uchar))
- return 0;
- s += rc;
+ int middle = (high + low) / 2;
+ unicode_char ch = charinfo[middle].ch;
+ if (ch < target)
+ low = middle + 1;
+ else if (ch > target)
+ high = middle;
+ else
+ return &charinfo[middle];
}
- return 1;
+ return NULL;
}
-static attotime choose_delay(ioport_manager &portdata, unicode_char ch)
-{
- if (portdata.current_rate != attotime::zero)
- return portdata.current_rate;
- attotime delay = attotime::zero;
- if (portdata.queue_chars)
- {
- /* systems with queue_chars can afford a much smaller delay */
- delay = attotime::from_msec(10);
- }
- else
- {
- switch(ch) {
- case '\r':
- delay = attotime::from_msec(200);
- break;
+//-------------------------------------------------
+// dynamic_field - constructor
+//-------------------------------------------------
- default:
- delay = attotime::from_msec(50);
- break;
- }
- }
- return delay;
+dynamic_field::dynamic_field(ioport_field &field)
+ : m_next(NULL),
+ m_field(field),
+ m_shift(0),
+ m_oldval(field.defvalue())
+{
+ // fill in the data
+ for (ioport_value mask = field.mask(); !(mask & 1); mask >>= 1)
+ m_shift++;
+ m_oldval >>= m_shift;
}
+//-------------------------------------------------
+// read - read the updated value and merge it
+// into the target
+//-------------------------------------------------
-static void internal_post_key(running_machine &machine, unicode_char ch)
+void dynamic_field::read(ioport_value &result)
{
- ioport_manager &portdata = machine.ioport();
- key_buffer *keybuf;
+ // skip if not enabled
+ if (!m_field.enabled())
+ return;
+
+ // call the callback to read a new value
+ ioport_value newval = m_field.m_read(m_field, m_field.m_read_param);
+ m_oldval = newval;
+
+ // merge in the bits (don't invert yet, as all digitals are inverted together)
+ result = (result & ~m_field.mask()) | ((newval << m_shift) & m_field.mask());
+}
- keybuf = get_buffer(machine);
- /* need to start up the timer? */
- if (keybuf->begin_pos == keybuf->end_pos)
- {
- portdata.inputx_timer->adjust(choose_delay(portdata, ch));
- keybuf->status_keydown = 0;
- }
+//-------------------------------------------------
+// write - track a change to a value and call
+// the write callback if there's something new
+//-------------------------------------------------
+
+void dynamic_field::write(ioport_value newval)
+{
+ // skip if not enabled
+ if (!m_field.enabled())
+ return;
- keybuf->buffer[keybuf->end_pos++] = ch;
- if ((keybuf->end_pos+1) % keybuf->size == keybuf->begin_pos)
+ // if the bits have changed, call the handler
+ newval = ((newval ^ m_field.defvalue()) & m_field.mask()) >> m_shift;
+ if (m_oldval != newval)
{
- // Buffer full
- unicode_char *old_buffer = keybuf->buffer;
- keybuf->size = keybuf->size + KEY_BUFFER_SIZE;
- keybuf->buffer = auto_alloc_array(machine, unicode_char, keybuf->size);
- for( int i = keybuf->begin_pos; i <= keybuf->end_pos; i++ )
- {
- keybuf->buffer[i] = old_buffer[i];
- }
- auto_free(machine, old_buffer);
+ m_field.m_write(m_field, m_field.m_write_param, m_oldval, newval);
+ m_oldval = newval;
}
- keybuf->end_pos %= keybuf->size;
}
+//-------------------------------------------------
+// analog_field - constructor
+//-------------------------------------------------
-static int buffer_full(running_machine &machine)
-{
- key_buffer *keybuf;
- keybuf = get_buffer(machine);
- return ((keybuf->end_pos + 1) % keybuf->size) == keybuf->begin_pos;
-}
+analog_field::analog_field(ioport_field &field)
+ : m_next(NULL),
+ m_field(field),
+ m_shift(0),
+ m_adjdefvalue(field.defvalue() & field.mask()),
+ m_adjmin(field.minval() & field.mask()),
+ m_adjmax(field.maxval() & field.mask()),
+ m_sensitivity(field.sensitivity()),
+ m_reverse(field.analog_reverse()),
+ m_delta(field.delta()),
+ m_centerdelta(field.centerdelta()),
+ m_accum(0),
+ m_previous(0),
+ m_previousanalog(0),
+ m_minimum(INPUT_ABSOLUTE_MIN),
+ m_maximum(INPUT_ABSOLUTE_MAX),
+ m_center(0),
+ m_reverse_val(0),
+ m_scalepos(0),
+ m_scaleneg(0),
+ m_keyscalepos(0),
+ m_keyscaleneg(0),
+ m_positionalscale(0),
+ m_absolute(false),
+ m_wraps(false),
+ m_autocenter(false),
+ m_single_scale(false),
+ m_interpolate(false),
+ m_lastdigital(false)
+{
+ // compute the shift amount and number of bits
+ for (ioport_value mask = field.mask(); !(mask & 1); mask >>= 1)
+ m_shift++;
+
+ // initialize core data
+ m_adjdefvalue >>= m_shift;
+ m_adjmin >>= m_shift;
+ m_adjmax >>= m_shift;
+
+ // set basic parameters based on the configured type
+ switch (field.type())
+ {
+ // paddles and analog joysticks are absolute and autocenter
+ case IPT_AD_STICK_X:
+ case IPT_AD_STICK_Y:
+ case IPT_AD_STICK_Z:
+ case IPT_PADDLE:
+ case IPT_PADDLE_V:
+ m_absolute = true;
+ m_autocenter = true;
+ m_interpolate = !field.analog_reset();
+ break;
+ // pedals start at and autocenter to the min range
+ case IPT_PEDAL:
+ case IPT_PEDAL2:
+ case IPT_PEDAL3:
+ m_center = INPUT_ABSOLUTE_MIN;
+ m_accum = apply_inverse_sensitivity(m_center);
+ m_absolute = true;
+ m_autocenter = true;
+ m_interpolate = !field.analog_reset();
+ break;
+ // lightguns are absolute as well, but don't autocenter and don't interpolate their values
+ case IPT_LIGHTGUN_X:
+ case IPT_LIGHTGUN_Y:
+ m_absolute = true;
+ m_autocenter = false;
+ m_interpolate = false;
+ break;
-static void inputx_postn_rate(running_machine &machine, const unicode_char *text, size_t text_len, attotime rate)
-{
- ioport_manager &portdata = machine.ioport();
- int last_cr = 0;
- unicode_char ch;
- const char *s;
- const char_info *ci;
- const inputx_code *code;
+ // positional devices are absolute, but can also wrap like relative devices
+ // set each position to be 512 units
+ case IPT_POSITIONAL:
+ case IPT_POSITIONAL_V:
+ m_positionalscale = compute_scale(field.maxval(), INPUT_ABSOLUTE_MAX - INPUT_ABSOLUTE_MIN);
+ m_adjmin = 0;
+ m_adjmax = field.maxval() - 1;
+ m_wraps = field.analog_wraps();
+ m_autocenter = !m_wraps;
+ break;
- portdata.current_rate = rate;
+ // dials, mice and trackballs are relative devices
+ // these have fixed "min" and "max" values based on how many bits are in the port
+ // in addition, we set the wrap around min/max values to 512 * the min/max values
+ // this takes into account the mapping that one mouse unit ~= 512 analog units
+ case IPT_DIAL:
+ case IPT_DIAL_V:
+ case IPT_TRACKBALL_X:
+ case IPT_TRACKBALL_Y:
+ case IPT_MOUSE_X:
+ case IPT_MOUSE_Y:
+ m_absolute = false;
+ m_wraps = true;
+ m_interpolate = !field.analog_reset();
+ break;
+
+ default:
+ fatalerror("Unknown analog port type -- don't know if it is absolute or not");
+ break;
+ }
- if (inputx_can_post(machine))
+ // further processing for absolute controls
+ if (m_absolute)
{
- while((text_len > 0) && !buffer_full(machine))
- {
- ch = *(text++);
- text_len--;
+ // if the default value is pegged at the min or max, use a single scale value for the whole axis
+ m_single_scale = (m_adjdefvalue == m_adjmin) || (m_adjdefvalue == m_adjmax);
- /* change all eolns to '\r' */
- if ((ch != '\n') || !last_cr)
- {
- if (ch == '\n')
- ch = '\r';
- else
- last_cr = (ch == '\r');
+ // if not "single scale", compute separate scales for each side of the default
+ if (!m_single_scale)
+ {
+ // unsigned
+ m_scalepos = compute_scale(m_adjmax - m_adjdefvalue, INPUT_ABSOLUTE_MAX - 0);
+ m_scaleneg = compute_scale(m_adjdefvalue - m_adjmin, 0 - INPUT_ABSOLUTE_MIN);
- if (LOG_INPUTX)
- {
- code = find_code(portdata.codes, ch);
- logerror("inputx_postn(): code=%i (%s) field->name='%s'\n", (int) ch, code_point_string(machine, ch), (code && code->field[0]) ? code->field[0]->name : "<null>");
- }
+ if (m_adjmin > m_adjmax)
+ m_scaleneg = -m_scaleneg;
- if (can_post_key_directly(machine, ch))
- {
- /* we can post this key in the queue directly */
- internal_post_key(machine, ch);
- }
- else if (can_post_key_alternate(machine, ch))
- {
- /* we can post this key with an alternate representation */
- ci = find_charinfo(ch);
- assert(ci && ci->alternate);
- s = ci->alternate;
- while(*s)
- {
- s += uchar_from_utf8(&ch, s, strlen(s));
- internal_post_key(machine, ch);
- }
- }
- }
- else
- {
- last_cr = 0;
- }
+ // reverse point is at center
+ m_reverse_val = 0;
}
- }
-}
-
-
+ else
+ {
+ // single axis that increases from default
+ m_scalepos = compute_scale(m_adjmax - m_adjmin, INPUT_ABSOLUTE_MAX - INPUT_ABSOLUTE_MIN);
-static TIMER_CALLBACK(inputx_timerproc)
-{
- ioport_manager &portdata = machine.ioport();
- key_buffer *keybuf;
- attotime delay;
+ // move from default
+ if (m_adjdefvalue == m_adjmax)
+ m_scalepos = -m_scalepos;
- keybuf = get_buffer(machine);
+ // make the scaling the same for easier coding when we need to scale
+ m_scaleneg = m_scalepos;
- if (portdata.queue_chars)
- {
- /* the driver has a queue_chars handler */
- while((keybuf->begin_pos != keybuf->end_pos) && (*portdata.queue_chars)(machine, &keybuf->buffer[keybuf->begin_pos], 1))
- {
- keybuf->begin_pos++;
- keybuf->begin_pos %= keybuf->size;
-
- if (portdata.current_rate != attotime::zero)
- break;
+ // reverse point is at max
+ m_reverse_val = m_maximum;
}
}
+
+ // relative and positional controls all map directly with a 512x scale factor
else
{
- /* the driver does not have a queue_chars handler */
- if (keybuf->status_keydown)
- {
- keybuf->status_keydown = FALSE;
- keybuf->begin_pos++;
- keybuf->begin_pos %= keybuf->size;
- }
+ // The relative code is set up to allow specifing PORT_MINMAX and default values.
+ // The validity checks are purposely set up to not allow you to use anything other
+ // a default of 0 and PORT_MINMAX(0,mask). This is in case the need arises to use
+ // this feature in the future. Keeping the code in does not hurt anything.
+ if (m_adjmin > m_adjmax)
+ // adjust for signed
+ m_adjmin = -m_adjmin;
+
+ if (m_wraps)
+ m_adjmax++;
+
+ m_minimum = (m_adjmin - m_adjdefvalue) * INPUT_RELATIVE_PER_PIXEL;
+ m_maximum = (m_adjmax - m_adjdefvalue) * INPUT_RELATIVE_PER_PIXEL;
+
+ // make the scaling the same for easier coding when we need to scale
+ m_scaleneg = m_scalepos = compute_scale(1, INPUT_RELATIVE_PER_PIXEL);
+
+ if (m_field.analog_reset())
+ // delta values reverse from center
+ m_reverse_val = 0;
else
{
- keybuf->status_keydown = TRUE;
- }
- }
+ // positional controls reverse from their max range
+ m_reverse_val = m_maximum + m_minimum;
- /* need to make sure timerproc is called again if buffer not empty */
- if (keybuf->begin_pos != keybuf->end_pos)
- {
- delay = choose_delay(portdata, keybuf->buffer[keybuf->begin_pos]);
- portdata.inputx_timer->adjust(delay);
+ // relative controls reverse from 1 past their max range
+ if (m_wraps)
+ m_reverse_val -= INPUT_RELATIVE_PER_PIXEL;
+ }
}
-}
-int inputx_is_posting(running_machine &machine)
-{
- ioport_manager &portdata = machine.ioport();
- const key_buffer *keybuf;
- keybuf = get_buffer(machine);
- return (keybuf->begin_pos != keybuf->end_pos) || (portdata.charqueue_empty && !(*portdata.charqueue_empty)(machine));
+ // compute scale for keypresses
+ m_keyscalepos = recip_scale(m_scalepos);
+ m_keyscaleneg = recip_scale(m_scaleneg);
}
-/***************************************************************************
- Coded input
+//-------------------------------------------------
+// apply_min_max - clamp the given input value to
+// the appropriate min/max for the analog control
+//-------------------------------------------------
-***************************************************************************/
-static void inputx_postc_rate(running_machine &machine, unicode_char ch, attotime rate);
-
-static void inputx_postn_coded_rate(running_machine &machine, const char *text, size_t text_len, attotime rate)
+inline ioport_value analog_field::apply_min_max(ioport_value value) const
{
- size_t i, j, key_len, increment;
- unicode_char ch;
+ // take the analog minimum and maximum values and apply the inverse of the
+ // sensitivity so that we can clamp against them before applying sensitivity
+ INT32 adjmin = apply_inverse_sensitivity(m_minimum);
+ INT32 adjmax = apply_inverse_sensitivity(m_maximum);
- static const struct
- {
- const char *key;
- unicode_char code;
- } codes[] =
+ // for absolute devices, clamp to the bounds absolutely
+ if (!m_wraps)
{
- { "BACKSPACE", 8 },
- { "BS", 8 },
- { "BKSP", 8 },
- { "DEL", UCHAR_MAMEKEY(DEL) },
- { "DELETE", UCHAR_MAMEKEY(DEL) },
- { "END", UCHAR_MAMEKEY(END) },
- { "ENTER", 13 },
- { "ESC", '\033' },
- { "HOME", UCHAR_MAMEKEY(HOME) },
- { "INS", UCHAR_MAMEKEY(INSERT) },
- { "INSERT", UCHAR_MAMEKEY(INSERT) },
- { "PGDN", UCHAR_MAMEKEY(PGDN) },
- { "PGUP", UCHAR_MAMEKEY(PGUP) },
- { "SPACE", 32 },
- { "TAB", 9 },
- { "F1", UCHAR_MAMEKEY(F1) },
- { "F2", UCHAR_MAMEKEY(F2) },
- { "F3", UCHAR_MAMEKEY(F3) },
- { "F4", UCHAR_MAMEKEY(F4) },
- { "F5", UCHAR_MAMEKEY(F5) },
- { "F6", UCHAR_MAMEKEY(F6) },
- { "F7", UCHAR_MAMEKEY(F7) },
- { "F8", UCHAR_MAMEKEY(F8) },
- { "F9", UCHAR_MAMEKEY(F9) },
- { "F10", UCHAR_MAMEKEY(F10) },
- { "F11", UCHAR_MAMEKEY(F11) },
- { "F12", UCHAR_MAMEKEY(F12) },
- { "QUOTE", '\"' }
- };
+ if (value > adjmax)
+ value = adjmax;
+ else if (value < adjmin)
+ value = adjmin;
+ }
- i = 0;
- while(i < text_len)
+ // for relative devices, wrap around when we go past the edge
+ else
{
- ch = text[i];
- increment = 1;
-
- if (ch == '{')
- {
- for (j = 0; j < ARRAY_LENGTH(codes); j++)
- {
- key_len = strlen(codes[j].key);
- if (i + key_len + 2 <= text_len)
- {
- if (!core_strnicmp(codes[j].key, &text[i + 1], key_len) && (text[i + key_len + 1] == '}'))
- {
- ch = codes[j].code;
- increment = key_len + 2;
- }
- }
- }
- }
-
- if (ch)
- inputx_postc_rate(machine, ch, rate);
- i += increment;
+ INT32 range = adjmax - adjmin;
+ // rolls to other end when 1 position past end.
+ value = (value - adjmin) % range;
+ if (value < 0)
+ value += range;
+ value += adjmin;
}
+
+ return value;
}
+//-------------------------------------------------
+// apply_sensitivity - apply a sensitivity
+// adjustment for a current value
+//-------------------------------------------------
-/***************************************************************************
+inline ioport_value analog_field::apply_sensitivity(ioport_value value) const
+{
+ return INT32((INT64(value) * m_sensitivity) / 100.0 + 0.5);
+}
- Alternative calls
-***************************************************************************/
+//-------------------------------------------------
+// apply_inverse_sensitivity - reverse-apply the
+// sensitivity adjustment for a current value
+//-------------------------------------------------
-static void inputx_postc_rate(running_machine &machine, unicode_char ch, attotime rate)
+inline ioport_value analog_field::apply_inverse_sensitivity(ioport_value value) const
{
- inputx_postn_rate(machine, &ch, 1, rate);
+ return INT32((INT64(value) * 100) / m_sensitivity);
}
-void inputx_postc(running_machine &machine, unicode_char ch)
+
+//-------------------------------------------------
+// apply_settings - return the value of an
+// analog input
+//-------------------------------------------------
+
+ioport_value analog_field::apply_settings(ioport_value value) const
{
- inputx_postc_rate(machine, ch, attotime::zero);
+ // apply the min/max and then the sensitivity
+ value = apply_min_max(value);
+ value = apply_sensitivity(value);
+
+ // apply reversal if needed
+ if (m_reverse)
+ value = m_reverse_val - value;
+ else if (m_single_scale)
+ // it's a pedal or the default value is equal to min/max
+ // so we need to adjust the center to the minimum
+ value -= INPUT_ABSOLUTE_MIN;
+
+ // map differently for positive and negative values
+ if (value >= 0)
+ value = apply_scale(value, m_scalepos);
+ else
+ value = apply_scale(value, m_scaleneg);
+ value += m_adjdefvalue;
+
+ return value;
}
-static void inputx_postn_utf8_rate(running_machine &machine, const char *text, size_t text_len, attotime rate)
+
+//-------------------------------------------------
+// frame_update - update the internals of a
+// single analog field periodically
+//-------------------------------------------------
+
+void analog_field::frame_update(running_machine &machine)
{
- size_t len = 0;
- unicode_char buf[256];
- unicode_char c;
- int rc;
+ // clamp the previous value to the min/max range and remember it
+ m_previous = m_accum = apply_min_max(m_accum);
- while(text_len > 0)
+ // get the new raw analog value and its type
+ input_item_class itemclass;
+ INT32 rawvalue = machine.input().seq_axis_value(m_field.seq(SEQ_TYPE_STANDARD), itemclass);
+
+ // if we got an absolute input, it overrides everything else
+ if (itemclass == ITEM_CLASS_ABSOLUTE)
{
- if (len == ARRAY_LENGTH(buf))
+ if (m_previousanalog != rawvalue)
{
- inputx_postn_rate(machine, buf, len, attotime::zero);
- len = 0;
- }
+ // only update if analog value changed
+ m_previousanalog = rawvalue;
+
+ // apply the inverse of the sensitivity to the raw value so that
+ // it will still cover the full min->max range requested after
+ // we apply the sensitivity adjustment
+ if (m_absolute || m_field.analog_reset())
+ {
+ // if port is absolute, then just return the absolute data supplied
+ m_accum = apply_inverse_sensitivity(rawvalue);
+ }
+ else if (m_positionalscale != 0)
+ {
+ // if port is positional, we will take the full analog control and divide it
+ // into positions, that way as the control is moved full scale,
+ // it moves through all the positions
+ rawvalue = apply_scale(rawvalue - INPUT_ABSOLUTE_MIN, m_positionalscale) * INPUT_RELATIVE_PER_PIXEL + m_minimum;
+
+ // clamp the high value so it does not roll over
+ rawvalue = MIN(rawvalue, m_maximum);
+ m_accum = apply_inverse_sensitivity(rawvalue);
+ }
+ else
+ // if port is relative, we use the value to simulate the speed of relative movement
+ // sensitivity adjustment is allowed for this mode
+ m_accum += rawvalue;
- rc = uchar_from_utf8(&c, text, text_len);
- if (rc < 0)
+ m_lastdigital = false;
+ // do not bother with other control types if the analog data is changing
+ return;
+ }
+ else
{
- rc = 1;
- c = INVALID_CHAR;
+ // we still have to update fake relative from joystick control
+ if (!m_absolute && m_positionalscale == 0)
+ m_accum += rawvalue;
}
- text += rc;
- text_len -= rc;
- buf[len++] = c;
}
- inputx_postn_rate(machine, buf, len, rate);
-}
-
-void inputx_post_utf8(running_machine &machine, const char *text)
-{
- inputx_postn_utf8_rate(machine, text, strlen(text), attotime::zero);
-}
-
-void inputx_post_utf8_rate(running_machine &machine, const char *text, attotime rate)
-{
- inputx_postn_utf8_rate(machine, text, strlen(text), rate);
-}
-
-/***************************************************************************
- Other stuff
+ // if we got it from a relative device, use that as the starting delta
+ // also note that the last input was not a digital one
+ INT32 delta = 0;
+ if (itemclass == ITEM_CLASS_RELATIVE && rawvalue != 0)
+ {
+ delta = rawvalue;
+ m_lastdigital = false;
+ }
- This stuff is here more out of convienience than anything else
-***************************************************************************/
+ INT64 keyscale = (m_accum >= 0) ? m_keyscalepos : m_keyscaleneg;
-int input_classify_port(const input_field_config *field)
-{
- int result;
+ // if the decrement code sequence is pressed, add the key delta to
+ // the accumulated delta; also note that the last input was a digital one
+ bool keypressed = false;
+ if (machine.input().seq_pressed(m_field.seq(SEQ_TYPE_DECREMENT)))
+ {
+ keypressed = true;
+ if (m_delta != 0)
+ delta -= apply_scale(m_delta, keyscale);
+ else if (!m_lastdigital)
+ // decrement only once when first pressed
+ delta -= apply_scale(1, keyscale);
+ m_lastdigital = true;
+ }
- switch(field->type)
+ // same for the increment code sequence
+ if (machine.input().seq_pressed(m_field.seq(SEQ_TYPE_INCREMENT)))
{
- case IPT_JOYSTICK_UP:
- case IPT_JOYSTICK_DOWN:
- case IPT_JOYSTICK_LEFT:
- case IPT_JOYSTICK_RIGHT:
- case IPT_JOYSTICKLEFT_UP:
- case IPT_JOYSTICKLEFT_DOWN:
- case IPT_JOYSTICKLEFT_LEFT:
- case IPT_JOYSTICKLEFT_RIGHT:
- case IPT_JOYSTICKRIGHT_UP:
- case IPT_JOYSTICKRIGHT_DOWN:
- case IPT_JOYSTICKRIGHT_LEFT:
- case IPT_JOYSTICKRIGHT_RIGHT:
- case IPT_BUTTON1:
- case IPT_BUTTON2:
- case IPT_BUTTON3:
- case IPT_BUTTON4:
- case IPT_BUTTON5:
- case IPT_BUTTON6:
- case IPT_BUTTON7:
- case IPT_BUTTON8:
- case IPT_BUTTON9:
- case IPT_BUTTON10:
- case IPT_AD_STICK_X:
- case IPT_AD_STICK_Y:
- case IPT_AD_STICK_Z:
- case IPT_TRACKBALL_X:
- case IPT_TRACKBALL_Y:
- case IPT_LIGHTGUN_X:
- case IPT_LIGHTGUN_Y:
- case IPT_MOUSE_X:
- case IPT_MOUSE_Y:
- case IPT_START:
- case IPT_SELECT:
- result = INPUT_CLASS_CONTROLLER;
- break;
+ keypressed = true;
+ if (m_delta)
+ delta += apply_scale(m_delta, keyscale);
+ else if (!m_lastdigital)
+ // increment only once when first pressed
+ delta += apply_scale(1, keyscale);
+ m_lastdigital = true;
+ }
- case IPT_KEYPAD:
- case IPT_KEYBOARD:
- result = INPUT_CLASS_KEYBOARD;
- break;
+ // if resetting is requested, clear the accumulated position to 0 before
+ // applying the deltas so that we only return this frame's delta
+ // note that centering only works for relative controls
+ // no need to check if absolute here because it is checked by the validity tests
+ if (m_field.analog_reset())
+ m_accum = 0;
- case IPT_CONFIG:
- result = INPUT_CLASS_CONFIG;
- break;
+ // apply the delta to the accumulated value
+ m_accum += delta;
- case IPT_DIPSWITCH:
- result = INPUT_CLASS_DIPSWITCH;
- break;
+ // if our last movement was due to a digital input, and if this control
+ // type autocenters, and if neither the increment nor the decrement seq
+ // was pressed, apply autocentering
+ if (m_autocenter)
+ {
+ INT32 center = apply_inverse_sensitivity(m_center);
+ if (m_lastdigital && !keypressed)
+ {
+ // autocenter from positive values
+ if (m_accum >= center)
+ {
+ m_accum -= apply_scale(m_centerdelta, m_keyscalepos);
+ if (m_accum < center)
+ {
+ m_accum = center;
+ m_lastdigital = false;
+ }
+ }
- case 0:
- if (field->name && (field->name != (const char *) -1))
- result = INPUT_CLASS_MISC;
+ // autocenter from negative values
else
- result = INPUT_CLASS_INTERNAL;
- break;
-
- default:
- result = INPUT_CLASS_INTERNAL;
- break;
+ {
+ m_accum += apply_scale(m_centerdelta, m_keyscaleneg);
+ if (m_accum > center)
+ {
+ m_accum = center;
+ m_lastdigital = false;
+ }
+ }
+ }
}
- return result;
+ else if (!keypressed)
+ m_lastdigital = false;
}
+//-------------------------------------------------
+// read - read the current value and insert into
+// the provided ioport_value
+//-------------------------------------------------
-int input_player_number(const input_field_config *port)
+void analog_field::read(ioport_value &result)
{
- return port->player;
-}
+ // do nothing if we're not enabled
+ if (!m_field.enabled())
+ return;
+ // start with the raw value
+ INT32 value = m_accum;
+ // interpolate if appropriate and if time has passed since the last update
+ if (m_interpolate)
+ value = manager().frame_interpolate(m_previous, m_accum);
-/*-------------------------------------------------
- input_has_input_class - checks to see if a
- particular input class is present
--------------------------------------------------*/
+ // apply standard analog settings
+ value = apply_settings(value);
-int input_has_input_class(running_machine &machine, int inputclass)
-{
- const input_port_config *port;
- const input_field_config *field;
+ // remap the value if needed
+ if (m_field.remap_table() != NULL)
+ value = m_field.remap_table()[value];
- for (port = machine.ioport().first_port(); port != NULL; port = port->next())
- {
- for (field = port->first_field(); field != NULL; field = field->next())
- {
- if (input_classify_port(field) == inputclass)
- return TRUE;
- }
- }
- return FALSE;
-}
+ // invert bits if needed
+ if (m_field.analog_invert())
+ value = ~value;
+ // insert into the port
+ result = (result & ~m_field.mask()) | ((value << m_shift) & m_field.mask());
+}
-/*-------------------------------------------------
- input_count_players - counts the number of
- active players
--------------------------------------------------*/
+//-------------------------------------------------
+// crosshair_read - read a value for crosshairs,
+// scaled between 0 and 1
+//-------------------------------------------------
-int input_count_players(running_machine &machine)
+float analog_field::crosshair_read()
{
- const input_port_config *port;
- const input_field_config *field;
- int joystick_count;
-
- joystick_count = 0;
- for (port = machine.ioport().first_port(); port != NULL; port = port->next())
- {
- for (field = port->first_field(); field != NULL; field = field->next())
- {
- if (input_classify_port(field) == INPUT_CLASS_CONTROLLER)
- {
- if (joystick_count <= field->player + 1)
- joystick_count = field->player + 1;
- }
- }
- }
- return joystick_count;
+ INT32 rawvalue = apply_settings(m_accum) & (m_field.mask() >> m_shift);
+ return float(rawvalue - m_adjmin) / float(m_adjmax - m_adjmin);
}
/***************************************************************************
- DEBUGGER SUPPORT
+ TOKENIZATION HELPERS
***************************************************************************/
-/*-------------------------------------------------
- execute_input - debugger command to enter
- natural keyboard input
--------------------------------------------------*/
+//-------------------------------------------------
+// token_to_input_type - convert a string token
+// to an input field type and player
+//-------------------------------------------------
-static void execute_input(running_machine &machine, int ref, int params, const char *param[])
+ioport_type ioport_manager::token_to_input_type(const char *string, int &player) const
{
- inputx_postn_coded_rate(machine, param[0], strlen(param[0]), attotime::zero);
-}
-
-
-
-/*-------------------------------------------------
- execute_dumpkbd - debugger command to natural
- keyboard codes
--------------------------------------------------*/
+ // check for our failsafe case first
+ int ipnum;
+ if (sscanf(string, "TYPE_OTHER(%d,%d)", &ipnum, &player) == 2)
+ return ioport_type(ipnum);
-static void execute_dumpkbd(running_machine &machine, int ref, int params, const char *param[])
-{
- inputx_code *codes = machine.ioport().codes;
- const char *filename;
- FILE *file = NULL;
- const inputx_code *code;
- char buffer[512];
- size_t pos;
- int i, j;
- size_t left_column_width = 24;
-
- /* was there a file specified? */
- filename = (params > 0) ? param[0] : NULL;
- if (filename != NULL)
- {
- /* if so, open it */
- file = fopen(filename, "w");
- if (file == NULL)
+ // find the token in the list
+ for (input_type_entry *entry = m_typelist.first(); entry != NULL; entry = entry->next())
+ if (entry->token() != NULL && !strcmp(entry->token(), string))
{
- debug_console_printf(machine, "Cannot open \"%s\"\n", filename);
- return;
+ player = entry->player();
+ return entry->type();
}
- }
-
- if ((codes != NULL) && (codes[0].ch != 0))
- {
- /* loop through all codes */
- for (i = 0; codes[i].ch; i++)
- {
- code = &codes[i];
- pos = 0;
- /* describe the character code */
- pos += snprintf(&buffer[pos], ARRAY_LENGTH(buffer) - pos, "%08X (%s) ",
- code->ch,
- code_point_string(machine, code->ch));
-
- /* pad with spaces */
- while(pos < left_column_width)
- buffer[pos++] = ' ';
- buffer[pos] = '\0';
+ // if we fail, return IPT_UNKNOWN
+ player = 0;
+ return IPT_UNKNOWN;
+}
- /* identify the keys used */
- for (j = 0; j < ARRAY_LENGTH(code->field) && (code->field[j] != NULL); j++)
- {
- pos += snprintf(&buffer[pos], ARRAY_LENGTH(buffer) - pos, "%s'%s'",
- (j > 0) ? ", " : "",
- code->field[j]->name);
- }
- /* and output it as appropriate */
- if (file != NULL)
- fprintf(file, "%s\n", buffer);
- else
- debug_console_printf(machine, "%s\n", buffer);
- }
- }
- else
- {
- debug_console_printf(machine, "No natural keyboard support\n");
- }
+//-------------------------------------------------
+// input_type_to_token - convert an input field
+// type and player to a string token
+//-------------------------------------------------
- /* cleanup */
- if (file != NULL)
- fclose(file);
+const char *ioport_manager::input_type_to_token(astring &string, ioport_type type, int player)
+{
+ // look up the port and return the token
+ input_type_entry *entry = m_type_to_entry[type][player];
+ if (entry != NULL)
+ return string.cpy(entry->token());
+ // if that fails, carry on
+ return string.format("TYPE_OTHER(%d,%d)", type, player);
}
+//-------------------------------------------------
+// token_to_seq_type - convert a string to
+// a sequence type
+//-------------------------------------------------
-input_port_config *ioconfig_alloc_port(ioport_list &portlist, device_t &device, const char *tag)
+input_seq_type ioport_manager::token_to_seq_type(const char *string)
{
- astring fulltag;
- device.subtag(fulltag, tag);
- return &portlist.append(fulltag, *global_alloc(input_port_config(device, fulltag)));
+ // look up the string in the table of possible sequence types and return the index
+ for (int seqindex = 0; seqindex < ARRAY_LENGTH(seqtypestrings); seqindex++)
+ if (!mame_stricmp(string, seqtypestrings[seqindex]))
+ return input_seq_type(seqindex);
+ return SEQ_TYPE_INVALID;
}
-input_port_config *ioconfig_modify_port(ioport_list &portlist, device_t &device, const char *tag)
-{
- astring fulltag;
- device.subtag(fulltag, tag);
- input_port_config *port = portlist.find(fulltag.cstr());
- if (port == NULL)
- throw emu_fatalerror("Requested to modify nonexistent port '%s'", fulltag.cstr());
- port->bump_modcount();
- return port;
-}
-input_field_config *ioconfig_alloc_field(input_port_config &port, int type, input_port_value defval, input_port_value mask, const char *name)
-{
- if (&port == NULL)
- throw emu_fatalerror("INPUT_TOKEN_FIELD encountered with no active port (mask=%X defval=%X)\n", mask, defval); \
- if (type != IPT_UNKNOWN && type != IPT_UNUSED)
- port.active |= mask;
- if (type == IPT_DIPSWITCH || type == IPT_CONFIG)
- defval = port_default_value(port.tag(), mask, defval, port.owner());
- return &port.fieldlist().append(*global_alloc(input_field_config(port, type, defval, mask, input_port_string_from_token(name))));
-}
-input_field_config *ioconfig_alloc_onoff(input_port_config &port, const char *name, input_port_value defval, input_port_value mask, const char *diplocation, astring &errorbuf)
-{
- input_field_config *curfield = ioconfig_alloc_field(port, IPT_DIPSWITCH, defval, mask, name);
- if (name == DEF_STR(Service_Mode))
- {
- curfield->flags |= FIELD_FLAG_TOGGLE;
- curfield->seq[SEQ_TYPE_STANDARD].set(KEYCODE_F2);
- }
- if (diplocation != NULL)
- diplocation_list_alloc(*curfield, diplocation, errorbuf);
- ioconfig_alloc_setting(*curfield, defval & mask, DEF_STR(Off));
- ioconfig_alloc_setting(*curfield, ~defval & mask, DEF_STR(On));
- return curfield;
-}
+//-------------------------------------------------
+// validate_natural_keyboard_statics -
+// validates natural keyboard static data
+//-------------------------------------------------
-input_setting_config *ioconfig_alloc_setting(input_field_config &field, input_port_value value, const char *name)
+/*
+int validate_natural_keyboard_statics(void)
{
- return &field.settinglist().append(*global_alloc(input_setting_config(field, value, input_port_string_from_token(name))));
-}
+ int i;
+ int error = FALSE;
+ unicode_char last_char = 0;
+ const char_info *ci;
-void ioconfig_field_add_char(input_field_config &field, unicode_char ch, astring &errorbuf)
-{
- for (int index = 0; index < ARRAY_LENGTH(field.chars); index++)
- if (field.chars[index] == 0)
+ // check to make sure that charinfo is in order
+ for (i = 0; i < ARRAY_LENGTH(charinfo); i++)
+ {
+ if (last_char >= charinfo[i].ch)
{
- field.chars[index] = ch;
- break;
+ mame_printf_error("inputx: charinfo is out of order; 0x%08x should be higher than 0x%08x\n", charinfo[i].ch, last_char);
+ error = TRUE;
}
-}
+ last_char = charinfo[i].ch;
+ }
-void ioconfig_add_code(input_field_config &field, int which, input_code code)
-{
- field.seq[which] |= code;
+ // check to make sure that I can look up everything on alternate_charmap
+ for (i = 0; i < ARRAY_LENGTH(charinfo); i++)
+ {
+ ci = char_info::find(charinfo[i].ch);
+ if (ci != &charinfo[i])
+ {
+ mame_printf_error("ioport: expected char_info::find(0x%08x) to work properly\n", charinfo[i].ch);
+ error = TRUE;
+ }
+ }
+ return error;
}
+*/
-
-input_type_entry::input_type_entry(UINT32 _type, ioport_group _group, int _player, const char *_token, const char *_name, input_seq standard)
- : type(_type),
- group(_group),
- player(_player),
- token(_token),
- name(_name),
- m_next(NULL)
-{
- defseq[SEQ_TYPE_STANDARD] = seq[SEQ_TYPE_STANDARD] = standard;
-}
-
-input_type_entry::input_type_entry(UINT32 _type, ioport_group _group, int _player, const char *_token, const char *_name, input_seq standard, input_seq decrement, input_seq increment)
- : type(_type),
- group(_group),
- player(_player),
- token(_token),
- name(_name),
- m_next(NULL)
-{
- defseq[SEQ_TYPE_STANDARD] = seq[SEQ_TYPE_STANDARD] = standard;
- defseq[SEQ_TYPE_INCREMENT] = seq[SEQ_TYPE_INCREMENT] = increment;
- defseq[SEQ_TYPE_DECREMENT] = seq[SEQ_TYPE_DECREMENT] = decrement;
-}