summaryrefslogtreecommitdiffstatshomepage
path: root/src/osd
diff options
context:
space:
mode:
author Vas Crabb <vas@vastheman.com>2022-06-16 03:32:46 +1000
committer Vas Crabb <vas@vastheman.com>2022-06-16 03:32:46 +1000
commit1964365f34499ae5785c7b8f13836caa05156dfa (patch)
tree15ce654e3170c3509db1fddbb9b70a194f77cb46 /src/osd
parentd345b7ec2ccf3c9a958bddd3906a202e42a88809 (diff)
Optimisation, and baby steps towards untangling stuff:
Optimised the scheduler's handling of unscheduled timers - gives a 50% performance improvement in some timer-heavy drivers. Added better endianness swizzling helpers. Got rid of some of the OSD input modules' dependence on concrete input classes from emu.
Diffstat (limited to 'src/osd')
-rw-r--r--src/osd/interface/inputcode.h872
-rw-r--r--src/osd/interface/inputman.h77
-rw-r--r--src/osd/interface/inputseq.cpp210
-rw-r--r--src/osd/interface/inputseq.h107
-rw-r--r--src/osd/modules/input/input_common.cpp45
-rw-r--r--src/osd/modules/input/input_common.h74
-rw-r--r--src/osd/modules/input/input_dinput.cpp6
-rw-r--r--src/osd/modules/input/input_rawinput.cpp12
-rw-r--r--src/osd/modules/input/input_sdl.cpp8
-rw-r--r--src/osd/modules/input/input_win32.cpp4
-rw-r--r--src/osd/osdcomm.h22
11 files changed, 1366 insertions, 71 deletions
diff --git a/src/osd/interface/inputcode.h b/src/osd/interface/inputcode.h
new file mode 100644
index 00000000000..1d5b1156ae5
--- /dev/null
+++ b/src/osd/interface/inputcode.h
@@ -0,0 +1,872 @@
+// license:BSD-3-Clause
+// copyright-holders:Aaron Giles
+/***************************************************************************
+
+ inputcode.h
+
+ Codes for representing host inputs
+
+***************************************************************************/
+#ifndef MAME_OSD_INTERFACE_INPUTCODE_H
+#define MAME_OSD_INTERFACE_INPUTCODE_H
+
+#pragma once
+
+#include "osdcomm.h"
+
+#include <cassert>
+
+
+//**************************************************************************
+// CONSTANTS
+//**************************************************************************
+
+// maximum number of axis/buttons/hats with ITEM_IDs for use by osd layer
+constexpr int INPUT_MAX_AXIS = 8;
+constexpr int INPUT_MAX_BUTTONS = 32;
+constexpr int INPUT_MAX_HATS = 4;
+constexpr int INPUT_MAX_ADD_SWITCH = 16;
+constexpr int INPUT_MAX_ADD_ABSOLUTE = 16;
+constexpr int INPUT_MAX_ADD_RELATIVE = 16;
+
+
+// device classes
+enum input_device_class
+{
+ DEVICE_CLASS_INVALID,
+ DEVICE_CLASS_FIRST_VALID,
+ DEVICE_CLASS_KEYBOARD = DEVICE_CLASS_FIRST_VALID,
+ DEVICE_CLASS_MOUSE,
+ DEVICE_CLASS_LIGHTGUN,
+ DEVICE_CLASS_JOYSTICK,
+ DEVICE_CLASS_LAST_VALID = DEVICE_CLASS_JOYSTICK,
+ DEVICE_CLASS_INTERNAL,
+ DEVICE_CLASS_MAXIMUM
+};
+DECLARE_ENUM_INCDEC_OPERATORS(input_device_class)
+
+
+// device index
+constexpr int DEVICE_INDEX_MAXIMUM = 0xff;
+
+
+// input item classes
+enum input_item_class
+{
+ ITEM_CLASS_INVALID,
+ ITEM_CLASS_SWITCH,
+ ITEM_CLASS_ABSOLUTE,
+ ITEM_CLASS_RELATIVE,
+ ITEM_CLASS_MAXIMUM
+};
+
+
+// input item modifiers
+enum input_item_modifier
+{
+ ITEM_MODIFIER_NONE,
+ ITEM_MODIFIER_REVERSE,
+ ITEM_MODIFIER_POS,
+ ITEM_MODIFIER_NEG,
+ ITEM_MODIFIER_LEFT,
+ ITEM_MODIFIER_RIGHT,
+ ITEM_MODIFIER_UP,
+ ITEM_MODIFIER_DOWN,
+ ITEM_MODIFIER_MAXIMUM
+};
+
+
+// standard item IDs
+enum input_item_id
+{
+ ITEM_ID_INVALID,
+ ITEM_ID_FIRST_VALID,
+
+ // standard keyboard IDs
+ ITEM_ID_A = ITEM_ID_FIRST_VALID,
+ ITEM_ID_B,
+ ITEM_ID_C,
+ ITEM_ID_D,
+ ITEM_ID_E,
+ ITEM_ID_F,
+ ITEM_ID_G,
+ ITEM_ID_H,
+ ITEM_ID_I,
+ ITEM_ID_J,
+ ITEM_ID_K,
+ ITEM_ID_L,
+ ITEM_ID_M,
+ ITEM_ID_N,
+ ITEM_ID_O,
+ ITEM_ID_P,
+ ITEM_ID_Q,
+ ITEM_ID_R,
+ ITEM_ID_S,
+ ITEM_ID_T,
+ ITEM_ID_U,
+ ITEM_ID_V,
+ ITEM_ID_W,
+ ITEM_ID_X,
+ ITEM_ID_Y,
+ ITEM_ID_Z,
+ ITEM_ID_0,
+ ITEM_ID_1,
+ ITEM_ID_2,
+ ITEM_ID_3,
+ ITEM_ID_4,
+ ITEM_ID_5,
+ ITEM_ID_6,
+ ITEM_ID_7,
+ ITEM_ID_8,
+ ITEM_ID_9,
+ ITEM_ID_F1,
+ ITEM_ID_F2,
+ ITEM_ID_F3,
+ ITEM_ID_F4,
+ ITEM_ID_F5,
+ ITEM_ID_F6,
+ ITEM_ID_F7,
+ ITEM_ID_F8,
+ ITEM_ID_F9,
+ ITEM_ID_F10,
+ ITEM_ID_F11,
+ ITEM_ID_F12,
+ ITEM_ID_F13,
+ ITEM_ID_F14,
+ ITEM_ID_F15,
+ ITEM_ID_F16,
+ ITEM_ID_F17,
+ ITEM_ID_F18,
+ ITEM_ID_F19,
+ ITEM_ID_F20,
+ ITEM_ID_ESC,
+ ITEM_ID_TILDE,
+ ITEM_ID_MINUS,
+ ITEM_ID_EQUALS,
+ ITEM_ID_BACKSPACE,
+ ITEM_ID_TAB,
+ ITEM_ID_OPENBRACE,
+ ITEM_ID_CLOSEBRACE,
+ ITEM_ID_ENTER,
+ ITEM_ID_COLON,
+ ITEM_ID_QUOTE,
+ ITEM_ID_BACKSLASH,
+ ITEM_ID_BACKSLASH2,
+ ITEM_ID_COMMA,
+ ITEM_ID_STOP,
+ ITEM_ID_SLASH,
+ ITEM_ID_SPACE,
+ ITEM_ID_INSERT,
+ ITEM_ID_DEL,
+ ITEM_ID_HOME,
+ ITEM_ID_END,
+ ITEM_ID_PGUP,
+ ITEM_ID_PGDN,
+ ITEM_ID_LEFT,
+ ITEM_ID_RIGHT,
+ ITEM_ID_UP,
+ ITEM_ID_DOWN,
+ ITEM_ID_0_PAD,
+ ITEM_ID_1_PAD,
+ ITEM_ID_2_PAD,
+ ITEM_ID_3_PAD,
+ ITEM_ID_4_PAD,
+ ITEM_ID_5_PAD,
+ ITEM_ID_6_PAD,
+ ITEM_ID_7_PAD,
+ ITEM_ID_8_PAD,
+ ITEM_ID_9_PAD,
+ ITEM_ID_SLASH_PAD,
+ ITEM_ID_ASTERISK,
+ ITEM_ID_MINUS_PAD,
+ ITEM_ID_PLUS_PAD,
+ ITEM_ID_DEL_PAD,
+ ITEM_ID_ENTER_PAD,
+ ITEM_ID_BS_PAD,
+ ITEM_ID_TAB_PAD,
+ ITEM_ID_00_PAD,
+ ITEM_ID_000_PAD,
+ ITEM_ID_COMMA_PAD,
+ ITEM_ID_EQUALS_PAD,
+ ITEM_ID_PRTSCR,
+ ITEM_ID_PAUSE,
+ ITEM_ID_LSHIFT,
+ ITEM_ID_RSHIFT,
+ ITEM_ID_LCONTROL,
+ ITEM_ID_RCONTROL,
+ ITEM_ID_LALT,
+ ITEM_ID_RALT,
+ ITEM_ID_SCRLOCK,
+ ITEM_ID_NUMLOCK,
+ ITEM_ID_CAPSLOCK,
+ ITEM_ID_LWIN,
+ ITEM_ID_RWIN,
+ ITEM_ID_MENU,
+ ITEM_ID_CANCEL,
+
+ // standard mouse/joystick/gun IDs
+ ITEM_ID_XAXIS,
+ ITEM_ID_YAXIS,
+ ITEM_ID_ZAXIS,
+ ITEM_ID_RXAXIS,
+ ITEM_ID_RYAXIS,
+ ITEM_ID_RZAXIS,
+ ITEM_ID_SLIDER1,
+ ITEM_ID_SLIDER2,
+ ITEM_ID_BUTTON1,
+ ITEM_ID_BUTTON2,
+ ITEM_ID_BUTTON3,
+ ITEM_ID_BUTTON4,
+ ITEM_ID_BUTTON5,
+ ITEM_ID_BUTTON6,
+ ITEM_ID_BUTTON7,
+ ITEM_ID_BUTTON8,
+ ITEM_ID_BUTTON9,
+ ITEM_ID_BUTTON10,
+ ITEM_ID_BUTTON11,
+ ITEM_ID_BUTTON12,
+ ITEM_ID_BUTTON13,
+ ITEM_ID_BUTTON14,
+ ITEM_ID_BUTTON15,
+ ITEM_ID_BUTTON16,
+ ITEM_ID_BUTTON17,
+ ITEM_ID_BUTTON18,
+ ITEM_ID_BUTTON19,
+ ITEM_ID_BUTTON20,
+ ITEM_ID_BUTTON21,
+ ITEM_ID_BUTTON22,
+ ITEM_ID_BUTTON23,
+ ITEM_ID_BUTTON24,
+ ITEM_ID_BUTTON25,
+ ITEM_ID_BUTTON26,
+ ITEM_ID_BUTTON27,
+ ITEM_ID_BUTTON28,
+ ITEM_ID_BUTTON29,
+ ITEM_ID_BUTTON30,
+ ITEM_ID_BUTTON31,
+ ITEM_ID_BUTTON32,
+ ITEM_ID_START,
+ ITEM_ID_SELECT,
+
+ // Hats
+ ITEM_ID_HAT1UP,
+ ITEM_ID_HAT1DOWN,
+ ITEM_ID_HAT1LEFT,
+ ITEM_ID_HAT1RIGHT,
+ ITEM_ID_HAT2UP,
+ ITEM_ID_HAT2DOWN,
+ ITEM_ID_HAT2LEFT,
+ ITEM_ID_HAT2RIGHT,
+ ITEM_ID_HAT3UP,
+ ITEM_ID_HAT3DOWN,
+ ITEM_ID_HAT3LEFT,
+ ITEM_ID_HAT3RIGHT,
+ ITEM_ID_HAT4UP,
+ ITEM_ID_HAT4DOWN,
+ ITEM_ID_HAT4LEFT,
+ ITEM_ID_HAT4RIGHT,
+
+ // Additional IDs
+ ITEM_ID_ADD_SWITCH1,
+ ITEM_ID_ADD_SWITCH2,
+ ITEM_ID_ADD_SWITCH3,
+ ITEM_ID_ADD_SWITCH4,
+ ITEM_ID_ADD_SWITCH5,
+ ITEM_ID_ADD_SWITCH6,
+ ITEM_ID_ADD_SWITCH7,
+ ITEM_ID_ADD_SWITCH8,
+ ITEM_ID_ADD_SWITCH9,
+ ITEM_ID_ADD_SWITCH10,
+ ITEM_ID_ADD_SWITCH11,
+ ITEM_ID_ADD_SWITCH12,
+ ITEM_ID_ADD_SWITCH13,
+ ITEM_ID_ADD_SWITCH14,
+ ITEM_ID_ADD_SWITCH15,
+ ITEM_ID_ADD_SWITCH16,
+
+ ITEM_ID_ADD_ABSOLUTE1,
+ ITEM_ID_ADD_ABSOLUTE2,
+ ITEM_ID_ADD_ABSOLUTE3,
+ ITEM_ID_ADD_ABSOLUTE4,
+ ITEM_ID_ADD_ABSOLUTE5,
+ ITEM_ID_ADD_ABSOLUTE6,
+ ITEM_ID_ADD_ABSOLUTE7,
+ ITEM_ID_ADD_ABSOLUTE8,
+ ITEM_ID_ADD_ABSOLUTE9,
+ ITEM_ID_ADD_ABSOLUTE10,
+ ITEM_ID_ADD_ABSOLUTE11,
+ ITEM_ID_ADD_ABSOLUTE12,
+ ITEM_ID_ADD_ABSOLUTE13,
+ ITEM_ID_ADD_ABSOLUTE14,
+ ITEM_ID_ADD_ABSOLUTE15,
+ ITEM_ID_ADD_ABSOLUTE16,
+
+ ITEM_ID_ADD_RELATIVE1,
+ ITEM_ID_ADD_RELATIVE2,
+ ITEM_ID_ADD_RELATIVE3,
+ ITEM_ID_ADD_RELATIVE4,
+ ITEM_ID_ADD_RELATIVE5,
+ ITEM_ID_ADD_RELATIVE6,
+ ITEM_ID_ADD_RELATIVE7,
+ ITEM_ID_ADD_RELATIVE8,
+ ITEM_ID_ADD_RELATIVE9,
+ ITEM_ID_ADD_RELATIVE10,
+ ITEM_ID_ADD_RELATIVE11,
+ ITEM_ID_ADD_RELATIVE12,
+ ITEM_ID_ADD_RELATIVE13,
+ ITEM_ID_ADD_RELATIVE14,
+ ITEM_ID_ADD_RELATIVE15,
+ ITEM_ID_ADD_RELATIVE16,
+
+ // generic other IDs
+ ITEM_ID_OTHER_SWITCH,
+ ITEM_ID_OTHER_AXIS_ABSOLUTE,
+ ITEM_ID_OTHER_AXIS_RELATIVE,
+ ITEM_ID_MAXIMUM,
+
+ // internal codes for sequences
+ ITEM_ID_SEQ_END,
+ ITEM_ID_SEQ_DEFAULT,
+ ITEM_ID_SEQ_NOT,
+ ITEM_ID_SEQ_OR,
+
+ // absolute maximum ID
+ ITEM_ID_ABSOLUTE_MAXIMUM = 0xfff
+};
+DECLARE_ENUM_INCDEC_OPERATORS(input_item_id)
+
+
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// a combined code that describes a particular input on a particular device
+
+class input_code
+{
+public:
+ // construction/destruction
+ constexpr input_code(
+ input_device_class devclass = DEVICE_CLASS_INVALID,
+ int devindex = 0,
+ input_item_class itemclass = ITEM_CLASS_INVALID,
+ input_item_modifier modifier = ITEM_MODIFIER_NONE,
+ input_item_id itemid = ITEM_ID_INVALID) noexcept
+ : m_internal(((devclass & 0xf) << 28) | ((devindex & 0xff) << 20) | ((itemclass & 0xf) << 16) | ((modifier & 0xf) << 12) | (itemid & 0xfff))
+ {
+ assert(devclass >= 0 && devclass < DEVICE_CLASS_MAXIMUM);
+ assert(devindex >= 0 && devindex < DEVICE_INDEX_MAXIMUM);
+ assert(itemclass >= 0 && itemclass < ITEM_CLASS_MAXIMUM);
+ assert(modifier >= 0 && modifier < ITEM_MODIFIER_MAXIMUM);
+ assert(itemid >= 0 && itemid < ITEM_ID_ABSOLUTE_MAXIMUM);
+ }
+ constexpr input_code(const input_code &src) noexcept = default;
+
+ // operators
+ constexpr bool operator==(const input_code &rhs) const noexcept { return m_internal == rhs.m_internal; }
+ constexpr bool operator!=(const input_code &rhs) const noexcept { return m_internal != rhs.m_internal; }
+ constexpr bool operator<(const input_code &rhs) const noexcept { return m_internal < rhs.m_internal; }
+
+ // getters
+ constexpr bool internal() const noexcept { return device_class() == DEVICE_CLASS_INTERNAL; }
+ constexpr input_device_class device_class() const noexcept { return input_device_class((m_internal >> 28) & 0xf); }
+ constexpr int device_index() const noexcept { return ((m_internal >> 20) & 0xff); }
+ constexpr input_item_class item_class() const noexcept { return input_item_class((m_internal >> 16) & 0xf); }
+ constexpr input_item_modifier item_modifier() const noexcept { return input_item_modifier((m_internal >> 12) & 0xf); }
+ constexpr input_item_id item_id() const noexcept { return input_item_id(m_internal & 0xfff); }
+
+ // setters
+ void set_device_class(input_device_class devclass) noexcept
+ {
+ assert(devclass >= 0 && devclass <= 0xf);
+ m_internal = (m_internal & ~(0xf << 28)) | ((devclass & 0xf) << 28);
+ }
+ void set_device_index(int devindex) noexcept
+ {
+ assert(devindex >= 0 && devindex <= 0xff);
+ m_internal = (m_internal & ~(0xff << 20)) | ((devindex & 0xff) << 20);
+ }
+ void set_item_class(input_item_class itemclass) noexcept
+ {
+ assert(itemclass >= 0 && itemclass <= 0xf);
+ m_internal = (m_internal & ~(0xf << 16)) | ((itemclass & 0xf) << 16);
+ }
+ void set_item_modifier(input_item_modifier modifier) noexcept
+ {
+ assert(modifier >= 0 && modifier <= 0xf);
+ m_internal = (m_internal & ~(0xf << 12)) | ((modifier & 0xf) << 12);
+ }
+ void set_item_id(input_item_id itemid) noexcept
+ {
+ assert(itemid >= 0 && itemid <= 0xfff);
+ m_internal = (m_internal & ~0xfff) | (itemid & 0xfff);
+ }
+
+private:
+ osd::u32 m_internal;
+};
+
+
+
+//**************************************************************************
+// MACROS
+//**************************************************************************
+
+// invalid codes
+#define INPUT_CODE_INVALID input_code()
+
+// keyboard codes
+constexpr input_code KEYCODE_A_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_A); }
+constexpr input_code KEYCODE_B_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_B); }
+constexpr input_code KEYCODE_C_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_C); }
+constexpr input_code KEYCODE_D_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_D); }
+constexpr input_code KEYCODE_E_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_E); }
+constexpr input_code KEYCODE_F_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_F); }
+constexpr input_code KEYCODE_G_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_G); }
+constexpr input_code KEYCODE_H_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_H); }
+constexpr input_code KEYCODE_I_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_I); }
+constexpr input_code KEYCODE_J_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_J); }
+constexpr input_code KEYCODE_K_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_K); }
+constexpr input_code KEYCODE_L_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_L); }
+constexpr input_code KEYCODE_M_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_M); }
+constexpr input_code KEYCODE_N_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_N); }
+constexpr input_code KEYCODE_O_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_O); }
+constexpr input_code KEYCODE_P_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_P); }
+constexpr input_code KEYCODE_Q_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_Q); }
+constexpr input_code KEYCODE_R_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_R); }
+constexpr input_code KEYCODE_S_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_S); }
+constexpr input_code KEYCODE_T_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_T); }
+constexpr input_code KEYCODE_U_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_U); }
+constexpr input_code KEYCODE_V_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_V); }
+constexpr input_code KEYCODE_W_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_W); }
+constexpr input_code KEYCODE_X_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_X); }
+constexpr input_code KEYCODE_Y_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_Y); }
+constexpr input_code KEYCODE_Z_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_Z); }
+constexpr input_code KEYCODE_0_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_0); }
+constexpr input_code KEYCODE_1_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_1); }
+constexpr input_code KEYCODE_2_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_2); }
+constexpr input_code KEYCODE_3_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_3); }
+constexpr input_code KEYCODE_4_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_4); }
+constexpr input_code KEYCODE_5_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_5); }
+constexpr input_code KEYCODE_6_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_6); }
+constexpr input_code KEYCODE_7_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_7); }
+constexpr input_code KEYCODE_8_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_8); }
+constexpr input_code KEYCODE_9_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_9); }
+constexpr input_code KEYCODE_F1_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_F1); }
+constexpr input_code KEYCODE_F2_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_F2); }
+constexpr input_code KEYCODE_F3_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_F3); }
+constexpr input_code KEYCODE_F4_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_F4); }
+constexpr input_code KEYCODE_F5_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_F5); }
+constexpr input_code KEYCODE_F6_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_F6); }
+constexpr input_code KEYCODE_F7_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_F7); }
+constexpr input_code KEYCODE_F8_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_F8); }
+constexpr input_code KEYCODE_F9_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_F9); }
+constexpr input_code KEYCODE_F10_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_F10); }
+constexpr input_code KEYCODE_F11_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_F11); }
+constexpr input_code KEYCODE_F12_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_F12); }
+constexpr input_code KEYCODE_F13_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_F13); }
+constexpr input_code KEYCODE_F14_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_F14); }
+constexpr input_code KEYCODE_F15_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_F15); }
+constexpr input_code KEYCODE_F16_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_F16); }
+constexpr input_code KEYCODE_F17_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_F17); }
+constexpr input_code KEYCODE_F18_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_F18); }
+constexpr input_code KEYCODE_F19_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_F19); }
+constexpr input_code KEYCODE_F20_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_F20); }
+constexpr input_code KEYCODE_ESC_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_ESC); }
+constexpr input_code KEYCODE_TILDE_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_TILDE); }
+constexpr input_code KEYCODE_MINUS_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_MINUS); }
+constexpr input_code KEYCODE_EQUALS_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_EQUALS); }
+constexpr input_code KEYCODE_BACKSPACE_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BACKSPACE); }
+constexpr input_code KEYCODE_TAB_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_TAB); }
+constexpr input_code KEYCODE_OPENBRACE_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_OPENBRACE); }
+constexpr input_code KEYCODE_CLOSEBRACE_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_CLOSEBRACE); }
+constexpr input_code KEYCODE_ENTER_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_ENTER); }
+constexpr input_code KEYCODE_COLON_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_COLON); }
+constexpr input_code KEYCODE_QUOTE_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_QUOTE); }
+constexpr input_code KEYCODE_BACKSLASH_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BACKSLASH); }
+constexpr input_code KEYCODE_BACKSLASH2_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BACKSLASH2); }
+constexpr input_code KEYCODE_COMMA_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_COMMA); }
+constexpr input_code KEYCODE_STOP_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_STOP); }
+constexpr input_code KEYCODE_SLASH_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_SLASH); }
+constexpr input_code KEYCODE_SPACE_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_SPACE); }
+constexpr input_code KEYCODE_INSERT_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_INSERT); }
+constexpr input_code KEYCODE_DEL_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_DEL); }
+constexpr input_code KEYCODE_HOME_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_HOME); }
+constexpr input_code KEYCODE_END_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_END); }
+constexpr input_code KEYCODE_PGUP_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_PGUP); }
+constexpr input_code KEYCODE_PGDN_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_PGDN); }
+constexpr input_code KEYCODE_LEFT_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_LEFT); }
+constexpr input_code KEYCODE_RIGHT_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_RIGHT); }
+constexpr input_code KEYCODE_UP_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_UP); }
+constexpr input_code KEYCODE_DOWN_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_DOWN); }
+constexpr input_code KEYCODE_0_PAD_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_0_PAD); }
+constexpr input_code KEYCODE_1_PAD_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_1_PAD); }
+constexpr input_code KEYCODE_2_PAD_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_2_PAD); }
+constexpr input_code KEYCODE_3_PAD_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_3_PAD); }
+constexpr input_code KEYCODE_4_PAD_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_4_PAD); }
+constexpr input_code KEYCODE_5_PAD_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_5_PAD); }
+constexpr input_code KEYCODE_6_PAD_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_6_PAD); }
+constexpr input_code KEYCODE_7_PAD_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_7_PAD); }
+constexpr input_code KEYCODE_8_PAD_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_8_PAD); }
+constexpr input_code KEYCODE_9_PAD_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_9_PAD); }
+constexpr input_code KEYCODE_SLASH_PAD_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_SLASH_PAD); }
+constexpr input_code KEYCODE_ASTERISK_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_ASTERISK); }
+constexpr input_code KEYCODE_MINUS_PAD_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_MINUS_PAD); }
+constexpr input_code KEYCODE_PLUS_PAD_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_PLUS_PAD); }
+constexpr input_code KEYCODE_DEL_PAD_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_DEL_PAD); }
+constexpr input_code KEYCODE_ENTER_PAD_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_ENTER_PAD); }
+constexpr input_code KEYCODE_BS_PAD_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BS_PAD); }
+constexpr input_code KEYCODE_TAB_PAD_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_TAB_PAD); }
+constexpr input_code KEYCODE_00_PAD_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_00_PAD); }
+constexpr input_code KEYCODE_000_PAD_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_000_PAD); }
+constexpr input_code KEYCODE_COMMA_PAD_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_COMMA_PAD); }
+constexpr input_code KEYCODE_EQUALS_PAD_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_EQUALS_PAD); }
+constexpr input_code KEYCODE_PRTSCR_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_PRTSCR); }
+constexpr input_code KEYCODE_PAUSE_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_PAUSE); }
+constexpr input_code KEYCODE_LSHIFT_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_LSHIFT); }
+constexpr input_code KEYCODE_RSHIFT_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_RSHIFT); }
+constexpr input_code KEYCODE_LCONTROL_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_LCONTROL); }
+constexpr input_code KEYCODE_RCONTROL_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_RCONTROL); }
+constexpr input_code KEYCODE_LALT_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_LALT); }
+constexpr input_code KEYCODE_RALT_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_RALT); }
+constexpr input_code KEYCODE_SCRLOCK_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_SCRLOCK); }
+constexpr input_code KEYCODE_NUMLOCK_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_NUMLOCK); }
+constexpr input_code KEYCODE_CAPSLOCK_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_CAPSLOCK); }
+constexpr input_code KEYCODE_LWIN_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_LWIN); }
+constexpr input_code KEYCODE_RWIN_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_RWIN); }
+constexpr input_code KEYCODE_MENU_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_MENU); }
+constexpr input_code KEYCODE_CANCEL_INDEXED(int n) { return input_code(DEVICE_CLASS_KEYBOARD, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_CANCEL); }
+
+#define KEYCODE_A KEYCODE_A_INDEXED(0)
+#define KEYCODE_B KEYCODE_B_INDEXED(0)
+#define KEYCODE_C KEYCODE_C_INDEXED(0)
+#define KEYCODE_D KEYCODE_D_INDEXED(0)
+#define KEYCODE_E KEYCODE_E_INDEXED(0)
+#define KEYCODE_F KEYCODE_F_INDEXED(0)
+#define KEYCODE_G KEYCODE_G_INDEXED(0)
+#define KEYCODE_H KEYCODE_H_INDEXED(0)
+#define KEYCODE_I KEYCODE_I_INDEXED(0)
+#define KEYCODE_J KEYCODE_J_INDEXED(0)
+#define KEYCODE_K KEYCODE_K_INDEXED(0)
+#define KEYCODE_L KEYCODE_L_INDEXED(0)
+#define KEYCODE_M KEYCODE_M_INDEXED(0)
+#define KEYCODE_N KEYCODE_N_INDEXED(0)
+#define KEYCODE_O KEYCODE_O_INDEXED(0)
+#define KEYCODE_P KEYCODE_P_INDEXED(0)
+#define KEYCODE_Q KEYCODE_Q_INDEXED(0)
+#define KEYCODE_R KEYCODE_R_INDEXED(0)
+#define KEYCODE_S KEYCODE_S_INDEXED(0)
+#define KEYCODE_T KEYCODE_T_INDEXED(0)
+#define KEYCODE_U KEYCODE_U_INDEXED(0)
+#define KEYCODE_V KEYCODE_V_INDEXED(0)
+#define KEYCODE_W KEYCODE_W_INDEXED(0)
+#define KEYCODE_X KEYCODE_X_INDEXED(0)
+#define KEYCODE_Y KEYCODE_Y_INDEXED(0)
+#define KEYCODE_Z KEYCODE_Z_INDEXED(0)
+#define KEYCODE_0 KEYCODE_0_INDEXED(0)
+#define KEYCODE_1 KEYCODE_1_INDEXED(0)
+#define KEYCODE_2 KEYCODE_2_INDEXED(0)
+#define KEYCODE_3 KEYCODE_3_INDEXED(0)
+#define KEYCODE_4 KEYCODE_4_INDEXED(0)
+#define KEYCODE_5 KEYCODE_5_INDEXED(0)
+#define KEYCODE_6 KEYCODE_6_INDEXED(0)
+#define KEYCODE_7 KEYCODE_7_INDEXED(0)
+#define KEYCODE_8 KEYCODE_8_INDEXED(0)
+#define KEYCODE_9 KEYCODE_9_INDEXED(0)
+#define KEYCODE_F1 KEYCODE_F1_INDEXED(0)
+#define KEYCODE_F2 KEYCODE_F2_INDEXED(0)
+#define KEYCODE_F3 KEYCODE_F3_INDEXED(0)
+#define KEYCODE_F4 KEYCODE_F4_INDEXED(0)
+#define KEYCODE_F5 KEYCODE_F5_INDEXED(0)
+#define KEYCODE_F6 KEYCODE_F6_INDEXED(0)
+#define KEYCODE_F7 KEYCODE_F7_INDEXED(0)
+#define KEYCODE_F8 KEYCODE_F8_INDEXED(0)
+#define KEYCODE_F9 KEYCODE_F9_INDEXED(0)
+#define KEYCODE_F10 KEYCODE_F10_INDEXED(0)
+#define KEYCODE_F11 KEYCODE_F11_INDEXED(0)
+#define KEYCODE_F12 KEYCODE_F12_INDEXED(0)
+#define KEYCODE_F13 KEYCODE_F13_INDEXED(0)
+#define KEYCODE_F14 KEYCODE_F14_INDEXED(0)
+#define KEYCODE_F15 KEYCODE_F15_INDEXED(0)
+#define KEYCODE_F16 KEYCODE_F16_INDEXED(0)
+#define KEYCODE_F17 KEYCODE_F17_INDEXED(0)
+#define KEYCODE_F18 KEYCODE_F18_INDEXED(0)
+#define KEYCODE_F19 KEYCODE_F19_INDEXED(0)
+#define KEYCODE_F20 KEYCODE_F20_INDEXED(0)
+#define KEYCODE_ESC KEYCODE_ESC_INDEXED(0)
+#define KEYCODE_TILDE KEYCODE_TILDE_INDEXED(0)
+#define KEYCODE_MINUS KEYCODE_MINUS_INDEXED(0)
+#define KEYCODE_EQUALS KEYCODE_EQUALS_INDEXED(0)
+#define KEYCODE_BACKSPACE KEYCODE_BACKSPACE_INDEXED(0)
+#define KEYCODE_TAB KEYCODE_TAB_INDEXED(0)
+#define KEYCODE_OPENBRACE KEYCODE_OPENBRACE_INDEXED(0)
+#define KEYCODE_CLOSEBRACE KEYCODE_CLOSEBRACE_INDEXED(0)
+#define KEYCODE_ENTER KEYCODE_ENTER_INDEXED(0)
+#define KEYCODE_COLON KEYCODE_COLON_INDEXED(0)
+#define KEYCODE_QUOTE KEYCODE_QUOTE_INDEXED(0)
+#define KEYCODE_BACKSLASH KEYCODE_BACKSLASH_INDEXED(0)
+#define KEYCODE_BACKSLASH2 KEYCODE_BACKSLASH2_INDEXED(0)
+#define KEYCODE_COMMA KEYCODE_COMMA_INDEXED(0)
+#define KEYCODE_STOP KEYCODE_STOP_INDEXED(0)
+#define KEYCODE_SLASH KEYCODE_SLASH_INDEXED(0)
+#define KEYCODE_SPACE KEYCODE_SPACE_INDEXED(0)
+#define KEYCODE_INSERT KEYCODE_INSERT_INDEXED(0)
+#define KEYCODE_DEL KEYCODE_DEL_INDEXED(0)
+#define KEYCODE_HOME KEYCODE_HOME_INDEXED(0)
+#define KEYCODE_END KEYCODE_END_INDEXED(0)
+#define KEYCODE_PGUP KEYCODE_PGUP_INDEXED(0)
+#define KEYCODE_PGDN KEYCODE_PGDN_INDEXED(0)
+#define KEYCODE_LEFT KEYCODE_LEFT_INDEXED(0)
+#define KEYCODE_RIGHT KEYCODE_RIGHT_INDEXED(0)
+#define KEYCODE_UP KEYCODE_UP_INDEXED(0)
+#define KEYCODE_DOWN KEYCODE_DOWN_INDEXED(0)
+#define KEYCODE_0_PAD KEYCODE_0_PAD_INDEXED(0)
+#define KEYCODE_1_PAD KEYCODE_1_PAD_INDEXED(0)
+#define KEYCODE_2_PAD KEYCODE_2_PAD_INDEXED(0)
+#define KEYCODE_3_PAD KEYCODE_3_PAD_INDEXED(0)
+#define KEYCODE_4_PAD KEYCODE_4_PAD_INDEXED(0)
+#define KEYCODE_5_PAD KEYCODE_5_PAD_INDEXED(0)
+#define KEYCODE_6_PAD KEYCODE_6_PAD_INDEXED(0)
+#define KEYCODE_7_PAD KEYCODE_7_PAD_INDEXED(0)
+#define KEYCODE_8_PAD KEYCODE_8_PAD_INDEXED(0)
+#define KEYCODE_9_PAD KEYCODE_9_PAD_INDEXED(0)
+#define KEYCODE_SLASH_PAD KEYCODE_SLASH_PAD_INDEXED(0)
+#define KEYCODE_ASTERISK KEYCODE_ASTERISK_INDEXED(0)
+#define KEYCODE_MINUS_PAD KEYCODE_MINUS_PAD_INDEXED(0)
+#define KEYCODE_PLUS_PAD KEYCODE_PLUS_PAD_INDEXED(0)
+#define KEYCODE_DEL_PAD KEYCODE_DEL_PAD_INDEXED(0)
+#define KEYCODE_ENTER_PAD KEYCODE_ENTER_PAD_INDEXED(0)
+#define KEYCODE_BS_PAD KEYCODE_BS_PAD_INDEXED(0)
+#define KEYCODE_TAB_PAD KEYCODE_TAB_PAD_INDEXED(0)
+#define KEYCODE_00_PAD KEYCODE_00_PAD_INDEXED(0)
+#define KEYCODE_000_PAD KEYCODE_000_PAD_INDEXED(0)
+#define KEYCODE_COMMA_PAD KEYCODE_COMMA_PAD_INDEXED(0)
+#define KEYCODE_EQUALS_PAD KEYCODE_EQUALS_PAD_INDEXED(0)
+#define KEYCODE_PRTSCR KEYCODE_PRTSCR_INDEXED(0)
+#define KEYCODE_PAUSE KEYCODE_PAUSE_INDEXED(0)
+#define KEYCODE_LSHIFT KEYCODE_LSHIFT_INDEXED(0)
+#define KEYCODE_RSHIFT KEYCODE_RSHIFT_INDEXED(0)
+#define KEYCODE_LCONTROL KEYCODE_LCONTROL_INDEXED(0)
+#define KEYCODE_RCONTROL KEYCODE_RCONTROL_INDEXED(0)
+#define KEYCODE_LALT KEYCODE_LALT_INDEXED(0)
+#define KEYCODE_RALT KEYCODE_RALT_INDEXED(0)
+#define KEYCODE_SCRLOCK KEYCODE_SCRLOCK_INDEXED(0)
+#define KEYCODE_NUMLOCK KEYCODE_NUMLOCK_INDEXED(0)
+#define KEYCODE_CAPSLOCK KEYCODE_CAPSLOCK_INDEXED(0)
+#define KEYCODE_LWIN KEYCODE_LWIN_INDEXED(0)
+#define KEYCODE_RWIN KEYCODE_RWIN_INDEXED(0)
+#define KEYCODE_MENU KEYCODE_MENU_INDEXED(0)
+#define KEYCODE_CANCEL KEYCODE_CANCEL_INDEXED(0)
+
+// mouse axes as relative devices
+constexpr input_code MOUSECODE_X_INDEXED(int n) { return input_code(DEVICE_CLASS_MOUSE, n, ITEM_CLASS_RELATIVE, ITEM_MODIFIER_NONE, ITEM_ID_XAXIS); }
+constexpr input_code MOUSECODE_Y_INDEXED(int n) { return input_code(DEVICE_CLASS_MOUSE, n, ITEM_CLASS_RELATIVE, ITEM_MODIFIER_NONE, ITEM_ID_YAXIS); }
+constexpr input_code MOUSECODE_Z_INDEXED(int n) { return input_code(DEVICE_CLASS_MOUSE, n, ITEM_CLASS_RELATIVE, ITEM_MODIFIER_NONE, ITEM_ID_ZAXIS); }
+
+#define MOUSECODE_X MOUSECODE_X_INDEXED(0)
+#define MOUSECODE_Y MOUSECODE_Y_INDEXED(0)
+#define MOUSECODE_Z MOUSECODE_Z_INDEXED(0)
+
+// mouse axes as switches in +/- direction
+constexpr input_code MOUSECODE_X_POS_SWITCH_INDEXED(int n) { return input_code(DEVICE_CLASS_MOUSE, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_POS, ITEM_ID_XAXIS); }
+constexpr input_code MOUSECODE_X_NEG_SWITCH_INDEXED(int n) { return input_code(DEVICE_CLASS_MOUSE, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NEG, ITEM_ID_XAXIS); }
+constexpr input_code MOUSECODE_Y_POS_SWITCH_INDEXED(int n) { return input_code(DEVICE_CLASS_MOUSE, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_POS, ITEM_ID_YAXIS); }
+constexpr input_code MOUSECODE_Y_NEG_SWITCH_INDEXED(int n) { return input_code(DEVICE_CLASS_MOUSE, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NEG, ITEM_ID_YAXIS); }
+constexpr input_code MOUSECODE_Z_POS_SWITCH_INDEXED(int n) { return input_code(DEVICE_CLASS_MOUSE, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_POS, ITEM_ID_ZAXIS); }
+constexpr input_code MOUSECODE_Z_NEG_SWITCH_INDEXED(int n) { return input_code(DEVICE_CLASS_MOUSE, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NEG, ITEM_ID_ZAXIS); }
+
+#define MOUSECODE_X_POS_SWITCH MOUSECODE_X_POS_SWITCH_INDEXED(0)
+#define MOUSECODE_X_NEG_SWITCH MOUSECODE_X_NEG_SWITCH_INDEXED(0)
+#define MOUSECODE_Y_POS_SWITCH MOUSECODE_Y_POS_SWITCH_INDEXED(0)
+#define MOUSECODE_Y_NEG_SWITCH MOUSECODE_Y_NEG_SWITCH_INDEXED(0)
+#define MOUSECODE_Z_POS_SWITCH MOUSECODE_Z_POS_SWITCH_INDEXED(0)
+#define MOUSECODE_Z_NEG_SWITCH MOUSECODE_Z_NEG_SWITCH_INDEXED(0)
+
+// mouse buttons
+constexpr input_code MOUSECODE_BUTTON1_INDEXED(int n) { return input_code(DEVICE_CLASS_MOUSE, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BUTTON1); }
+constexpr input_code MOUSECODE_BUTTON2_INDEXED(int n) { return input_code(DEVICE_CLASS_MOUSE, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BUTTON2); }
+constexpr input_code MOUSECODE_BUTTON3_INDEXED(int n) { return input_code(DEVICE_CLASS_MOUSE, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BUTTON3); }
+constexpr input_code MOUSECODE_BUTTON4_INDEXED(int n) { return input_code(DEVICE_CLASS_MOUSE, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BUTTON4); }
+constexpr input_code MOUSECODE_BUTTON5_INDEXED(int n) { return input_code(DEVICE_CLASS_MOUSE, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BUTTON5); }
+constexpr input_code MOUSECODE_BUTTON6_INDEXED(int n) { return input_code(DEVICE_CLASS_MOUSE, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BUTTON6); }
+constexpr input_code MOUSECODE_BUTTON7_INDEXED(int n) { return input_code(DEVICE_CLASS_MOUSE, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BUTTON7); }
+constexpr input_code MOUSECODE_BUTTON8_INDEXED(int n) { return input_code(DEVICE_CLASS_MOUSE, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BUTTON8); }
+
+#define MOUSECODE_BUTTON1 MOUSECODE_BUTTON1_INDEXED(0)
+#define MOUSECODE_BUTTON2 MOUSECODE_BUTTON2_INDEXED(0)
+#define MOUSECODE_BUTTON3 MOUSECODE_BUTTON3_INDEXED(0)
+#define MOUSECODE_BUTTON4 MOUSECODE_BUTTON4_INDEXED(0)
+#define MOUSECODE_BUTTON5 MOUSECODE_BUTTON5_INDEXED(0)
+#define MOUSECODE_BUTTON6 MOUSECODE_BUTTON6_INDEXED(0)
+#define MOUSECODE_BUTTON7 MOUSECODE_BUTTON7_INDEXED(0)
+#define MOUSECODE_BUTTON8 MOUSECODE_BUTTON8_INDEXED(0)
+
+// gun axes as absolute devices
+constexpr input_code GUNCODE_X_INDEXED(int n) { return input_code(DEVICE_CLASS_LIGHTGUN, n, ITEM_CLASS_ABSOLUTE, ITEM_MODIFIER_NONE, ITEM_ID_XAXIS); }
+constexpr input_code GUNCODE_Y_INDEXED(int n) { return input_code(DEVICE_CLASS_LIGHTGUN, n, ITEM_CLASS_ABSOLUTE, ITEM_MODIFIER_NONE, ITEM_ID_YAXIS); }
+
+#define GUNCODE_X GUNCODE_X_INDEXED(0)
+#define GUNCODE_Y GUNCODE_Y_INDEXED(0)
+
+// gun buttons
+constexpr input_code GUNCODE_BUTTON1_INDEXED(int n) { return input_code(DEVICE_CLASS_LIGHTGUN, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BUTTON1); }
+constexpr input_code GUNCODE_BUTTON2_INDEXED(int n) { return input_code(DEVICE_CLASS_LIGHTGUN, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BUTTON2); }
+constexpr input_code GUNCODE_BUTTON3_INDEXED(int n) { return input_code(DEVICE_CLASS_LIGHTGUN, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BUTTON3); }
+constexpr input_code GUNCODE_BUTTON4_INDEXED(int n) { return input_code(DEVICE_CLASS_LIGHTGUN, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BUTTON4); }
+constexpr input_code GUNCODE_BUTTON5_INDEXED(int n) { return input_code(DEVICE_CLASS_LIGHTGUN, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BUTTON5); }
+constexpr input_code GUNCODE_BUTTON6_INDEXED(int n) { return input_code(DEVICE_CLASS_LIGHTGUN, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BUTTON6); }
+constexpr input_code GUNCODE_BUTTON7_INDEXED(int n) { return input_code(DEVICE_CLASS_LIGHTGUN, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BUTTON7); }
+constexpr input_code GUNCODE_BUTTON8_INDEXED(int n) { return input_code(DEVICE_CLASS_LIGHTGUN, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BUTTON8); }
+
+#define GUNCODE_BUTTON1 GUNCODE_BUTTON1_INDEXED(0)
+#define GUNCODE_BUTTON2 GUNCODE_BUTTON2_INDEXED(0)
+#define GUNCODE_BUTTON3 GUNCODE_BUTTON3_INDEXED(0)
+#define GUNCODE_BUTTON4 GUNCODE_BUTTON4_INDEXED(0)
+#define GUNCODE_BUTTON5 GUNCODE_BUTTON5_INDEXED(0)
+#define GUNCODE_BUTTON6 GUNCODE_BUTTON6_INDEXED(0)
+#define GUNCODE_BUTTON7 GUNCODE_BUTTON7_INDEXED(0)
+#define GUNCODE_BUTTON8 GUNCODE_BUTTON8_INDEXED(0)
+
+// joystick axes as absolute devices
+constexpr input_code JOYCODE_X_INDEXED(int n) { return input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_ABSOLUTE, ITEM_MODIFIER_NONE, ITEM_ID_XAXIS); }
+constexpr input_code JOYCODE_Y_INDEXED(int n) { return input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_ABSOLUTE, ITEM_MODIFIER_NONE, ITEM_ID_YAXIS); }
+constexpr input_code JOYCODE_Z_INDEXED(int n) { return input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_ABSOLUTE, ITEM_MODIFIER_NONE, ITEM_ID_ZAXIS); }
+constexpr input_code JOYCODE_U_INDEXED(int n) { return input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_ABSOLUTE, ITEM_MODIFIER_NONE, ITEM_ID_RXAXIS); }
+constexpr input_code JOYCODE_V_INDEXED(int n) { return input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_ABSOLUTE, ITEM_MODIFIER_NONE, ITEM_ID_RYAXIS); }
+constexpr input_code JOYCODE_W_INDEXED(int n) { return input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_ABSOLUTE, ITEM_MODIFIER_NONE, ITEM_ID_RZAXIS); }
+
+#define JOYCODE_X JOYCODE_X_INDEXED(0)
+#define JOYCODE_Y JOYCODE_Y_INDEXED(0)
+#define JOYCODE_Z JOYCODE_Z_INDEXED(0)
+#define JOYCODE_U JOYCODE_U_INDEXED(0)
+#define JOYCODE_V JOYCODE_V_INDEXED(0)
+#define JOYCODE_W JOYCODE_W_INDEXED(0)
+
+// joystick axes as absolute half-axes
+constexpr input_code JOYCODE_X_POS_ABSOLUTE_INDEXED(int n) { return input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_ABSOLUTE, ITEM_MODIFIER_POS, ITEM_ID_XAXIS); }
+constexpr input_code JOYCODE_X_NEG_ABSOLUTE_INDEXED(int n) { return input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_ABSOLUTE, ITEM_MODIFIER_NEG, ITEM_ID_XAXIS); }
+constexpr input_code JOYCODE_Y_POS_ABSOLUTE_INDEXED(int n) { return input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_ABSOLUTE, ITEM_MODIFIER_POS, ITEM_ID_YAXIS); }
+constexpr input_code JOYCODE_Y_NEG_ABSOLUTE_INDEXED(int n) { return input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_ABSOLUTE, ITEM_MODIFIER_NEG, ITEM_ID_YAXIS); }
+constexpr input_code JOYCODE_Z_POS_ABSOLUTE_INDEXED(int n) { return input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_ABSOLUTE, ITEM_MODIFIER_POS, ITEM_ID_ZAXIS); }
+constexpr input_code JOYCODE_Z_NEG_ABSOLUTE_INDEXED(int n) { return input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_ABSOLUTE, ITEM_MODIFIER_NEG, ITEM_ID_ZAXIS); }
+constexpr input_code JOYCODE_U_POS_ABSOLUTE_INDEXED(int n) { return input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_ABSOLUTE, ITEM_MODIFIER_POS, ITEM_ID_RXAXIS); }
+constexpr input_code JOYCODE_U_NEG_ABSOLUTE_INDEXED(int n) { return input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_ABSOLUTE, ITEM_MODIFIER_NEG, ITEM_ID_RXAXIS); }
+constexpr input_code JOYCODE_V_POS_ABSOLUTE_INDEXED(int n) { return input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_ABSOLUTE, ITEM_MODIFIER_POS, ITEM_ID_RYAXIS); }
+constexpr input_code JOYCODE_V_NEG_ABSOLUTE_INDEXED(int n) { return input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_ABSOLUTE, ITEM_MODIFIER_NEG, ITEM_ID_RYAXIS); }
+constexpr input_code JOYCODE_W_POS_ABSOLUTE_INDEXED(int n) { return input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_ABSOLUTE, ITEM_MODIFIER_POS, ITEM_ID_RZAXIS); }
+constexpr input_code JOYCODE_W_NEG_ABSOLUTE_INDEXED(int n) { return input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_ABSOLUTE, ITEM_MODIFIER_NEG, ITEM_ID_RZAXIS); }
+
+#define JOYCODE_X_POS_ABSOLUTE JOYCODE_X_POS_ABSOLUTE_INDEXED(0)
+#define JOYCODE_X_NEG_ABSOLUTE JOYCODE_X_NEG_ABSOLUTE_INDEXED(0)
+#define JOYCODE_Y_POS_ABSOLUTE JOYCODE_Y_POS_ABSOLUTE_INDEXED(0)
+#define JOYCODE_Y_NEG_ABSOLUTE JOYCODE_Y_NEG_ABSOLUTE_INDEXED(0)
+#define JOYCODE_Z_POS_ABSOLUTE JOYCODE_Z_POS_ABSOLUTE_INDEXED(0)
+#define JOYCODE_Z_NEG_ABSOLUTE JOYCODE_Z_NEG_ABSOLUTE_INDEXED(0)
+#define JOYCODE_U_POS_ABSOLUTE JOYCODE_U_POS_ABSOLUTE_INDEXED(0)
+#define JOYCODE_U_NEG_ABSOLUTE JOYCODE_U_NEG_ABSOLUTE_INDEXED(0)
+#define JOYCODE_V_POS_ABSOLUTE JOYCODE_V_POS_ABSOLUTE_INDEXED(0)
+#define JOYCODE_V_NEG_ABSOLUTE JOYCODE_V_NEG_ABSOLUTE_INDEXED(0)
+#define JOYCODE_W_POS_ABSOLUTE JOYCODE_W_POS_ABSOLUTE_INDEXED(0)
+#define JOYCODE_W_NEG_ABSOLUTE JOYCODE_W_NEG_ABSOLUTE_INDEXED(0)
+
+// joystick axes as switches; X/Y are specially handled for left/right/up/down mapping
+constexpr input_code JOYCODE_X_LEFT_SWITCH_INDEXED(int n) { return input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_LEFT, ITEM_ID_XAXIS); }
+constexpr input_code JOYCODE_X_RIGHT_SWITCH_INDEXED(int n) { return input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_RIGHT, ITEM_ID_XAXIS); }
+constexpr input_code JOYCODE_Y_UP_SWITCH_INDEXED(int n) { return input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_UP, ITEM_ID_YAXIS); }
+constexpr input_code JOYCODE_Y_DOWN_SWITCH_INDEXED(int n) { return input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_DOWN, ITEM_ID_YAXIS); }
+constexpr input_code JOYCODE_Z_POS_SWITCH_INDEXED(int n) { return input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_POS, ITEM_ID_ZAXIS); }
+constexpr input_code JOYCODE_Z_NEG_SWITCH_INDEXED(int n) { return input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NEG, ITEM_ID_ZAXIS); }
+constexpr input_code JOYCODE_U_POS_SWITCH_INDEXED(int n) { return input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_POS, ITEM_ID_RXAXIS); }
+constexpr input_code JOYCODE_U_NEG_SWITCH_INDEXED(int n) { return input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NEG, ITEM_ID_RXAXIS); }
+constexpr input_code JOYCODE_V_POS_SWITCH_INDEXED(int n) { return input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_POS, ITEM_ID_RYAXIS); }
+constexpr input_code JOYCODE_V_NEG_SWITCH_INDEXED(int n) { return input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NEG, ITEM_ID_RYAXIS); }
+constexpr input_code JOYCODE_W_POS_SWITCH_INDEXED(int n) { return input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_POS, ITEM_ID_RZAXIS); }
+constexpr input_code JOYCODE_W_NEG_SWITCH_INDEXED(int n) { return input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NEG, ITEM_ID_RZAXIS); }
+
+#define JOYCODE_X_LEFT_SWITCH JOYCODE_X_LEFT_SWITCH_INDEXED(0)
+#define JOYCODE_X_RIGHT_SWITCH JOYCODE_X_RIGHT_SWITCH_INDEXED(0)
+#define JOYCODE_Y_UP_SWITCH JOYCODE_Y_UP_SWITCH_INDEXED(0)
+#define JOYCODE_Y_DOWN_SWITCH JOYCODE_Y_DOWN_SWITCH_INDEXED(0)
+#define JOYCODE_Z_POS_SWITCH JOYCODE_Z_POS_SWITCH_INDEXED(0)
+#define JOYCODE_Z_NEG_SWITCH JOYCODE_Z_NEG_SWITCH_INDEXED(0)
+#define JOYCODE_U_POS_SWITCH JOYCODE_U_POS_SWITCH_INDEXED(0)
+#define JOYCODE_U_NEG_SWITCH JOYCODE_U_NEG_SWITCH_INDEXED(0)
+#define JOYCODE_V_POS_SWITCH JOYCODE_V_POS_SWITCH_INDEXED(0)
+#define JOYCODE_V_NEG_SWITCH JOYCODE_V_NEG_SWITCH_INDEXED(0)
+#define JOYCODE_W_POS_SWITCH JOYCODE_W_POS_SWITCH_INDEXED(0)
+#define JOYCODE_W_NEG_SWITCH JOYCODE_W_NEG_SWITCH_INDEXED(0)
+
+// joystick buttons
+constexpr input_code JOYCODE_BUTTON1_INDEXED(int n) { return input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BUTTON1); }
+constexpr input_code JOYCODE_BUTTON2_INDEXED(int n) { return input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BUTTON2); }
+constexpr input_code JOYCODE_BUTTON3_INDEXED(int n) { return input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BUTTON3); }
+constexpr input_code JOYCODE_BUTTON4_INDEXED(int n) { return input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BUTTON4); }
+constexpr input_code JOYCODE_BUTTON5_INDEXED(int n) { return input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BUTTON5); }
+constexpr input_code JOYCODE_BUTTON6_INDEXED(int n) { return input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BUTTON6); }
+constexpr input_code JOYCODE_BUTTON7_INDEXED(int n) { return input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BUTTON7); }
+constexpr input_code JOYCODE_BUTTON8_INDEXED(int n) { return input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BUTTON8); }
+constexpr input_code JOYCODE_BUTTON9_INDEXED(int n) { return input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BUTTON9); }
+constexpr input_code JOYCODE_BUTTON10_INDEXED(int n) { return input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BUTTON10); }
+constexpr input_code JOYCODE_BUTTON11_INDEXED(int n) { return input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BUTTON11); }
+constexpr input_code JOYCODE_BUTTON12_INDEXED(int n) { return input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BUTTON12); }
+constexpr input_code JOYCODE_BUTTON13_INDEXED(int n) { return input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BUTTON13); }
+constexpr input_code JOYCODE_BUTTON14_INDEXED(int n) { return input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BUTTON14); }
+constexpr input_code JOYCODE_BUTTON15_INDEXED(int n) { return input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BUTTON15); }
+constexpr input_code JOYCODE_BUTTON16_INDEXED(int n) { return input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BUTTON16); }
+constexpr input_code JOYCODE_BUTTON17_INDEXED(int n) { return input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BUTTON17); }
+constexpr input_code JOYCODE_BUTTON18_INDEXED(int n) { return input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BUTTON18); }
+constexpr input_code JOYCODE_BUTTON19_INDEXED(int n) { return input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BUTTON19); }
+constexpr input_code JOYCODE_BUTTON20_INDEXED(int n) { return input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BUTTON20); }
+constexpr input_code JOYCODE_BUTTON21_INDEXED(int n) { return input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BUTTON21); }
+constexpr input_code JOYCODE_BUTTON22_INDEXED(int n) { return input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BUTTON22); }
+constexpr input_code JOYCODE_BUTTON23_INDEXED(int n) { return input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BUTTON23); }
+constexpr input_code JOYCODE_BUTTON24_INDEXED(int n) { return input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BUTTON24); }
+constexpr input_code JOYCODE_BUTTON25_INDEXED(int n) { return input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BUTTON25); }
+constexpr input_code JOYCODE_BUTTON26_INDEXED(int n) { return input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BUTTON26); }
+constexpr input_code JOYCODE_BUTTON27_INDEXED(int n) { return input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BUTTON27); }
+constexpr input_code JOYCODE_BUTTON28_INDEXED(int n) { return input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BUTTON28); }
+constexpr input_code JOYCODE_BUTTON29_INDEXED(int n) { return input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BUTTON29); }
+constexpr input_code JOYCODE_BUTTON30_INDEXED(int n) { return input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BUTTON30); }
+constexpr input_code JOYCODE_BUTTON31_INDEXED(int n) { return input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BUTTON31); }
+constexpr input_code JOYCODE_BUTTON32_INDEXED(int n) { return input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_BUTTON32); }
+constexpr input_code JOYCODE_START_INDEXED(int n) { return input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_START); }
+constexpr input_code JOYCODE_SELECT_INDEXED(int n) { return input_code(DEVICE_CLASS_JOYSTICK, n, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, ITEM_ID_SELECT); }
+
+#define JOYCODE_BUTTON1 JOYCODE_BUTTON1_INDEXED(0)
+#define JOYCODE_BUTTON2 JOYCODE_BUTTON2_INDEXED(0)
+#define JOYCODE_BUTTON3 JOYCODE_BUTTON3_INDEXED(0)
+#define JOYCODE_BUTTON4 JOYCODE_BUTTON4_INDEXED(0)
+#define JOYCODE_BUTTON5 JOYCODE_BUTTON5_INDEXED(0)
+#define JOYCODE_BUTTON6 JOYCODE_BUTTON6_INDEXED(0)
+#define JOYCODE_BUTTON7 JOYCODE_BUTTON7_INDEXED(0)
+#define JOYCODE_BUTTON8 JOYCODE_BUTTON8_INDEXED(0)
+#define JOYCODE_BUTTON9 JOYCODE_BUTTON9_INDEXED(0)
+#define JOYCODE_BUTTON10 JOYCODE_BUTTON10_INDEXED(0)
+#define JOYCODE_BUTTON11 JOYCODE_BUTTON11_INDEXED(0)
+#define JOYCODE_BUTTON12 JOYCODE_BUTTON12_INDEXED(0)
+#define JOYCODE_BUTTON13 JOYCODE_BUTTON13_INDEXED(0)
+#define JOYCODE_BUTTON14 JOYCODE_BUTTON14_INDEXED(0)
+#define JOYCODE_BUTTON15 JOYCODE_BUTTON15_INDEXED(0)
+#define JOYCODE_BUTTON16 JOYCODE_BUTTON16_INDEXED(0)
+#define JOYCODE_BUTTON17 JOYCODE_BUTTON17_INDEXED(0)
+#define JOYCODE_BUTTON18 JOYCODE_BUTTON18_INDEXED(0)
+#define JOYCODE_BUTTON19 JOYCODE_BUTTON19_INDEXED(0)
+#define JOYCODE_BUTTON20 JOYCODE_BUTTON20_INDEXED(0)
+#define JOYCODE_BUTTON21 JOYCODE_BUTTON21_INDEXED(0)
+#define JOYCODE_BUTTON22 JOYCODE_BUTTON22_INDEXED(0)
+#define JOYCODE_BUTTON23 JOYCODE_BUTTON23_INDEXED(0)
+#define JOYCODE_BUTTON24 JOYCODE_BUTTON24_INDEXED(0)
+#define JOYCODE_BUTTON25 JOYCODE_BUTTON25_INDEXED(0)
+#define JOYCODE_BUTTON26 JOYCODE_BUTTON26_INDEXED(0)
+#define JOYCODE_BUTTON27 JOYCODE_BUTTON27_INDEXED(0)
+#define JOYCODE_BUTTON28 JOYCODE_BUTTON28_INDEXED(0)
+#define JOYCODE_BUTTON29 JOYCODE_BUTTON29_INDEXED(0)
+#define JOYCODE_BUTTON30 JOYCODE_BUTTON30_INDEXED(0)
+#define JOYCODE_BUTTON31 JOYCODE_BUTTON31_INDEXED(0)
+#define JOYCODE_BUTTON32 JOYCODE_BUTTON32_INDEXED(0)
+#define JOYCODE_START JOYCODE_START_INDEXED(0)
+#define JOYCODE_SELECT JOYCODE_SELECT_INDEXED(0)
+
+
+#endif // MAME_OSD_INTERFACE_INPUTCODE_H
diff --git a/src/osd/interface/inputman.h b/src/osd/interface/inputman.h
new file mode 100644
index 00000000000..223c9a6926d
--- /dev/null
+++ b/src/osd/interface/inputman.h
@@ -0,0 +1,77 @@
+// license:BSD-3-Clause
+// copyright-holders:Aaron Giles
+/***************************************************************************
+
+ inputman.h
+
+ OSD interface to the input manager.
+
+***************************************************************************/
+#ifndef MAME_OSD_INTERFACE_INPUTMAN_H
+#define MAME_OSD_INTERFACE_INPUTMAN_H
+
+#pragma once
+
+#include "inputcode.h"
+
+#include <string_view>
+
+
+namespace osd {
+
+//**************************************************************************
+// CONSTANTS
+//**************************************************************************
+
+// relative devices return ~512 units per on-screen pixel
+constexpr s32 INPUT_RELATIVE_PER_PIXEL = 512;
+
+// absolute devices return values between -65536 and +65536
+constexpr s32 INPUT_ABSOLUTE_MIN = -65'536;
+constexpr s32 INPUT_ABSOLUTE_MAX = 65'536;
+
+// invalid memory value for axis polling
+constexpr s32 INVALID_AXIS_VALUE = 0x7fff'ffff;
+
+
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// base for application representation of host input device
+
+class input_device
+{
+public:
+ // callback for getting the value of an individual input on a device
+ typedef s32 (*item_get_state_func)(void *device_internal, void *item_internal);
+
+ virtual ~input_device() = default;
+
+ virtual input_item_id add_item(
+ std::string_view name,
+ input_item_id itemid,
+ item_get_state_func getstate,
+ void *internal = nullptr) = 0;
+};
+
+
+// base for application input manager
+
+class input_manager
+{
+public:
+ virtual ~input_manager() = default;
+
+ virtual input_device &add_device(
+ input_device_class devclass,
+ std::string_view name,
+ std::string_view id,
+ void *internal = nullptr) = 0;
+};
+
+
+} // namespace osd
+
+#endif // MAME_OSD_INTERFACE_INPUTMAN_H
diff --git a/src/osd/interface/inputseq.cpp b/src/osd/interface/inputseq.cpp
new file mode 100644
index 00000000000..da1f2b98b26
--- /dev/null
+++ b/src/osd/interface/inputseq.cpp
@@ -0,0 +1,210 @@
+// license:BSD-3-Clause
+// copyright-holders:Aaron Giles
+/***************************************************************************
+
+ inputseq.cpp
+
+ A combination of hosts inputs that can be assigned to a control.
+
+***************************************************************************/
+
+#include "inputseq.h"
+
+
+namespace osd {
+
+//**************************************************************************
+// CONSTANTS
+//**************************************************************************
+
+// additional expanded input codes for sequences
+constexpr input_code input_seq::end_code;
+constexpr input_code input_seq::default_code;
+constexpr input_code input_seq::not_code;
+constexpr input_code input_seq::or_code;
+
+// constant sequences
+const input_seq input_seq::empty_seq;
+
+
+
+//**************************************************************************
+// INPUT SEQ
+//**************************************************************************
+
+//-------------------------------------------------
+// operator+= - append a code to the end of an
+// input sequence
+//-------------------------------------------------
+
+input_seq &input_seq::operator+=(input_code code) noexcept
+{
+ // if not enough room, return false
+ const int curlength = length();
+ if (curlength < m_code.size())
+ {
+ m_code[curlength] = code;
+ if ((curlength + 1) < m_code.size())
+ m_code[curlength + 1] = end_code;
+ }
+ return *this;
+}
+
+
+//-------------------------------------------------
+// operator|= - append a code to a sequence; if
+// the sequence is non-empty, insert an OR
+// before the new code
+//-------------------------------------------------
+
+input_seq &input_seq::operator|=(input_code code) noexcept
+{
+ // overwrite end/default with the new code
+ if (m_code[0] == default_code)
+ {
+ m_code[0] = code;
+ m_code[1] = end_code;
+ }
+ else
+ {
+ // otherwise, append an OR token and then the new code
+ const int curlength = length();
+ if ((curlength + 1) < m_code.size())
+ {
+ m_code[curlength] = or_code;
+ m_code[curlength + 1] = code;
+ if ((curlength + 2) < m_code.size())
+ m_code[curlength + 2] = end_code;
+ }
+ }
+ return *this;
+}
+
+
+//-------------------------------------------------
+// length - return the length of the sequence
+//-------------------------------------------------
+
+int input_seq::length() const noexcept
+{
+ // find the end token; error if none found
+ for (int seqnum = 0; seqnum < m_code.size(); seqnum++)
+ if (m_code[seqnum] == end_code)
+ return seqnum;
+ return m_code.size();
+}
+
+
+//-------------------------------------------------
+// is_valid - return true if a given sequence is
+// valid
+//-------------------------------------------------
+
+bool input_seq::is_valid() const noexcept
+{
+ // "default" can only be of length 1
+ if (m_code[0] == default_code)
+ return m_code[1] == end_code;
+
+ // scan the sequence for valid codes
+ input_item_class lastclass = ITEM_CLASS_INVALID;
+ input_code lastcode = INPUT_CODE_INVALID;
+ decltype(m_code) positive_codes;
+ decltype(m_code) negative_codes;
+ auto positive_codes_end = positive_codes.begin();
+ auto negative_codes_end = negative_codes.begin();
+ for (input_code code : m_code)
+ {
+ // invalid codes are never permitted
+ if (code == INPUT_CODE_INVALID)
+ return false;
+
+ // if we hit an OR or the end, validate the previous chunk
+ if (code == or_code || code == end_code)
+ {
+ // must be at least one positive code
+ if (positive_codes.begin() == positive_codes_end)
+ return false;
+
+ // last code must not have been an internal code
+ if (lastcode.internal())
+ return false;
+
+ // if this is the end, we're ok
+ if (code == end_code)
+ return true;
+
+ // reset the state for the next chunk
+ positive_codes_end = positive_codes.begin();
+ negative_codes_end = negative_codes.begin();
+ lastclass = ITEM_CLASS_INVALID;
+ }
+ else if (code == not_code)
+ {
+ // if we hit a NOT, make sure we don't have a double
+ if (lastcode == not_code)
+ return false;
+ }
+ else
+ {
+ // track positive codes, and don't allow positive and negative for the same code
+ if (lastcode != not_code)
+ {
+ *positive_codes_end++ = code;
+ if (std::find(negative_codes.begin(), negative_codes_end, code) != negative_codes_end)
+ return false;
+ }
+ else
+ {
+ *negative_codes_end++ = code;
+ if (std::find(positive_codes.begin(), positive_codes_end, code) != positive_codes_end)
+ return false;
+ }
+
+ // non-switch items can't have a NOT
+ input_item_class itemclass = code.item_class();
+ if (itemclass != ITEM_CLASS_SWITCH && lastcode == not_code)
+ return false;
+
+ // absolute/relative items must all be the same class
+ if ((lastclass == ITEM_CLASS_ABSOLUTE && itemclass != ITEM_CLASS_ABSOLUTE) ||
+ (lastclass == ITEM_CLASS_RELATIVE && itemclass != ITEM_CLASS_RELATIVE))
+ return false;
+ }
+
+ // remember the last code
+ lastcode = code;
+ }
+
+ // if we got here, we were missing an END token; fail
+ return false;
+}
+
+
+//-------------------------------------------------
+// backspace - "backspace" over the last entry in
+// a sequence
+//-------------------------------------------------
+
+void input_seq::backspace() noexcept
+{
+ // if we have at least one entry, remove it
+ const int curlength = length();
+ if (curlength > 0)
+ m_code[curlength - 1] = end_code;
+}
+
+
+//-------------------------------------------------
+// replace - replace all instances of oldcode
+// with newcode in a sequence
+//-------------------------------------------------
+
+void input_seq::replace(input_code oldcode, input_code newcode) noexcept
+{
+ for (input_code &elem : m_code)
+ if (elem == oldcode)
+ elem = newcode;
+}
+
+} // namespace osd
diff --git a/src/osd/interface/inputseq.h b/src/osd/interface/inputseq.h
new file mode 100644
index 00000000000..62704462d47
--- /dev/null
+++ b/src/osd/interface/inputseq.h
@@ -0,0 +1,107 @@
+// license:BSD-3-Clause
+// copyright-holders:Aaron Giles
+/***************************************************************************
+
+ inputseq.h
+
+ A combination of hosts inputs that can be assigned to a control.
+
+***************************************************************************/
+#ifndef MAME_OSD_INTERFACE_INPUTSEQ_H
+#define MAME_OSD_INTERFACE_INPUTSEQ_H
+
+#pragma once
+
+#include "inputcode.h"
+
+#include <algorithm>
+#include <array>
+#include <cassert>
+#include <utility>
+
+
+namespace osd {
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// a combination of input_codes, supporting AND/OR and inversion
+
+class input_seq
+{
+public:
+ // construction/destruction
+ input_seq() noexcept : input_seq(std::make_index_sequence<std::tuple_size<decltype(m_code)>::value>())
+ {
+ }
+ template <typename... T>
+ input_seq(input_code code_0, T... code_n) noexcept :
+ input_seq(std::make_index_sequence<std::tuple_size<decltype(m_code)>::value - sizeof...(T) - 1>(), code_0, code_n...)
+ {
+ }
+ constexpr input_seq(const input_seq &rhs) noexcept = default;
+
+ // operators
+ bool operator==(const input_seq &rhs) const noexcept { return m_code == rhs.m_code; }
+ bool operator!=(const input_seq &rhs) const noexcept { return m_code != rhs.m_code; }
+ constexpr input_code operator[](int index) const noexcept { return (index >= 0 && index < m_code.size()) ? m_code[index] : end_code; }
+ input_seq &operator+=(input_code code) noexcept;
+ input_seq &operator|=(input_code code) noexcept;
+
+ // getters
+ constexpr bool empty() const noexcept { return m_code[0] == end_code; }
+ constexpr int max_size() const noexcept { return std::tuple_size<decltype(m_code)>::value; }
+ int length() const noexcept;
+ bool is_valid() const noexcept;
+ constexpr bool is_default() const noexcept { return m_code[0] == default_code; }
+
+ // setters
+ template <typename... T> void set(input_code code_0, T... code_n) noexcept
+ {
+ static_assert(sizeof...(T) < std::tuple_size<decltype(m_code)>::value, "too many codes for input_seq");
+ set<0>(code_0, code_n...);
+ }
+ void reset() noexcept { set(end_code); }
+ void set_default() noexcept { set(default_code); }
+ void backspace() noexcept;
+ void replace(input_code oldcode, input_code newcode) noexcept;
+
+ // constant codes used in sequences
+ static constexpr input_code end_code { DEVICE_CLASS_INTERNAL, 0, ITEM_CLASS_INVALID, ITEM_MODIFIER_NONE, ITEM_ID_SEQ_END };
+ static constexpr input_code default_code { DEVICE_CLASS_INTERNAL, 0, ITEM_CLASS_INVALID, ITEM_MODIFIER_NONE, ITEM_ID_SEQ_DEFAULT };
+ static constexpr input_code not_code { DEVICE_CLASS_INTERNAL, 0, ITEM_CLASS_INVALID, ITEM_MODIFIER_NONE, ITEM_ID_SEQ_NOT };
+ static constexpr input_code or_code { DEVICE_CLASS_INTERNAL, 0, ITEM_CLASS_INVALID, ITEM_MODIFIER_NONE, ITEM_ID_SEQ_OR };
+
+ // constant sequences
+ static const input_seq empty_seq;
+
+private:
+ static constexpr input_code get_end_code(size_t) noexcept { return end_code; }
+
+ template <size_t... N, typename... T>
+ input_seq(std::integer_sequence<size_t, N...>, T... code) noexcept : m_code({ code..., get_end_code(N)... })
+ {
+ }
+ template <size_t... N>
+ input_seq(std::integer_sequence<size_t, N...>) noexcept : m_code({ get_end_code(N)... })
+ {
+ }
+
+ template <unsigned N> void set() noexcept
+ {
+ std::fill(std::next(m_code.begin(), N), m_code.end(), end_code);
+ }
+ template <unsigned N, typename... T> void set(input_code code_0, T... code_n) noexcept
+ {
+ m_code[N] = code_0;
+ set<N + 1>(code_n...);
+ }
+
+ // internal state
+ std::array<input_code, 16> m_code;
+};
+
+} // namespace osd
+
+#endif // MAME_OSD_INTERFACE_INPUTSEQ_H
diff --git a/src/osd/modules/input/input_common.cpp b/src/osd/modules/input/input_common.cpp
index bb596295ea9..7127a7878fa 100644
--- a/src/osd/modules/input/input_common.cpp
+++ b/src/osd/modules/input/input_common.cpp
@@ -14,6 +14,8 @@
#include "emu.h"
#include "input_common.h"
+#include "inputdev.h" // FIXME: still using concrete input device class in input_module_base::poll
+
// winnt.h defines this
#ifdef DELETE
#undef DELETE
@@ -277,3 +279,46 @@ int input_module_base::init(const osd_options &options)
return 0;
}
+
+void input_module_base::poll(running_machine &machine)
+{
+ // ignore if not enabled
+ if (m_input_enabled)
+ {
+ // grab the current time
+ m_last_poll = m_clock.now();
+
+ before_poll(machine);
+
+ // track if mouse/lightgun is enabled, for mouse hiding purposes
+ m_mouse_enabled = machine.input().device_class(DEVICE_CLASS_MOUSE).enabled();
+ m_lightgun_enabled = machine.input().device_class(DEVICE_CLASS_LIGHTGUN).enabled();
+ }
+
+ // poll all of the devices
+ if (should_poll_devices(machine))
+ {
+ m_devicelist.poll_devices();
+ }
+ else
+ {
+ m_devicelist.reset_devices();
+ }
+}
+
+void input_module_base::pause()
+{
+ // keep track of the paused state
+ m_input_paused = true;
+}
+
+void input_module_base::resume()
+{
+ // keep track of the paused state
+ m_input_paused = false;
+}
+
+void input_module_base::exit()
+{
+ devicelist().free_all_devices();
+}
diff --git a/src/osd/modules/input/input_common.h b/src/osd/modules/input/input_common.h
index c030d8f17b2..e220445c266 100644
--- a/src/osd/modules/input/input_common.h
+++ b/src/osd/modules/input/input_common.h
@@ -14,7 +14,7 @@
#include "input_module.h"
-#include "inputdev.h"
+#include "interface/inputman.h"
#include <algorithm>
#include <chrono>
@@ -204,7 +204,7 @@ class device_info
private:
const std::string m_name;
const std::string m_id;
- input_device * m_device;
+ osd::input_device * m_device;
running_machine & m_machine;
input_module & m_module;
input_device_class m_deviceclass;
@@ -228,7 +228,7 @@ public:
running_machine & machine() const { return m_machine; }
const std::string & name() const { return m_name; }
const std::string & id() const { return m_id; }
- input_device * device() const { return m_device; }
+ osd::input_device * device() const { return m_device; }
input_module & module() const { return m_module; }
input_device_class deviceclass() const { return m_deviceclass; }
@@ -255,8 +255,8 @@ protected:
virtual void process_event(TEvent &ev) = 0;
public:
- event_based_device(running_machine &machine, std::string &&name, std::string &&id, input_device_class deviceclass, input_module &module)
- : device_info(machine, std::move(name), std::move(id), deviceclass, module)
+ event_based_device(running_machine &machine, std::string &&name, std::string &&id, input_device_class deviceclass, input_module &module) :
+ device_info(machine, std::move(name), std::move(id), deviceclass, module)
{
}
@@ -338,14 +338,14 @@ public:
// allocate the device object
auto devinfo = std::make_unique<TActual>(machine, std::move(name), std::move(id), module, std::forward<TArgs>(args)...);
- return add_device(machine, std::move(devinfo));
+ return add_device(machine.input(), std::move(devinfo));
}
template <typename TActual>
- TActual &add_device(running_machine &machine, std::unique_ptr<TActual> &&devinfo)
+ TActual &add_device(osd::input_manager &manager, std::unique_ptr<TActual> &&devinfo)
{
// Add the device to the machine
- devinfo->m_device = &machine.input().device_class(devinfo->deviceclass()).add_device(devinfo->name(), devinfo->id(), devinfo.get());
+ devinfo->m_device = &manager.add_device(devinfo->deviceclass(), devinfo->name(), devinfo->id(), devinfo.get());
// append us to the list
return *static_cast<TActual *>(m_list.emplace_back(std::move(devinfo)).get());
@@ -453,9 +453,9 @@ public:
bool mouse_enabled() const { return m_mouse_enabled; }
bool lightgun_enabled() const { return m_lightgun_enabled; }
- int init(const osd_options &options) override;
+ virtual int init(const osd_options &options) override;
- void poll_if_necessary(running_machine &machine) override
+ virtual void poll_if_necessary(running_machine &machine) override
{
auto elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(m_clock.now() - m_last_poll);
if (elapsed.count() >= MIN_POLLING_INTERVAL)
@@ -464,51 +464,13 @@ public:
}
}
- virtual void poll(running_machine &machine)
- {
- // ignore if not enabled
- if (m_input_enabled)
- {
- // grab the current time
- m_last_poll = m_clock.now();
-
- before_poll(machine);
-
- // track if mouse/lightgun is enabled, for mouse hiding purposes
- m_mouse_enabled = machine.input().device_class(DEVICE_CLASS_MOUSE).enabled();
- m_lightgun_enabled = machine.input().device_class(DEVICE_CLASS_LIGHTGUN).enabled();
- }
-
- // poll all of the devices
- if (should_poll_devices(machine))
- {
- m_devicelist.poll_devices();
- }
- else
- {
- m_devicelist.reset_devices();
- }
- }
-
- virtual void pause() override
- {
- // keep track of the paused state
- m_input_paused = true;
- }
-
- virtual void resume() override
- {
- // keep track of the paused state
- m_input_paused = false;
- }
-
- virtual void exit() override
- {
- devicelist().free_all_devices();
- }
+ virtual void pause() override;
+ virtual void resume() override;
+ virtual void exit() override;
protected:
virtual int init_internal() { return 0; }
+ virtual void poll(running_machine &machine);
virtual bool should_poll_devices(running_machine &machine) = 0;
virtual void before_poll(running_machine &machine) { }
};
@@ -571,14 +533,14 @@ inline int32_t normalize_absolute_axis(double raw, double rawmin, double rawmax)
if (raw >= center)
{
// above center
- double result = (raw - center) * INPUT_ABSOLUTE_MAX / (rawmax - center);
- return std::min(result, (double)INPUT_ABSOLUTE_MAX);
+ double result = (raw - center) * osd::INPUT_ABSOLUTE_MAX / (rawmax - center);
+ return std::min(result, (double)osd::INPUT_ABSOLUTE_MAX);
}
else
{
// below center
- double result = -((center - raw) * (double)-INPUT_ABSOLUTE_MIN / (center - rawmin));
- return std::max(result, (double)INPUT_ABSOLUTE_MIN);
+ double result = -((center - raw) * (double)-osd::INPUT_ABSOLUTE_MIN / (center - rawmin));
+ return std::max(result, (double)osd::INPUT_ABSOLUTE_MIN);
}
}
diff --git a/src/osd/modules/input/input_dinput.cpp b/src/osd/modules/input/input_dinput.cpp
index fa273e5fdb1..77467f80d59 100644
--- a/src/osd/modules/input/input_dinput.cpp
+++ b/src/osd/modules/input/input_dinput.cpp
@@ -389,9 +389,9 @@ void dinput_mouse_device::poll()
dinput_device::poll_dinput(&mouse);
// scale the axis data
- mouse.lX *= INPUT_RELATIVE_PER_PIXEL;
- mouse.lY *= INPUT_RELATIVE_PER_PIXEL;
- mouse.lZ *= INPUT_RELATIVE_PER_PIXEL;
+ mouse.lX *= osd::INPUT_RELATIVE_PER_PIXEL;
+ mouse.lY *= osd::INPUT_RELATIVE_PER_PIXEL;
+ mouse.lZ *= osd::INPUT_RELATIVE_PER_PIXEL;
}
void dinput_mouse_device::reset()
diff --git a/src/osd/modules/input/input_rawinput.cpp b/src/osd/modules/input/input_rawinput.cpp
index 8547a967dab..94018f9c404 100644
--- a/src/osd/modules/input/input_rawinput.cpp
+++ b/src/osd/modules/input/input_rawinput.cpp
@@ -347,12 +347,12 @@ public:
if (rawinput.data.mouse.usFlags == MOUSE_MOVE_RELATIVE)
{
- mouse.lX += rawinput.data.mouse.lLastX * INPUT_RELATIVE_PER_PIXEL;
- mouse.lY += rawinput.data.mouse.lLastY * INPUT_RELATIVE_PER_PIXEL;
+ mouse.lX += rawinput.data.mouse.lLastX * osd::INPUT_RELATIVE_PER_PIXEL;
+ mouse.lY += rawinput.data.mouse.lLastY * osd::INPUT_RELATIVE_PER_PIXEL;
// update zaxis
if (rawinput.data.mouse.usButtonFlags & RI_MOUSE_WHEEL)
- mouse.lZ += static_cast<int16_t>(rawinput.data.mouse.usButtonData) * INPUT_RELATIVE_PER_PIXEL;
+ mouse.lZ += static_cast<int16_t>(rawinput.data.mouse.usButtonData) * osd::INPUT_RELATIVE_PER_PIXEL;
// update the button states; always update the corresponding mouse buttons
if (rawinput.data.mouse.usButtonFlags & RI_MOUSE_BUTTON_1_DOWN) mouse.rgbButtons[0] = 0x80;
@@ -405,12 +405,12 @@ public:
{
// update the X/Y positions
- lightgun.lX = normalize_absolute_axis(rawinput.data.mouse.lLastX, 0, INPUT_ABSOLUTE_MAX);
- lightgun.lY = normalize_absolute_axis(rawinput.data.mouse.lLastY, 0, INPUT_ABSOLUTE_MAX);
+ lightgun.lX = normalize_absolute_axis(rawinput.data.mouse.lLastX, 0, osd::INPUT_ABSOLUTE_MAX);
+ lightgun.lY = normalize_absolute_axis(rawinput.data.mouse.lLastY, 0, osd::INPUT_ABSOLUTE_MAX);
// update zaxis
if (rawinput.data.mouse.usButtonFlags & RI_MOUSE_WHEEL)
- lightgun.lZ += static_cast<int16_t>(rawinput.data.mouse.usButtonData) * INPUT_RELATIVE_PER_PIXEL;
+ lightgun.lZ += static_cast<int16_t>(rawinput.data.mouse.usButtonData) * osd::INPUT_RELATIVE_PER_PIXEL;
// update the button states; always update the corresponding mouse buttons
if (rawinput.data.mouse.usButtonFlags & RI_MOUSE_BUTTON_1_DOWN) lightgun.rgbButtons[0] = 0x80;
diff --git a/src/osd/modules/input/input_sdl.cpp b/src/osd/modules/input/input_sdl.cpp
index 73d722525fa..76f8c494f70 100644
--- a/src/osd/modules/input/input_sdl.cpp
+++ b/src/osd/modules/input/input_sdl.cpp
@@ -526,8 +526,8 @@ public:
switch (sdlevent.type)
{
case SDL_MOUSEMOTION:
- mouse.lX += sdlevent.motion.xrel * INPUT_RELATIVE_PER_PIXEL;
- mouse.lY += sdlevent.motion.yrel * INPUT_RELATIVE_PER_PIXEL;
+ mouse.lX += sdlevent.motion.xrel * osd::INPUT_RELATIVE_PER_PIXEL;
+ mouse.lY += sdlevent.motion.yrel * osd::INPUT_RELATIVE_PER_PIXEL;
{
int cx = -1, cy = -1;
@@ -676,8 +676,8 @@ public:
case SDL_JOYBALLMOTION:
//printf("Ball %d %d\n", sdlevent.jball.xrel, sdlevent.jball.yrel);
- joystick.balls[sdlevent.jball.ball * 2] = sdlevent.jball.xrel * INPUT_RELATIVE_PER_PIXEL;
- joystick.balls[sdlevent.jball.ball * 2 + 1] = sdlevent.jball.yrel * INPUT_RELATIVE_PER_PIXEL;
+ joystick.balls[sdlevent.jball.ball * 2] = sdlevent.jball.xrel * osd::INPUT_RELATIVE_PER_PIXEL;
+ joystick.balls[sdlevent.jball.ball * 2 + 1] = sdlevent.jball.yrel * osd::INPUT_RELATIVE_PER_PIXEL;
break;
case SDL_JOYHATMOTION:
diff --git a/src/osd/modules/input/input_win32.cpp b/src/osd/modules/input/input_win32.cpp
index 17128d7c0d6..459e624fcfa 100644
--- a/src/osd/modules/input/input_win32.cpp
+++ b/src/osd/modules/input/input_win32.cpp
@@ -149,8 +149,8 @@ public:
if (!(cursor_info.flags & CURSOR_SHOWING))
{
// We measure the position change from the previously set center position
- mouse.lX = (cursor_info.ptScreenPos.x - win32_mouse.last_point.x) * INPUT_RELATIVE_PER_PIXEL;
- mouse.lY = (cursor_info.ptScreenPos.y - win32_mouse.last_point.y) * INPUT_RELATIVE_PER_PIXEL;
+ mouse.lX = (cursor_info.ptScreenPos.x - win32_mouse.last_point.x) * osd::INPUT_RELATIVE_PER_PIXEL;
+ mouse.lY = (cursor_info.ptScreenPos.y - win32_mouse.last_point.y) * osd::INPUT_RELATIVE_PER_PIXEL;
RECT window_pos = {0};
GetWindowRect(std::static_pointer_cast<win_window_info>(osd_common_t::s_window_list.front())->platform_window(), &window_pos);
diff --git a/src/osd/osdcomm.h b/src/osd/osdcomm.h
index 0b372e4e61e..516dd3e681a 100644
--- a/src/osd/osdcomm.h
+++ b/src/osd/osdcomm.h
@@ -71,6 +71,7 @@ using s64 = std::int64_t;
} // namespace OSD
+
/***************************************************************************
FUNDAMENTAL MACROS
***************************************************************************/
@@ -111,4 +112,25 @@ using ssize_t = std::make_signed_t<size_t>;
#endif
#endif
+
+// macro for defining a copy constructor and assignment operator to prevent copying
+#define DISABLE_COPYING(TYPE) \
+ TYPE(const TYPE &) = delete; \
+ TYPE &operator=(const TYPE &) = delete
+
+// macro for declaring enumeration operators that increment/decrement like plain old C
+#define DECLARE_ENUM_INCDEC_OPERATORS(TYPE) \
+inline TYPE &operator++(TYPE &value) { return value = TYPE(std::underlying_type_t<TYPE>(value) + 1); } \
+inline TYPE &operator--(TYPE &value) { return value = TYPE(std::underlying_type_t<TYPE>(value) - 1); } \
+inline TYPE operator++(TYPE &value, int) { TYPE const old(value); ++value; return old; } \
+inline TYPE operator--(TYPE &value, int) { TYPE const old(value); --value; return old; }
+
+// macro for declaring bitwise operators for an enumerated type
+#define DECLARE_ENUM_BITWISE_OPERATORS(TYPE) \
+constexpr TYPE operator~(TYPE value) { return TYPE(~std::underlying_type_t<TYPE>(value)); } \
+constexpr TYPE operator&(TYPE a, TYPE b) { return TYPE(std::underlying_type_t<TYPE>(a) & std::underlying_type_t<TYPE>(b)); } \
+constexpr TYPE operator|(TYPE a, TYPE b) { return TYPE(std::underlying_type_t<TYPE>(a) | std::underlying_type_t<TYPE>(b)); } \
+inline TYPE &operator&=(TYPE &a, TYPE b) { return a = a & b; } \
+inline TYPE &operator|=(TYPE &a, TYPE b) { return a = a | b; }
+
#endif // MAME_OSD_OSDCOMM_H