Merge input modules work.

This commit is contained in:
Brad Hughes 2016-02-28 14:56:54 -05:00
commit f68ad66131
30 changed files with 5131 additions and 4477 deletions

View File

@ -69,6 +69,19 @@ function osdmodulesbuild()
MAME_DIR .. "src/osd/modules/sound/sdl_sound.cpp",
MAME_DIR .. "src/osd/modules/sound/xaudio2_sound.cpp",
MAME_DIR .. "src/osd/modules/sound/none.cpp",
MAME_DIR .. "src/osd/modules/input/input_module.h",
MAME_DIR .. "src/osd/modules/input/input_common.cpp",
MAME_DIR .. "src/osd/modules/input/input_common.h",
MAME_DIR .. "src/osd/modules/input/input_dinput.cpp",
MAME_DIR .. "src/osd/modules/input/input_none.cpp",
MAME_DIR .. "src/osd/modules/input/input_rawinput.cpp",
MAME_DIR .. "src/osd/modules/input/input_win32.cpp",
MAME_DIR .. "src/osd/modules/input/input_sdl.cpp",
MAME_DIR .. "src/osd/modules/input/input_sdlcommon.cpp",
MAME_DIR .. "src/osd/modules/input/input_sdlcommon.h",
MAME_DIR .. "src/osd/modules/input/input_x11.cpp",
MAME_DIR .. "src/osd/modules/input/input_windows.cpp",
MAME_DIR .. "src/osd/modules/input/input_windows.h",
}
if _OPTIONS["targetos"]=="windows" then

View File

@ -425,8 +425,6 @@ project ("osd_" .. _OPTIONS["osd"])
MAME_DIR .. "src/osd/sdl/sdlprefix.h",
MAME_DIR .. "src/osd/sdl/sdlmain.cpp",
MAME_DIR .. "src/osd/osdepend.h",
MAME_DIR .. "src/osd/sdl/input.cpp",
MAME_DIR .. "src/osd/sdl/input.h",
MAME_DIR .. "src/osd/sdl/video.cpp",
MAME_DIR .. "src/osd/sdl/video.h",
MAME_DIR .. "src/osd/sdl/window.cpp",

View File

@ -163,7 +163,6 @@ project ("osd_" .. _OPTIONS["osd"])
MAME_DIR .. "src/osd/modules/render/drawgdi.h",
MAME_DIR .. "src/osd/modules/render/drawnone.cpp",
MAME_DIR .. "src/osd/modules/render/drawnone.h",
MAME_DIR .. "src/osd/windows/input.cpp",
MAME_DIR .. "src/osd/windows/input.h",
MAME_DIR .. "src/osd/windows/output.cpp",
MAME_DIR .. "src/osd/windows/output.h",

View File

@ -25,7 +25,8 @@
#include "debugger.h"
#include "window.h"
#include "../../windows/input.h"
#include "../input/input_common.h"
#include "../input/input_windows.h"
class debugger_windows : public osd_module, public debug_module, protected debugger_windows_interface
@ -121,7 +122,7 @@ void debugger_windows::wait_for_debugger(device_t &device, bool firststop)
show_all();
// run input polling to ensure that our status is in sync
wininput_poll(*m_machine);
downcast<windows_osd_interface&>(machine().osd()).poll_input(*m_machine);
// get and process messages
MSG message;
@ -202,7 +203,7 @@ bool debugger_windows::seq_pressed() const
else
{
// handle everything else as a series of ANDs
int const vkey = wininput_vkey_for_mame_code(code);
int const vkey = keyboard_trans_table::instance().vkey_for_mame_code(code);
bool const pressed = (vkey != 0) && ((GetAsyncKeyState(vkey) & 0x8000) != 0);
if (first) // if this is the first in the sequence, result is set equal

View File

@ -0,0 +1,266 @@
// license:BSD-3-Clause
// copyright-holders:Olivier Galibert, R. Belmont, Brad Hughes
//============================================================
//
// input_common.cpp - Common code for all MAME input modules
//
// SDLMAME by Olivier Galibert and R. Belmont
//
//============================================================
#include "input_module.h"
#include "modules/osdmodule.h"
#include "modules/lib/osdobj_common.h"
#include <mutex>
#include <memory>
// MAME headers
#include "emu.h"
// winnt.h defines this
#ifdef DELETE
#undef DELETE
#endif
#include "input_common.h"
//============================================================
// Keyboard translation table
//============================================================
#if defined(OSD_WINDOWS)
#include <windows.h>
#define KEY_TRANS_ENTRY0(mame, sdlsc, sdlkey, disc, virtual, ascii, UI) { ITEM_ID_##mame, KEY_ ## disc, virtual, ascii, "ITEM_ID_"#mame, (char *) UI }
#define KEY_TRANS_ENTRY1(mame, sdlsc, sdlkey, disc, virtual, ascii) { ITEM_ID_##mame, KEY_ ## disc, virtual, ascii, "ITEM_ID_"#mame, (char*) #mame }
#else
// SDL include
#include <sdlinc.h>
#define KEY_TRANS_ENTRY0(mame, sdlsc, sdlkey, disc, virtual, ascii, UI) { ITEM_ID_##mame, SDL_SCANCODE_ ## sdlsc, SDLK_ ## sdlkey, ascii, "ITEM_ID_"#mame, (char *) UI }
#define KEY_TRANS_ENTRY1(mame, sdlsc, sdlkey, disc, virtual, ascii) { ITEM_ID_##mame, SDL_SCANCODE_ ## sdlsc, SDLK_ ## sdlkey, ascii, "ITEM_ID_"#mame, (char*) #mame }
#endif
key_trans_entry keyboard_trans_table::s_default_table[] =
{
// MAME key sdl scancode sdl key di scancode virtual key ascii ui
KEY_TRANS_ENTRY0(ESC, ESCAPE, ESCAPE, ESCAPE, VK_ESCAPE, 27, "ESCAPE"),
KEY_TRANS_ENTRY1(1, 1, 1, 1, '1', '1'),
KEY_TRANS_ENTRY1(2, 2, 2, 2, '2', '2'),
KEY_TRANS_ENTRY1(3, 3, 3, 3, '3', '3'),
KEY_TRANS_ENTRY1(4, 4, 4, 4, '4', '4'),
KEY_TRANS_ENTRY1(5, 5, 5, 5, '5', '5'),
KEY_TRANS_ENTRY1(6, 6, 6, 6, '6', '6'),
KEY_TRANS_ENTRY1(7, 7, 7, 7, '7', '7'),
KEY_TRANS_ENTRY1(8, 8, 8, 8, '8', '8'),
KEY_TRANS_ENTRY1(9, 9, 9, 9, '9', '9'),
KEY_TRANS_ENTRY1(0, 0, 0, 0, '0', '0'),
KEY_TRANS_ENTRY1(MINUS, MINUS, MINUS, MINUS, VK_OEM_MINUS, '-'),
KEY_TRANS_ENTRY1(EQUALS, EQUALS, EQUALS, EQUALS, VK_OEM_PLUS, '='),
KEY_TRANS_ENTRY1(BACKSPACE, BACKSPACE, BACKSPACE, BACK, VK_BACK, 8),
KEY_TRANS_ENTRY1(TAB, TAB, TAB, TAB, VK_TAB, 9),
KEY_TRANS_ENTRY1(Q, Q, q, Q, 'Q', 'Q'),
KEY_TRANS_ENTRY1(W, W, w, W, 'W', 'W'),
KEY_TRANS_ENTRY1(E, E, e, E, 'E', 'E'),
KEY_TRANS_ENTRY1(R, R, r, R, 'R', 'R'),
KEY_TRANS_ENTRY1(T, T, t, T, 'T', 'T'),
KEY_TRANS_ENTRY1(Y, Y, y, Y, 'Y', 'Y'),
KEY_TRANS_ENTRY1(U, U, u, U, 'U', 'U'),
KEY_TRANS_ENTRY1(I, I, i, I, 'I', 'I'),
KEY_TRANS_ENTRY1(O, O, o, O, 'O', 'O'),
KEY_TRANS_ENTRY1(P, P, p, P, 'P', 'P'),
KEY_TRANS_ENTRY1(OPENBRACE, LEFTBRACKET, LEFTBRACKET, LBRACKET, VK_OEM_4, '['),
KEY_TRANS_ENTRY1(CLOSEBRACE, RIGHTBRACKET, RIGHTBRACKET, RBRACKET, VK_OEM_6, ']'),
KEY_TRANS_ENTRY0(ENTER, RETURN, RETURN, RETURN, VK_RETURN, 13, "RETURN"),
KEY_TRANS_ENTRY1(LCONTROL, LCTRL, LCTRL, LCONTROL, VK_LCONTROL, 0),
KEY_TRANS_ENTRY1(A, A, a, A, 'A', 'A'),
KEY_TRANS_ENTRY1(S, S, s, S, 'S', 'S'),
KEY_TRANS_ENTRY1(D, D, d, D, 'D', 'D'),
KEY_TRANS_ENTRY1(F, F, f, F, 'F', 'F'),
KEY_TRANS_ENTRY1(G, G, g, G, 'G', 'G'),
KEY_TRANS_ENTRY1(H, H, h, H, 'H', 'H'),
KEY_TRANS_ENTRY1(J, J, j, J, 'J', 'J'),
KEY_TRANS_ENTRY1(K, K, k, K, 'K', 'K'),
KEY_TRANS_ENTRY1(L, L, l, L, 'L', 'L'),
KEY_TRANS_ENTRY1(COLON, SEMICOLON, SEMICOLON, SEMICOLON, VK_OEM_1, ';'),
KEY_TRANS_ENTRY1(QUOTE, APOSTROPHE, QUOTE, APOSTROPHE, VK_OEM_7, '\''),
KEY_TRANS_ENTRY1(TILDE, GRAVE, BACKQUOTE, GRAVE, VK_OEM_3, '`'),
KEY_TRANS_ENTRY1(LSHIFT, LSHIFT, LSHIFT, LSHIFT, VK_LSHIFT, 0),
KEY_TRANS_ENTRY1(BACKSLASH, BACKSLASH, BACKSLASH, BACKSLASH, VK_OEM_5, '\\'),
KEY_TRANS_ENTRY1(BACKSLASH2, 0, 0, OEM_102, VK_OEM_102, '<'),
KEY_TRANS_ENTRY1(Z, Z, z, Z, 'Z', 'Z'),
KEY_TRANS_ENTRY1(X, X, x, X, 'X', 'X'),
KEY_TRANS_ENTRY1(C, C, c, C, 'C', 'C'),
KEY_TRANS_ENTRY1(V, V, v, V, 'V', 'V'),
KEY_TRANS_ENTRY1(B, B, b, B, 'B', 'B'),
KEY_TRANS_ENTRY1(N, N, n, N, 'N', 'N'),
KEY_TRANS_ENTRY1(M, M, m, M, 'M', 'M'),
KEY_TRANS_ENTRY1(COMMA, COMMA, COMMA, COMMA, VK_OEM_COMMA, ','),
KEY_TRANS_ENTRY1(STOP, PERIOD, PERIOD, PERIOD, VK_OEM_PERIOD, '.'),
KEY_TRANS_ENTRY1(SLASH, SLASH, SLASH, SLASH, VK_OEM_2, '/'),
KEY_TRANS_ENTRY1(RSHIFT, RSHIFT, RSHIFT, RSHIFT, VK_RSHIFT, 0),
KEY_TRANS_ENTRY1(ASTERISK, KP_MULTIPLY, KP_MULTIPLY, MULTIPLY, VK_MULTIPLY, '*'),
KEY_TRANS_ENTRY1(LALT, LALT, LALT, LMENU, VK_LMENU, 0),
KEY_TRANS_ENTRY1(SPACE, SPACE, SPACE, SPACE, VK_SPACE, ' '),
KEY_TRANS_ENTRY1(CAPSLOCK, CAPSLOCK, CAPSLOCK, CAPITAL, VK_CAPITAL, 0),
KEY_TRANS_ENTRY1(F1, F1, F1, F1, VK_F1, 0),
KEY_TRANS_ENTRY1(F2, F2, F2, F2, VK_F2, 0),
KEY_TRANS_ENTRY1(F3, F3, F3, F3, VK_F3, 0),
KEY_TRANS_ENTRY1(F4, F4, F4, F4, VK_F4, 0),
KEY_TRANS_ENTRY1(F5, F5, F5, F5, VK_F5, 0),
KEY_TRANS_ENTRY1(F6, F6, F6, F6, VK_F6, 0),
KEY_TRANS_ENTRY1(F7, F7, F7, F7, VK_F7, 0),
KEY_TRANS_ENTRY1(F8, F8, F8, F8, VK_F8, 0),
KEY_TRANS_ENTRY1(F9, F9, F9, F9, VK_F9, 0),
KEY_TRANS_ENTRY1(F10, F10, F10, F10, VK_F10, 0),
KEY_TRANS_ENTRY1(NUMLOCK, NUMLOCKCLEAR, NUMLOCKCLEAR, NUMLOCK, VK_NUMLOCK, 0),
KEY_TRANS_ENTRY1(SCRLOCK, SCROLLLOCK, SCROLLLOCK, SCROLL, VK_SCROLL, 0),
KEY_TRANS_ENTRY1(7_PAD, KP_7, KP_7, NUMPAD7, VK_NUMPAD7, 0),
KEY_TRANS_ENTRY1(8_PAD, KP_8, KP_8, NUMPAD8, VK_NUMPAD8, 0),
KEY_TRANS_ENTRY1(9_PAD, KP_9, KP_9, NUMPAD9, VK_NUMPAD9, 0),
KEY_TRANS_ENTRY1(MINUS_PAD, KP_MINUS, KP_MINUS, SUBTRACT, VK_SUBTRACT, 0),
KEY_TRANS_ENTRY1(4_PAD, KP_4, KP_4, NUMPAD4, VK_NUMPAD4, 0),
KEY_TRANS_ENTRY1(5_PAD, KP_5, KP_5, NUMPAD5, VK_NUMPAD5, 0),
KEY_TRANS_ENTRY1(6_PAD, KP_6, KP_6, NUMPAD6, VK_NUMPAD6, 0),
KEY_TRANS_ENTRY1(PLUS_PAD, KP_PLUS, KP_PLUS, ADD, VK_ADD, 0),
KEY_TRANS_ENTRY1(1_PAD, KP_1, KP_1, NUMPAD1, VK_NUMPAD1, 0),
KEY_TRANS_ENTRY1(2_PAD, KP_2, KP_2, NUMPAD2, VK_NUMPAD2, 0),
KEY_TRANS_ENTRY1(3_PAD, KP_3, KP_3, NUMPAD3, VK_NUMPAD3, 0),
KEY_TRANS_ENTRY1(0_PAD, KP_0, KP_0, NUMPAD0, VK_NUMPAD0, 0),
KEY_TRANS_ENTRY1(DEL_PAD, KP_PERIOD, KP_PERIOD, DECIMAL, VK_DECIMAL, 0),
KEY_TRANS_ENTRY1(F11, F11, F11, F11, VK_F11, 0),
KEY_TRANS_ENTRY1(F12, F12, F12, F12, VK_F12, 0),
KEY_TRANS_ENTRY1(F13, F13, F13, F13, VK_F13, 0),
KEY_TRANS_ENTRY1(F14, F14, F14, F14, VK_F14, 0),
KEY_TRANS_ENTRY1(F15, F15, F15, F15, VK_F15, 0),
KEY_TRANS_ENTRY1(ENTER_PAD, KP_ENTER, KP_ENTER, NUMPADENTER, VK_RETURN, 0),
KEY_TRANS_ENTRY1(RCONTROL, RCTRL, RCTRL, RCONTROL, VK_RCONTROL, 0),
KEY_TRANS_ENTRY1(SLASH_PAD, KP_DIVIDE, KP_DIVIDE, DIVIDE, VK_DIVIDE, 0),
KEY_TRANS_ENTRY1(PRTSCR, PRINTSCREEN, PRINTSCREEN, SYSRQ, 0, 0),
KEY_TRANS_ENTRY1(RALT, RALT, RALT, RMENU, VK_RMENU, 0),
KEY_TRANS_ENTRY1(HOME, HOME, HOME, HOME, VK_HOME, 0),
KEY_TRANS_ENTRY1(UP, UP, UP, UP, VK_UP, 0),
KEY_TRANS_ENTRY1(PGUP, PAGEUP, PAGEUP, PRIOR, VK_PRIOR, 0),
KEY_TRANS_ENTRY1(LEFT, LEFT, LEFT, LEFT, VK_LEFT, 0),
KEY_TRANS_ENTRY1(RIGHT, RIGHT, RIGHT, RIGHT, VK_RIGHT, 0),
KEY_TRANS_ENTRY1(END, END, END, END, VK_END, 0),
KEY_TRANS_ENTRY1(DOWN, DOWN, DOWN, DOWN, VK_DOWN, 0),
KEY_TRANS_ENTRY1(PGDN, PAGEDOWN, PAGEDOWN, NEXT, VK_NEXT, 0),
KEY_TRANS_ENTRY1(INSERT, INSERT, INSERT, INSERT, VK_INSERT, 0),
KEY_TRANS_ENTRY0(DEL, DELETE, DELETE, DELETE, VK_DELETE, 0, "DELETE"),
KEY_TRANS_ENTRY1(LWIN, LGUI, LGUI, LWIN, VK_LWIN, 0),
KEY_TRANS_ENTRY1(RWIN, RGUI, RGUI, RWIN, VK_RWIN, 0),
KEY_TRANS_ENTRY1(MENU, MENU, MENU, APPS, VK_APPS, 0),
KEY_TRANS_ENTRY1(PAUSE, PAUSE, PAUSE, PAUSE, VK_PAUSE, 0),
KEY_TRANS_ENTRY0(CANCEL, UNKNOWN, UNKNOWN, UNKNOWN, 0, 0, "CANCEL"),
// New keys introduced in Windows 2000. These have no MAME codes to
// preserve compatibility with old config files that may refer to them
// as e.g. FORWARD instead of e.g. KEYCODE_WEBFORWARD. They need table
// entries anyway because otherwise they aren't recognized when
// GetAsyncKeyState polling is used (as happens currently when MAME is
// paused). Some codes are missing because the mapping to vkey codes
// isn't clear, and MapVirtualKey is no help.
KEY_TRANS_ENTRY1(OTHER_SWITCH, MUTE, MUTE, MUTE, VK_VOLUME_MUTE, 0),
KEY_TRANS_ENTRY1(OTHER_SWITCH, VOLUMEDOWN, VOLUMEDOWN, VOLUMEDOWN, VK_VOLUME_DOWN, 0),
KEY_TRANS_ENTRY1(OTHER_SWITCH, VOLUMEUP, VOLUMEUP, VOLUMEUP, VK_VOLUME_UP, 0),
KEY_TRANS_ENTRY1(OTHER_SWITCH, AC_HOME, AC_HOME, WEBHOME, VK_BROWSER_HOME, 0),
KEY_TRANS_ENTRY1(OTHER_SWITCH, AC_SEARCH, AC_SEARCH, WEBSEARCH, VK_BROWSER_SEARCH, 0),
KEY_TRANS_ENTRY1(OTHER_SWITCH, AC_BOOKMARKS, AC_BOOKMARKS, WEBFAVORITES, VK_BROWSER_FAVORITES, 0),
KEY_TRANS_ENTRY1(OTHER_SWITCH, AC_REFRESH, AC_REFRESH, WEBREFRESH, VK_BROWSER_REFRESH, 0),
KEY_TRANS_ENTRY1(OTHER_SWITCH, AC_STOP, AC_STOP, WEBSTOP, VK_BROWSER_STOP, 0),
KEY_TRANS_ENTRY1(OTHER_SWITCH, AC_FORWARD, AC_FORWARD, WEBFORWARD, VK_BROWSER_FORWARD, 0),
KEY_TRANS_ENTRY1(OTHER_SWITCH, AC_BACK, AC_BACK, WEBBACK, VK_BROWSER_BACK, 0),
KEY_TRANS_ENTRY1(OTHER_SWITCH, MAIL, MAIL, MAIL, VK_LAUNCH_MAIL, 0),
KEY_TRANS_ENTRY1(OTHER_SWITCH, MEDIASELECT, MEDIASELECT, MEDIASELECT, VK_LAUNCH_MEDIA_SELECT, 0),
KEY_TRANS_ENTRY0(INVALID, UNKNOWN, UNKNOWN, ESCAPE, 0, 0, "INVALID")
};
// The private constructor to create the default instance
keyboard_trans_table::keyboard_trans_table()
{
m_table = s_default_table;
m_table_size = ARRAY_LENGTH(s_default_table);
}
// public constructor to allow creation of non-default instances
keyboard_trans_table::keyboard_trans_table(std::unique_ptr<key_trans_entry[]> entries, unsigned int size)
{
m_custom_table = std::move(entries);
m_table = m_custom_table.get();
m_table_size = size;
}
int keyboard_trans_table::lookup_mame_index(const char *scode)
{
for (int i = 0; i < m_table_size; i++)
{
if (!strcmp(scode, m_table[i].mame_key_name))
return i;
}
return -1;
}
input_item_id keyboard_trans_table::lookup_mame_code(const char *scode)
{
int const index = lookup_mame_index(scode);
if (index >= 0)
return m_table[index].mame_key;
else
return ITEM_ID_INVALID;
}
// Windows specific lookup methods
#if defined(OSD_WINDOWS)
input_item_id keyboard_trans_table::map_di_scancode_to_itemid(int scancode)
{
int tablenum;
// scan the table for a match
for (tablenum = 0; tablenum < m_table_size; tablenum++)
if (m_table[tablenum].scan_code == scancode)
return m_table[tablenum].mame_key;
// default to an "other" switch
return ITEM_ID_OTHER_SWITCH;
}
//============================================================
// wininput_vkey_for_mame_code
//============================================================
int keyboard_trans_table::vkey_for_mame_code(input_code code)
{
// only works for keyboard switches
if (code.device_class() == DEVICE_CLASS_KEYBOARD && code.item_class() == ITEM_CLASS_SWITCH)
{
input_item_id id = code.item_id();
int tablenum;
// scan the table for a match
for (tablenum = 0; tablenum < m_table_size; tablenum++)
if (m_table[tablenum].mame_key == id)
return m_table[tablenum].virtual_key;
}
return 0;
}
#endif
int input_module_base::init(const osd_options &options)
{
m_options = &options;
m_mouse_enabled = options.mouse();
m_lightgun_enabled = options.lightgun();
int result = init_internal();
if (result != 0)
return result;
m_input_paused = false;
m_input_enabled = true;
return 0;
}

View File

@ -0,0 +1,605 @@
// license:BSD-3-Clause
// copyright-holders:Olivier Galibert, R. Belmont, Brad Hughes
//============================================================
//
// input_common.h - Common code for all MAME input modules
//
// SDLMAME by Olivier Galibert and R. Belmont
//
//============================================================
#ifndef INPUT_COMMON_H_
#define INPUT_COMMON_H_
#include <memory>
#include <chrono>
#include <string>
#include <queue>
//============================================================
// PARAMETERS
//============================================================
enum
{
POVDIR_LEFT = 0,
POVDIR_RIGHT,
POVDIR_UP,
POVDIR_DOWN
};
#define MAX_KEYS 256
#define MAX_AXES 32
#define MAX_BUTTONS 32
#define MAX_HATS 8
#define MAX_POV 4
/****************************************************************************
* DirectInput compatible keyboard scan codes
****************************************************************************/
#define KEY_UNKNOWN 0x00
#define KEY_ESCAPE 0x01
#define KEY_1 0x02
#define KEY_2 0x03
#define KEY_3 0x04
#define KEY_4 0x05
#define KEY_5 0x06
#define KEY_6 0x07
#define KEY_7 0x08
#define KEY_8 0x09
#define KEY_9 0x0A
#define KEY_0 0x0B
#define KEY_MINUS 0x0C /* - on main keyboard */
#define KEY_EQUALS 0x0D
#define KEY_BACK 0x0E /* backspace */
#define KEY_TAB 0x0F
#define KEY_Q 0x10
#define KEY_W 0x11
#define KEY_E 0x12
#define KEY_R 0x13
#define KEY_T 0x14
#define KEY_Y 0x15
#define KEY_U 0x16
#define KEY_I 0x17
#define KEY_O 0x18
#define KEY_P 0x19
#define KEY_LBRACKET 0x1A
#define KEY_RBRACKET 0x1B
#define KEY_RETURN 0x1C /* Enter on main keyboard */
#define KEY_LCONTROL 0x1D
#define KEY_A 0x1E
#define KEY_S 0x1F
#define KEY_D 0x20
#define KEY_F 0x21
#define KEY_G 0x22
#define KEY_H 0x23
#define KEY_J 0x24
#define KEY_K 0x25
#define KEY_L 0x26
#define KEY_SEMICOLON 0x27
#define KEY_APOSTROPHE 0x28
#define KEY_GRAVE 0x29 /* accent grave */
#define KEY_LSHIFT 0x2A
#define KEY_BACKSLASH 0x2B
#define KEY_Z 0x2C
#define KEY_X 0x2D
#define KEY_C 0x2E
#define KEY_V 0x2F
#define KEY_B 0x30
#define KEY_N 0x31
#define KEY_M 0x32
#define KEY_COMMA 0x33
#define KEY_PERIOD 0x34 /* . on main keyboard */
#define KEY_SLASH 0x35 /* / on main keyboard */
#define KEY_RSHIFT 0x36
#define KEY_MULTIPLY 0x37 /* * on numeric keypad */
#define KEY_LMENU 0x38 /* left Alt */
#define KEY_SPACE 0x39
#define KEY_CAPITAL 0x3A
#define KEY_F1 0x3B
#define KEY_F2 0x3C
#define KEY_F3 0x3D
#define KEY_F4 0x3E
#define KEY_F5 0x3F
#define KEY_F6 0x40
#define KEY_F7 0x41
#define KEY_F8 0x42
#define KEY_F9 0x43
#define KEY_F10 0x44
#define KEY_NUMLOCK 0x45
#define KEY_SCROLL 0x46 /* Scroll Lock */
#define KEY_NUMPAD7 0x47
#define KEY_NUMPAD8 0x48
#define KEY_NUMPAD9 0x49
#define KEY_SUBTRACT 0x4A /* - on numeric keypad */
#define KEY_NUMPAD4 0x4B
#define KEY_NUMPAD5 0x4C
#define KEY_NUMPAD6 0x4D
#define KEY_ADD 0x4E /* + on numeric keypad */
#define KEY_NUMPAD1 0x4F
#define KEY_NUMPAD2 0x50
#define KEY_NUMPAD3 0x51
#define KEY_NUMPAD0 0x52
#define KEY_DECIMAL 0x53 /* . on numeric keypad */
#define KEY_OEM_102 0x56 /* <> or \| on RT 102-key keyboard (Non-U.S.) */
#define KEY_F11 0x57
#define KEY_F12 0x58
#define KEY_F13 0x64 /* (NEC PC98) */
#define KEY_F14 0x65 /* (NEC PC98) */
#define KEY_F15 0x66 /* (NEC PC98) */
#define KEY_KANA 0x70 /* (Japanese keyboard) */
#define KEY_ABNT_C1 0x73 /* /? on Brazilian keyboard */
#define KEY_CONVERT 0x79 /* (Japanese keyboard) */
#define KEY_NOCONVERT 0x7B /* (Japanese keyboard) */
#define KEY_YEN 0x7D /* (Japanese keyboard) */
#define KEY_ABNT_C2 0x7E /* Numpad . on Brazilian keyboard */
#define KEY_NUMPADEQUALS 0x8D /* = on numeric keypad (NEC PC98) */
#define KEY_PREVTRACK 0x90 /* Previous Track (DIK_CIRCUMFLEX on Japanese keyboard) */
#define KEY_AT 0x91 /* (NEC PC98) */
#define KEY_COLON 0x92 /* (NEC PC98) */
#define KEY_UNDERLINE 0x93 /* (NEC PC98) */
#define KEY_KANJI 0x94 /* (Japanese keyboard) */
#define KEY_STOP 0x95 /* (NEC PC98) */
#define KEY_AX 0x96 /* (Japan AX) */
#define KEY_UNLABELED 0x97 /* (J3100) */
#define KEY_NEXTTRACK 0x99 /* Next Track */
#define KEY_NUMPADENTER 0x9C /* Enter on numeric keypad */
#define KEY_RCONTROL 0x9D
#define KEY_MUTE 0xA0 /* Mute */
#define KEY_CALCULATOR 0xA1 /* Calculator */
#define KEY_PLAYPAUSE 0xA2 /* Play / Pause */
#define KEY_MEDIASTOP 0xA4 /* Media Stop */
#define KEY_VOLUMEDOWN 0xAE /* Volume - */
#define KEY_VOLUMEUP 0xB0 /* Volume + */
#define KEY_WEBHOME 0xB2 /* Web home */
#define KEY_NUMPADCOMMA 0xB3 /* , on numeric keypad (NEC PC98) */
#define KEY_DIVIDE 0xB5 /* / on numeric keypad */
#define KEY_SYSRQ 0xB7
#define KEY_RMENU 0xB8 /* right Alt */
#define KEY_PAUSE 0xC5 /* Pause */
#define KEY_HOME 0xC7 /* Home on arrow keypad */
#define KEY_UP 0xC8 /* UpArrow on arrow keypad */
#define KEY_PRIOR 0xC9 /* PgUp on arrow keypad */
#define KEY_LEFT 0xCB /* LeftArrow on arrow keypad */
#define KEY_RIGHT 0xCD /* RightArrow on arrow keypad */
#define KEY_END 0xCF /* End on arrow keypad */
#define KEY_DOWN 0xD0 /* DownArrow on arrow keypad */
#define KEY_NEXT 0xD1 /* PgDn on arrow keypad */
#define KEY_INSERT 0xD2 /* Insert on arrow keypad */
#define KEY_DELETE 0xD3 /* Delete on arrow keypad */
#define KEY_LWIN 0xDB /* Left Windows key */
#define KEY_RWIN 0xDC /* Right Windows key */
#define KEY_APPS 0xDD /* AppMenu key */
#define KEY_POWER 0xDE /* System Power */
#define KEY_SLEEP 0xDF /* System Sleep */
#define KEY_WAKE 0xE3 /* System Wake */
#define KEY_WEBSEARCH 0xE5 /* Web Search */
#define KEY_WEBFAVORITES 0xE6 /* Web Favorites */
#define KEY_WEBREFRESH 0xE7 /* Web Refresh */
#define KEY_WEBSTOP 0xE8 /* Web Stop */
#define KEY_WEBFORWARD 0xE9 /* Web Forward */
#define KEY_WEBBACK 0xEA /* Web Back */
#define KEY_MYCOMPUTER 0xEB /* My Computer */
#define KEY_MAIL 0xEC /* Mail */
#define KEY_MEDIASELECT 0xED /* Media Select */
//============================================================
// device_info
//============================================================
class input_device_list;
class device_info
{
friend input_device_list;
private:
std::string m_name;
input_device * m_device;
running_machine & m_machine;
input_module & m_module;
input_device_class m_deviceclass;
public:
// Constructor
device_info(running_machine &machine, const char *name, input_device_class deviceclass, input_module &module)
: m_name(name),
m_device(nullptr),
m_machine(machine),
m_module(module),
m_deviceclass(deviceclass)
{
}
// Destructor
virtual ~device_info() {}
// Getters
running_machine & machine() const { return m_machine; }
const char * name() { return m_name.c_str(); }
input_device * device() { return m_device; }
input_module & module() const { return m_module; }
input_device_class deviceclass() { return m_deviceclass; }
// Poll and reset methods
virtual void poll() {};
virtual void reset() = 0;
};
//============================================================
// event_based_device
//============================================================
#define DEFAULT_EVENT_QUEUE_SIZE 20
template <class TEvent>
class event_based_device : public device_info
{
private:
std::queue<TEvent> m_event_queue;
protected:
std::mutex m_device_lock;
virtual void process_event(TEvent &ev) = 0;
public:
event_based_device(running_machine &machine, const char *name, input_device_class deviceclass, input_module &module)
: device_info(machine, name, deviceclass, module)
{
}
void queue_events(const TEvent *events, int count)
{
std::lock_guard<std::mutex> scope_lock(m_device_lock);
for (int i = 0; i < count; i++)
m_event_queue.push(events[i]);
// If we've gone over the size, remove old events from the queue
while (m_event_queue.size() > DEFAULT_EVENT_QUEUE_SIZE)
m_event_queue.pop();
}
void virtual poll() override
{
std::lock_guard<std::mutex> scope_lock(m_device_lock);
// Process each event until the queue is empty
while (!m_event_queue.empty())
{
TEvent &next_event = m_event_queue.front();
process_event(next_event);
m_event_queue.pop();
}
}
};
//============================================================
// input_device_list class
//============================================================
class input_device_list
{
protected:
std::vector<std::unique_ptr<device_info>> m_list;
public:
input_device_list()
{
}
void poll_devices()
{
for (auto iter = m_list.begin(); iter != m_list.end(); iter++)
iter->get()->poll();
}
void reset_devices()
{
for (auto iter = m_list.begin(); iter != m_list.end(); iter++)
iter->get()->reset();
}
void free_device(device_info * devinfo)
{
// remove us from the list
for (auto iter = m_list.begin(); iter != m_list.end(); iter++)
{
if (iter->get() == devinfo)
{
m_list.erase(iter);
break;
}
}
}
int find_index(device_info* devinfo)
{
// remove us from the list
int i = 0;
for (auto iter = m_list.begin(); iter != m_list.end(); iter++)
{
if (iter->get() == devinfo)
{
break;
}
i++;
}
// return the index or -1 if we couldn't find it
return i == m_list.size() ? -1 : i;
}
void free_all_devices()
{
while (!m_list.empty())
m_list.pop_back();
}
int size()
{
return m_list.size();
}
device_info* at(int index)
{
return m_list.at(index).get();
}
template <typename TActual>
TActual* create_device(running_machine &machine, const char *name, input_module &module)
{
// allocate the device object
auto devinfo = std::make_unique<TActual>(machine, name, module);
// Add the device to the machine
devinfo->m_device = machine.input().device_class(devinfo->deviceclass()).add_device(devinfo->name(), devinfo.get());
// append us to the list
m_list.push_back(std::move(devinfo));
return (TActual*)m_list.back().get();
}
template <class TActual>
TActual* at(int index)
{
return (TActual*)m_list.at(index).get();
}
};
// keyboard translation table
struct key_trans_entry {
input_item_id mame_key;
#if !defined(OSD_WINDOWS)
int sdl_scancode;
int sdl_key;
#else
int scan_code;
unsigned char virtual_key;
#endif
char ascii_key;
char const * mame_key_name;
char * ui_name;
};
class keyboard_trans_table
{
private:
// default constructor is private
keyboard_trans_table();
static key_trans_entry s_default_table[];
std::unique_ptr<key_trans_entry[]> m_custom_table;
key_trans_entry * m_table;
UINT32 m_table_size;
public:
// constructor
keyboard_trans_table(std::unique_ptr<key_trans_entry[]> table, unsigned int size);
// getters/setters
UINT32 size() { return m_table_size; }
// public methods
input_item_id lookup_mame_code(const char * scode);
int lookup_mame_index(const char * scode);
#if defined(OSD_WINDOWS)
input_item_id map_di_scancode_to_itemid(int di_scancode);
int vkey_for_mame_code(input_code code);
#endif
static keyboard_trans_table& instance()
{
static keyboard_trans_table s_instance;
return s_instance;
}
key_trans_entry & operator [](int i) { return m_table[i]; }
};
//============================================================
// input_module_base - base class for input modules
//============================================================
class osd_options;
typedef std::chrono::high_resolution_clock clock_type;
typedef std::chrono::time_point<std::chrono::high_resolution_clock> timepoint_type;
// 10 milliseconds polling interval
#define MIN_POLLING_INTERVAL 10
class input_module_base : public input_module
{
public:
input_module_base(const char *type, const char* name)
: input_module(type, name),
m_input_enabled(FALSE),
m_mouse_enabled(FALSE),
m_lightgun_enabled(FALSE),
m_input_paused(FALSE)
{
}
private:
bool m_input_enabled;
bool m_mouse_enabled;
bool m_lightgun_enabled;
bool m_input_paused;
const osd_options * m_options;
input_device_list m_devicelist;
clock_type m_clock;
timepoint_type m_last_poll;
protected:
void set_mouse_enabled(bool value) { m_mouse_enabled = value; }
public:
const osd_options * options() { return m_options; }
input_device_list * devicelist() { return &m_devicelist; }
bool input_enabled() { return m_input_enabled; }
bool input_paused() { return m_input_paused; }
bool mouse_enabled() { return m_mouse_enabled; }
bool lightgun_enabled() { return m_lightgun_enabled; }
int init(const osd_options &options) override;
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)
{
poll(machine);
}
}
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();
}
protected:
virtual int init_internal() { return 0; }
virtual bool should_poll_devices(running_machine &machine) = 0;
virtual void before_poll(running_machine &machine) {}
};
inline static int generic_button_get_state(void *device_internal, void *item_internal)
{
device_info *devinfo = (device_info *)device_internal;
unsigned char *itemdata = (unsigned char*)item_internal;
// return the current state
devinfo->module().poll_if_necessary(devinfo->machine());
return *itemdata >> 7;
}
inline static int generic_axis_get_state(void *device_internal, void *item_internal)
{
device_info *devinfo = (device_info *)device_internal;
int *axisdata = (int*)item_internal;
// return the current state
devinfo->module().poll_if_necessary(devinfo->machine());
return *axisdata;
}
//============================================================
// default_button_name
//============================================================
inline static const char *default_button_name(int which)
{
static char buffer[20];
snprintf(buffer, ARRAY_LENGTH(buffer), "B%d", which);
return buffer;
}
//============================================================
// default_pov_name
//============================================================
inline static const char *default_pov_name(int which)
{
static char buffer[20];
snprintf(buffer, ARRAY_LENGTH(buffer), "POV%d", which);
return buffer;
}
// default axis names
const char *const default_axis_name[] =
{
"X", "Y", "Z", "RX",
"RY", "RZ", "SL1", "SL2"
};
inline static INT32 normalize_absolute_axis(INT32 raw, INT32 rawmin, INT32 rawmax)
{
INT32 center = (rawmax + rawmin) / 2;
// make sure we have valid data
if (rawmin >= rawmax)
return raw;
// above center
if (raw >= center)
{
INT32 result = (INT64)(raw - center) * (INT64)INPUT_ABSOLUTE_MAX / (INT64)(rawmax - center);
return MIN(result, INPUT_ABSOLUTE_MAX);
}
// below center
else
{
INT32 result = -((INT64)(center - raw) * (INT64)-INPUT_ABSOLUTE_MIN / (INT64)(center - rawmin));
return MAX(result, INPUT_ABSOLUTE_MIN);
}
}
#endif

View File

@ -0,0 +1,683 @@
// license:BSD-3-Clause
// copyright-holders:Aaron Giles, Brad Hughes
//============================================================
//
// input_dinput.cpp - Windows DirectInput support
//
//============================================================
#include "input_module.h"
#include "modules/osdmodule.h"
#if defined(OSD_WINDOWS)
// standard windows headers
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <winioctl.h>
#include <tchar.h>
// undef WINNT for dinput.h to prevent duplicate definition
#undef WINNT
#include <dinput.h>
#undef interface
#include <mutex>
#include <thread>
// MAME headers
#include "emu.h"
#include "osdepend.h"
#include "ui/ui.h"
#include "strconv.h"
// MAMEOS headers
#include "winmain.h"
#include "window.h"
#include "winutil.h"
#include "../../windows/input.h"
#include "input_common.h"
#include "input_windows.h"
#define STRUCTSIZE(x) (m_dinput_version == 0x0300) ? sizeof(x##_DX3) : sizeof(x)
static INT32 dinput_joystick_pov_get_state(void *device_internal, void *item_internal);
//============================================================
// dinput_set_dword_property
//============================================================
static HRESULT dinput_set_dword_property(LPDIRECTINPUTDEVICE device, REFGUID property_guid, DWORD object, DWORD how, DWORD value)
{
DIPROPDWORD dipdw;
dipdw.diph.dwSize = sizeof(dipdw);
dipdw.diph.dwHeaderSize = sizeof(dipdw.diph);
dipdw.diph.dwObj = object;
dipdw.diph.dwHow = how;
dipdw.dwData = value;
return IDirectInputDevice_SetProperty(device, property_guid, &dipdw.diph);
}
//============================================================
// dinput_device - base directinput device
//============================================================
// DirectInput-specific information about a device
struct dinput_api_state
{
LPDIRECTINPUTDEVICE device;
LPDIRECTINPUTDEVICE2 device2;
DIDEVCAPS caps;
LPCDIDATAFORMAT format;
};
class dinput_device : public device_info
{
public:
dinput_api_state dinput;
dinput_device(running_machine &machine, const char *name, input_device_class deviceclass, input_module &module)
: device_info(machine, name, deviceclass, module),
dinput({0})
{
}
protected:
HRESULT poll_dinput(LPVOID pState)
{
HRESULT result;
// first poll the device, then get the state
if (dinput.device2 != NULL)
IDirectInputDevice2_Poll(dinput.device2);
// GetDeviceState returns the immediate state
result = IDirectInputDevice_GetDeviceState(dinput.device, dinput.format->dwDataSize, pState);
// handle lost inputs here
if (result == DIERR_INPUTLOST || result == DIERR_NOTACQUIRED)
{
result = IDirectInputDevice_Acquire(dinput.device);
if (result == DI_OK)
result = IDirectInputDevice_GetDeviceState(dinput.device, dinput.format->dwDataSize, pState);
}
return result;
}
};
//============================================================
// dinput_keyboard_device - directinput keyboard device
//============================================================
class dinput_keyboard_device : public dinput_device
{
private:
HANDLE m_dataEvent;
HANDLE m_exitEvent;
std::mutex m_device_lock;
public:
keyboard_state keyboard;
dinput_keyboard_device(running_machine &machine, const char *name, input_module &module)
: dinput_device(machine, name, DEVICE_CLASS_KEYBOARD, module),
keyboard({0})
{
}
// Polls the direct input immediate state
void poll() override
{
std::lock_guard<std::mutex> scope_lock(m_device_lock);
// Poll the state
dinput_device::poll_dinput(&keyboard.state);
}
void reset() override
{
memset(&keyboard, 0, sizeof(keyboard));
}
};
//============================================================
// dinput_module - base directinput module
//============================================================
class dinput_module : public wininput_module
{
private:
LPDIRECTINPUT m_dinput;
int m_dinput_version;
int didevtype_keyboard;
int didevtype_mouse;
public:
dinput_module(const char* type, const char* name)
: wininput_module(type, name)
{
}
int init_internal() override
{
HRESULT result = S_OK;
#if DIRECTINPUT_VERSION >= 0x800
m_dinput_version = DIRECTINPUT_VERSION;
result = DirectInput8Create(GetModuleHandleUni(), m_dinput_version, IID_IDirectInput8, (void **)&m_dinput, NULL);
if (result != DI_OK)
{
m_dinput_version = 0;
return result;
}
#else
// first attempt to initialize DirectInput at the current version
m_dinput_version = DIRECTINPUT_VERSION;
result = DirectInputCreate(GetModuleHandleUni(), m_dinput_version, &m_dinput, NULL);
if (result != DI_OK)
{
// if that fails, try version 5
m_dinput_version = 0x0500;
result = DirectInputCreate(GetModuleHandleUni(), m_dinput_version, &m_dinput, NULL);
if (result != DI_OK)
{
// if that fails, try version 3
m_dinput_version = 0x0300;
result = DirectInputCreate(GetModuleHandleUni(), m_dinput_version, &m_dinput, NULL);
if (result != DI_OK)
{
m_dinput_version = 0;
return result;
}
}
}
#endif
osd_printf_verbose("DirectInput: Using DirectInput %d\n", m_dinput_version >> 8);
return 0;
}
void exit() override
{
wininput_module::exit();
}
virtual BOOL device_enum_callback(LPCDIDEVICEINSTANCE instance, LPVOID ref) = 0;
void input_init(running_machine &machine) override
{
struct dinput_callback_context
{
dinput_module * self;
running_machine * machine;
} context = { this, &machine };
// enumerate the ones we have
auto enum_callback = [](LPCDIDEVICEINSTANCE instance, LPVOID ref) {
return ((dinput_callback_context*)ref)->self->device_enum_callback(instance, ((dinput_callback_context*)ref)->machine);
};
HRESULT result = IDirectInput_EnumDevices(m_dinput, dinput_devclass(), enum_callback, &context, DIEDFL_ATTACHEDONLY);
if (result != DI_OK)
fatalerror("DirectInput: Unable to enumerate keyboards (result=%08X)\n", (UINT32)result);
}
protected:
virtual int dinput_devclass() = 0;
template <class TDevice>
TDevice* create_dinput_device(
running_machine &machine,
LPCDIDEVICEINSTANCE instance,
LPCDIDATAFORMAT format1,
LPCDIDATAFORMAT format2,
DWORD cooperative_level)
{
HRESULT result;
// convert instance name to utf8
auto osd_deleter = [](void *ptr) { osd_free(ptr); };
auto utf8_instance_name = std::unique_ptr<char, decltype(osd_deleter)>(utf8_from_tstring(instance->tszInstanceName), osd_deleter);
// allocate memory for the device object
TDevice* devinfo = devicelist()->create_device<TDevice>(machine, utf8_instance_name.get(), *this);
// attempt to create a device
result = IDirectInput_CreateDevice(m_dinput, WRAP_REFIID(instance->guidInstance), &devinfo->dinput.device, NULL);
if (result != DI_OK)
goto error;
// try to get a version 2 device for it
result = IDirectInputDevice_QueryInterface(devinfo->dinput.device, WRAP_REFIID(IID_IDirectInputDevice2), (void **)&devinfo->dinput.device2);
if (result != DI_OK)
devinfo->dinput.device2 = NULL;
// get the caps
devinfo->dinput.caps.dwSize = STRUCTSIZE(DIDEVCAPS);
result = IDirectInputDevice_GetCapabilities(devinfo->dinput.device, &devinfo->dinput.caps);
if (result != DI_OK)
goto error;
// attempt to set the data format
devinfo->dinput.format = format1;
result = IDirectInputDevice_SetDataFormat(devinfo->dinput.device, devinfo->dinput.format);
if (result != DI_OK)
{
// use the secondary format if available
if (format2 != NULL)
{
devinfo->dinput.format = format2;
result = IDirectInputDevice_SetDataFormat(devinfo->dinput.device, devinfo->dinput.format);
}
if (result != DI_OK)
goto error;
}
// set the cooperative level
result = IDirectInputDevice_SetCooperativeLevel(devinfo->dinput.device, win_window_list->m_hwnd, cooperative_level);
if (result != DI_OK)
goto error;
return devinfo;
error:
devicelist()->free_device(devinfo);
return NULL;
}
std::string device_item_name(dinput_device * devinfo, int offset, const char * defstring, const TCHAR * suffix)
{
DIDEVICEOBJECTINSTANCE instance = { 0 };
HRESULT result;
// query the key name
instance.dwSize = STRUCTSIZE(DIDEVICEOBJECTINSTANCE);
result = IDirectInputDevice_GetObjectInfo(devinfo->dinput.device, &instance, offset, DIPH_BYOFFSET);
// if we got an error and have no default string, just return NULL
if (result != DI_OK)
{
if (defstring == nullptr)
return nullptr;
// Return the default value
return std::string(defstring);
}
auto osd_free_deleter = [](char *p) { osd_free(p); };
// convert the name to utf8
auto namestring = std::unique_ptr<char, decltype(osd_free_deleter)>(utf8_from_tstring(instance.tszName), osd_free_deleter);
// if no suffix, return as-is
if (suffix == nullptr)
{
return std::string(namestring.get());
}
// otherwise, allocate space to add the suffix
auto combined = std::make_unique<char[]>(strlen(namestring.get()) + 1 + _tcslen(suffix) + 1);
// convert the suffix to utf8
auto suffix_utf8 = std::unique_ptr<char, decltype(osd_free_deleter)>(utf8_from_tstring(suffix), osd_free_deleter);
// Concat the name and suffix
strcpy(combined.get(), namestring.get());
strcat(combined.get(), " ");
strcat(combined.get(), suffix_utf8.get());
return std::string(combined.get());
}
};
class keyboard_input_dinput : public dinput_module
{
public:
keyboard_input_dinput() :
dinput_module(OSD_KEYBOARDINPUT_PROVIDER, "dinput")
{
}
int dinput_devclass() override
{
#if DIRECTINPUT_VERSION >= 0x800
return DI8DEVCLASS_KEYBOARD;
#else
return DIDEVTYPE_KEYBOARD;
#endif
}
BOOL device_enum_callback(LPCDIDEVICEINSTANCE instance, LPVOID ref) override
{
running_machine &machine = *(running_machine *)ref;
dinput_keyboard_device *devinfo;
int keynum;
// allocate and link in a new device
devinfo = create_dinput_device<dinput_keyboard_device>(machine, instance, &c_dfDIKeyboard, NULL, DISCL_FOREGROUND | DISCL_NONEXCLUSIVE);
if (devinfo == NULL)
goto exit;
// populate it
for (keynum = 0; keynum < MAX_KEYS; keynum++)
{
input_item_id itemid = keyboard_trans_table::instance().map_di_scancode_to_itemid(keynum);
char defname[20];
std::string name;
// generate/fetch the name
snprintf(defname, ARRAY_LENGTH(defname), "Scan%03d", keynum);
name = device_item_name(devinfo, keynum, defname, NULL);
// add the item to the device
devinfo->device()->add_item(name.c_str(), itemid, generic_button_get_state, &devinfo->keyboard.state[keynum]);
}
exit:
return DIENUM_CONTINUE;
}
};
class dinput_mouse_device : public dinput_device
{
public:
mouse_state mouse;
dinput_mouse_device(running_machine &machine, const char *name, input_module &module)
: dinput_device(machine, name, DEVICE_CLASS_MOUSE, module),
mouse({0})
{
}
void poll() override
{
// 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;
}
void reset() override
{
memset(&mouse, 0, sizeof(mouse));
}
};
class mouse_input_dinput : public dinput_module
{
public:
mouse_input_dinput() :
dinput_module(OSD_MOUSEINPUT_PROVIDER, "dinput")
{
}
int dinput_devclass() override
{
#if DIRECTINPUT_VERSION >= 0x800
return DI8DEVCLASS_POINTER;
#else
return DI8DEVTYPE_MOUSE;
#endif
}
BOOL device_enum_callback(LPCDIDEVICEINSTANCE instance, LPVOID ref) override
{
dinput_mouse_device *devinfo = NULL;
running_machine &machine = *(running_machine *)ref;
int axisnum, butnum;
HRESULT result;
// allocate and link in a new device
devinfo = create_dinput_device<dinput_mouse_device>(machine, instance, &c_dfDIMouse2, &c_dfDIMouse, DISCL_FOREGROUND | DISCL_NONEXCLUSIVE);
if (devinfo == NULL)
goto exit;
// set relative mode on the mouse device
result = dinput_set_dword_property(devinfo->dinput.device, DIPROP_AXISMODE, 0, DIPH_DEVICE, DIPROPAXISMODE_REL);
if (result != DI_OK && result != DI_PROPNOEFFECT)
{
osd_printf_error("DirectInput: Unable to set relative mode for mouse %d (%s)\n", devicelist()->size(), devinfo->name());
goto error;
}
// cap the number of axes and buttons based on the format
devinfo->dinput.caps.dwAxes = MIN(devinfo->dinput.caps.dwAxes, 3);
devinfo->dinput.caps.dwButtons = MIN(devinfo->dinput.caps.dwButtons, (devinfo->dinput.format == &c_dfDIMouse) ? 4 : 8);
// populate the axes
for (axisnum = 0; axisnum < devinfo->dinput.caps.dwAxes; axisnum++)
{
// add to the mouse device and optionally to the gun device as well
std::string name = device_item_name(devinfo, offsetof(DIMOUSESTATE, lX) + axisnum * sizeof(LONG), default_axis_name[axisnum], NULL);
devinfo->device()->add_item(name.c_str(), (input_item_id)(ITEM_ID_XAXIS + axisnum), generic_axis_get_state, &devinfo->mouse.lX + axisnum);
}
// populate the buttons
for (butnum = 0; butnum < devinfo->dinput.caps.dwButtons; butnum++)
{
FPTR offset = (FPTR)(&((DIMOUSESTATE *)NULL)->rgbButtons[butnum]);
// add to the mouse device
std::string name = device_item_name(devinfo, offset, default_button_name(butnum), NULL);
devinfo->device()->add_item(name.c_str(), (input_item_id)(ITEM_ID_BUTTON1 + butnum), generic_button_get_state, &devinfo->mouse.rgbButtons[butnum]);
}
exit:
return DIENUM_CONTINUE;
error:
if (devinfo != NULL)
devicelist()->free_device(devinfo);
goto exit;
}
};
// state information for a joystick; DirectInput state must be first element
struct dinput_joystick_state
{
DIJOYSTATE state;
LONG rangemin[8];
LONG rangemax[8];
};
class dinput_joystick_device : public dinput_device
{
public:
dinput_joystick_state joystick;
dinput_joystick_device(running_machine &machine, const char *name, input_module &module)
: dinput_device(machine, name, DEVICE_CLASS_JOYSTICK, module),
joystick({0})
{
}
void reset() override
{
memset(&joystick, 0, sizeof(joystick));
}
void poll() override
{
int axisnum;
// poll the device first
dinput_device::poll_dinput(&joystick.state);
// normalize axis values
for (axisnum = 0; axisnum < 8; axisnum++)
{
LONG *axis = (&joystick.state.lX) + axisnum;
*axis = normalize_absolute_axis(*axis, joystick.rangemin[axisnum], joystick.rangemax[axisnum]);
}
}
};
class joystick_input_dinput : public dinput_module
{
public:
joystick_input_dinput() :
dinput_module(OSD_JOYSTICKINPUT_PROVIDER, "dinput")
{
}
int dinput_devclass() override
{
#if DIRECTINPUT_VERSION >= 0x800
return DI8DEVCLASS_GAMECTRL;
#else
return DI8DEVTYPE_JOYSTICK;
#endif
}
BOOL device_enum_callback(LPCDIDEVICEINSTANCE instance, LPVOID ref) override
{
DWORD cooperative_level = DISCL_FOREGROUND | DISCL_NONEXCLUSIVE;
int axisnum, axiscount, povnum, butnum;
running_machine &machine = *(running_machine *)ref;
dinput_joystick_device *devinfo;
HRESULT result;
if (win_window_list != NULL && win_window_list->win_has_menu()) {
cooperative_level = DISCL_BACKGROUND | DISCL_NONEXCLUSIVE;
}
// allocate and link in a new device
devinfo = create_dinput_device<dinput_joystick_device>(machine, instance, &c_dfDIJoystick, NULL, cooperative_level);
if (devinfo == NULL)
goto exit;
// set absolute mode
result = dinput_set_dword_property(devinfo->dinput.device, DIPROP_AXISMODE, 0, DIPH_DEVICE, DIPROPAXISMODE_ABS);
if (result != DI_OK && result != DI_PROPNOEFFECT)
osd_printf_warning("DirectInput: Unable to set absolute mode for joystick %d (%s)\n", devicelist()->size(), devinfo->name());
// turn off deadzone; we do our own calculations
result = dinput_set_dword_property(devinfo->dinput.device, DIPROP_DEADZONE, 0, DIPH_DEVICE, 0);
if (result != DI_OK && result != DI_PROPNOEFFECT)
osd_printf_warning("DirectInput: Unable to reset deadzone for joystick %d (%s)\n", devicelist()->size(), devinfo->name());
// turn off saturation; we do our own calculations
result = dinput_set_dword_property(devinfo->dinput.device, DIPROP_SATURATION, 0, DIPH_DEVICE, 10000);
if (result != DI_OK && result != DI_PROPNOEFFECT)
osd_printf_warning("DirectInput: Unable to reset saturation for joystick %d (%s)\n", devicelist()->size(), devinfo->name());
// cap the number of axes, POVs, and buttons based on the format
devinfo->dinput.caps.dwAxes = MIN(devinfo->dinput.caps.dwAxes, 8);
devinfo->dinput.caps.dwPOVs = MIN(devinfo->dinput.caps.dwPOVs, 4);
devinfo->dinput.caps.dwButtons = MIN(devinfo->dinput.caps.dwButtons, 128);
// populate the axes
for (axisnum = axiscount = 0; axiscount < devinfo->dinput.caps.dwAxes && axisnum < 8; axisnum++)
{
DIPROPRANGE dipr;
std::string name;
// fetch the range of this axis
dipr.diph.dwSize = sizeof(dipr);
dipr.diph.dwHeaderSize = sizeof(dipr.diph);
dipr.diph.dwObj = offsetof(DIJOYSTATE2, lX) + axisnum * sizeof(LONG);
dipr.diph.dwHow = DIPH_BYOFFSET;
result = IDirectInputDevice_GetProperty(devinfo->dinput.device, DIPROP_RANGE, &dipr.diph);
if (result != DI_OK)
continue;
devinfo->joystick.rangemin[axisnum] = dipr.lMin;
devinfo->joystick.rangemax[axisnum] = dipr.lMax;
// populate the item description as well
name = device_item_name(devinfo, offsetof(DIJOYSTATE2, lX) + axisnum * sizeof(LONG), default_axis_name[axisnum], NULL);
devinfo->device()->add_item(name.c_str(), (input_item_id)(ITEM_ID_XAXIS + axisnum), generic_axis_get_state, &devinfo->joystick.state.lX + axisnum);
axiscount++;
}
// populate the POVs
for (povnum = 0; povnum < devinfo->dinput.caps.dwPOVs; povnum++)
{
std::string name;
// left
name = device_item_name(devinfo, offsetof(DIJOYSTATE2, rgdwPOV) + povnum * sizeof(DWORD), default_pov_name(povnum), TEXT("L"));
devinfo->device()->add_item(name.c_str(), ITEM_ID_OTHER_SWITCH, dinput_joystick_pov_get_state, (void *)(FPTR)(povnum * 4 + POVDIR_LEFT));
// right
name = device_item_name(devinfo, offsetof(DIJOYSTATE2, rgdwPOV) + povnum * sizeof(DWORD), default_pov_name(povnum), TEXT("R"));
devinfo->device()->add_item(name.c_str(), ITEM_ID_OTHER_SWITCH, dinput_joystick_pov_get_state, (void *)(FPTR)(povnum * 4 + POVDIR_RIGHT));
// up
name = device_item_name(devinfo, offsetof(DIJOYSTATE2, rgdwPOV) + povnum * sizeof(DWORD), default_pov_name(povnum), TEXT("U"));
devinfo->device()->add_item(name.c_str(), ITEM_ID_OTHER_SWITCH, dinput_joystick_pov_get_state, (void *)(FPTR)(povnum * 4 + POVDIR_UP));
// down
name = device_item_name(devinfo, offsetof(DIJOYSTATE2, rgdwPOV) + povnum * sizeof(DWORD), default_pov_name(povnum), TEXT("D"));
devinfo->device()->add_item(name.c_str(), ITEM_ID_OTHER_SWITCH, dinput_joystick_pov_get_state, (void *)(FPTR)(povnum * 4 + POVDIR_DOWN));
}
// populate the buttons
for (butnum = 0; butnum < devinfo->dinput.caps.dwButtons; butnum++)
{
FPTR offset = (FPTR)(&((DIJOYSTATE2 *)NULL)->rgbButtons[butnum]);
std::string name = device_item_name(devinfo, offset, default_button_name(butnum), NULL);
input_item_id itemid;
if (butnum < INPUT_MAX_BUTTONS)
itemid = (input_item_id)(ITEM_ID_BUTTON1 + butnum);
else if (butnum < INPUT_MAX_BUTTONS + INPUT_MAX_ADD_SWITCH)
itemid = (input_item_id)(ITEM_ID_ADD_SWITCH1 - INPUT_MAX_BUTTONS + butnum);
else
itemid = ITEM_ID_OTHER_SWITCH;
devinfo->device()->add_item(name.c_str(), itemid, generic_button_get_state, &devinfo->joystick.state.rgbButtons[butnum]);
}
exit:
return DIENUM_CONTINUE;
}
};
//============================================================
// dinput_joystick_pov_get_state
//============================================================
static INT32 dinput_joystick_pov_get_state(void *device_internal, void *item_internal)
{
dinput_joystick_device *devinfo = (dinput_joystick_device *)device_internal;
int povnum = (FPTR)item_internal / 4;
int povdir = (FPTR)item_internal % 4;
INT32 result = 0;
DWORD pov;
// get the current state
devinfo->module().poll_if_necessary(devinfo->machine());
pov = devinfo->joystick.state.rgdwPOV[povnum];
// if invalid, return 0
if ((pov & 0xffff) == 0xffff)
return result;
// return the current state
switch (povdir)
{
case POVDIR_LEFT: result = (pov >= 22500 && pov <= 31500); break;
case POVDIR_RIGHT: result = (pov >= 4500 && pov <= 13500); break;
case POVDIR_UP: result = (pov >= 31500 || pov <= 4500); break;
case POVDIR_DOWN: result = (pov >= 13500 && pov <= 22500); break;
}
return result;
}
#else
MODULE_NOT_SUPPORTED(keyboard_input_dinput, OSD_KEYBOARDINPUT_PROVIDER, "dinput")
MODULE_NOT_SUPPORTED(mouse_input_dinput, OSD_MOUSEINPUT_PROVIDER, "dinput")
MODULE_NOT_SUPPORTED(joystick_input_dinput, OSD_JOYSTICKINPUT_PROVIDER, "dinput")
#endif
MODULE_DEFINITION(KEYBOARDINPUT_DINPUT, keyboard_input_dinput)
MODULE_DEFINITION(MOUSEINPUT_DINPUT, mouse_input_dinput)
MODULE_DEFINITION(JOYSTICKINPUT_DINPUT, joystick_input_dinput)

View File

@ -0,0 +1,39 @@
// license:BSD-3-Clause
// copyright-holders:Brad Hughes
//============================================================
//
// input_module.h - OSD input module contracts
//
//============================================================
#ifndef INPUT_MODULE_H_
#define INPUT_MODULE_H_
#include "osdepend.h"
#include "modules/osdmodule.h"
class input_module : public osd_module
{
public:
input_module(const char *type, const char *name)
: osd_module(type, name)
{
}
virtual void input_init(running_machine &machine) = 0;
virtual void poll_if_necessary(running_machine &machine) = 0;
virtual void pause() = 0;
virtual void resume() = 0;
virtual void exit() override {};
};
//============================================================
// CONSTANTS
//============================================================
#define OSD_KEYBOARDINPUT_PROVIDER "keyboardprovider"
#define OSD_MOUSEINPUT_PROVIDER "mouseprovider"
#define OSD_LIGHTGUNINPUT_PROVIDER "lightgunprovider"
#define OSD_JOYSTICKINPUT_PROVIDER "joystickprovider"
#endif /* INPUT_MODULE_H_ */

View File

@ -0,0 +1,66 @@
// license:BSD-3-Clause
// copyright-holders:Brad Hughes
//============================================================
//
// input_none.cpp - Default unimplemented input modules
//
//============================================================
#include "input_module.h"
#include "modules/osdmodule.h"
class keyboard_input_none : public input_module
{
public:
keyboard_input_none()
: input_module(OSD_KEYBOARDINPUT_PROVIDER, "none") {}
int init(const osd_options &options) override { return 0; }
void poll_if_necessary(running_machine &machine) override {};
void input_init(running_machine &machine) override {};
void pause() override {};
void resume() override {};
};
MODULE_DEFINITION(KEYBOARD_NONE, keyboard_input_none)
class mouse_input_none : public input_module
{
public:
mouse_input_none()
: input_module(OSD_MOUSEINPUT_PROVIDER, "none") {}
int init(const osd_options &options) override { return 0; }
void input_init(running_machine &machine) override {};
void poll_if_necessary(running_machine &machine) override {};
void pause() override {};
void resume() override {};
};
MODULE_DEFINITION(MOUSE_NONE, mouse_input_none)
class lightgun_input_none : public input_module
{
public:
lightgun_input_none()
: input_module(OSD_LIGHTGUNINPUT_PROVIDER, "none") {}
int init(const osd_options &options) override { return 0; }
void input_init(running_machine &machine) override {};
void poll_if_necessary(running_machine &machine) override {};
void pause() override {};
void resume() override {};
};
MODULE_DEFINITION(LIGHTGUN_NONE, lightgun_input_none)
class joystick_input_none : public input_module
{
public:
joystick_input_none()
: input_module(OSD_JOYSTICKINPUT_PROVIDER, "none") {}
int init(const osd_options &options) override { return 0; }
void input_init(running_machine &machine) override {};
void poll_if_necessary(running_machine &machine) override {};
void pause() override {};
void resume() override {};
};
MODULE_DEFINITION(JOYSTICK_NONE, joystick_input_none)

View File

@ -0,0 +1,649 @@
// license:BSD-3-Clause
// copyright-holders:Aaron Giles, Brad Hughes
//============================================================
//
// input_rawinput.cpp - Windows RawInput input implementation
//
//============================================================
#include "input_module.h"
#include "modules/osdmodule.h"
#if defined(OSD_WINDOWS)
// standard windows headers
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <winioctl.h>
#include <tchar.h>
#undef interface
#include <mutex>
// MAME headers
#include "emu.h"
#include "osdepend.h"
#include "ui/ui.h"
#include "strconv.h"
// MAMEOS headers
#include "winmain.h"
#include "window.h"
#include "../../windows/input.h"
#include "input_common.h"
#include "input_windows.h"
//============================================================
// MACROS
//============================================================
#ifdef UNICODE
#define UNICODE_SUFFIX "W"
#else
#define UNICODE_SUFFIX "A"
#endif
// RawInput APIs
typedef /*WINUSERAPI*/ INT(WINAPI *get_rawinput_device_list_ptr)(OUT PRAWINPUTDEVICELIST pRawInputDeviceList, IN OUT PINT puiNumDevices, IN UINT cbSize);
typedef /*WINUSERAPI*/ INT(WINAPI *get_rawinput_data_ptr)(IN HRAWINPUT hRawInput, IN UINT uiCommand, OUT LPVOID pData, IN OUT PINT pcbSize, IN UINT cbSizeHeader);
typedef /*WINUSERAPI*/ INT(WINAPI *get_rawinput_device_info_ptr)(IN HANDLE hDevice, IN UINT uiCommand, OUT LPVOID pData, IN OUT PINT pcbSize);
typedef /*WINUSERAPI*/ BOOL(WINAPI *register_rawinput_devices_ptr)(IN PCRAWINPUTDEVICE pRawInputDevices, IN UINT uiNumDevices, IN UINT cbSize);
//============================================================
// reg_query_string
//============================================================
static TCHAR *reg_query_string(HKEY key, const TCHAR *path)
{
TCHAR *buffer;
DWORD datalen;
LONG result;
// first query to get the length
result = RegQueryValueEx(key, path, NULL, NULL, NULL, &datalen);
if (result != ERROR_SUCCESS)
return NULL;
// allocate a buffer
buffer = global_alloc_array(TCHAR, datalen + sizeof(*buffer));
buffer[datalen / sizeof(*buffer)] = 0;
// now get the actual data
result = RegQueryValueEx(key, path, NULL, NULL, (LPBYTE)buffer, &datalen);
if (result == ERROR_SUCCESS)
return buffer;
// otherwise return a NULL buffer
global_free_array(buffer);
return NULL;
}
//============================================================
// rawinput_device_improve_name
//============================================================
static TCHAR *rawinput_device_improve_name(TCHAR *name)
{
static const TCHAR usbbasepath[] = TEXT("SYSTEM\\CurrentControlSet\\Enum\\USB");
static const TCHAR basepath[] = TEXT("SYSTEM\\CurrentControlSet\\Enum\\");
TCHAR *regstring = NULL;
TCHAR *parentid = NULL;
TCHAR *regpath = NULL;
const TCHAR *chsrc;
HKEY regkey = NULL;
int usbindex;
TCHAR *chdst;
LONG result;
// The RAW name received is formatted as:
// \??\type-id#hardware-id#instance-id#{DeviceClasses-id}
// XP starts with "\??\"
// Vista64 starts with "\\?\"
// ensure the name is something we can handle
if (_tcsncmp(name, TEXT("\\\\?\\"), 4) != 0 && _tcsncmp(name, TEXT("\\??\\"), 4) != 0)
return name;
// allocate a temporary string and concatenate the base path plus the name
regpath = global_alloc_array(TCHAR, _tcslen(basepath) + 1 + _tcslen(name));
_tcscpy(regpath, basepath);
chdst = regpath + _tcslen(regpath);
// convert all # to \ in the name
for (chsrc = name + 4; *chsrc != 0; chsrc++)
*chdst++ = (*chsrc == '#') ? '\\' : *chsrc;
*chdst = 0;
// remove the final chunk
chdst = _tcsrchr(regpath, '\\');
if (chdst == NULL)
goto exit;
*chdst = 0;
// now try to open the registry key
result = RegOpenKeyEx(HKEY_LOCAL_MACHINE, regpath, 0, KEY_READ, &regkey);
if (result != ERROR_SUCCESS)
goto exit;
// fetch the device description; if it exists, we are finished
regstring = reg_query_string(regkey, TEXT("DeviceDesc"));
if (regstring != NULL)
goto convert;
// close this key
RegCloseKey(regkey);
regkey = NULL;
// if the key name does not contain "HID", it's not going to be in the USB tree; give up
if (_tcsstr(regpath, TEXT("HID")) == NULL)
goto exit;
// extract the expected parent ID from the regpath
parentid = _tcsrchr(regpath, '\\');
if (parentid == NULL)
goto exit;
parentid++;
// open the USB key
result = RegOpenKeyEx(HKEY_LOCAL_MACHINE, usbbasepath, 0, KEY_READ, &regkey);
if (result != ERROR_SUCCESS)
goto exit;
// enumerate the USB key
for (usbindex = 0; result == ERROR_SUCCESS && regstring == NULL; usbindex++)
{
TCHAR keyname[MAX_PATH];
DWORD namelen;
// get the next enumerated subkey and scan it
namelen = ARRAY_LENGTH(keyname) - 1;
result = RegEnumKeyEx(regkey, usbindex, keyname, &namelen, NULL, NULL, NULL, NULL);
if (result == ERROR_SUCCESS)
{
LONG subresult;
int subindex;
HKEY subkey;
// open the subkey
subresult = RegOpenKeyEx(regkey, keyname, 0, KEY_READ, &subkey);
if (subresult != ERROR_SUCCESS)
continue;
// enumerate the subkey
for (subindex = 0; subresult == ERROR_SUCCESS && regstring == NULL; subindex++)
{
// get the next enumerated subkey and scan it
namelen = ARRAY_LENGTH(keyname) - 1;
subresult = RegEnumKeyEx(subkey, subindex, keyname, &namelen, NULL, NULL, NULL, NULL);
if (subresult == ERROR_SUCCESS)
{
TCHAR *endparentid;
LONG endresult;
HKEY endkey;
// open this final key
endresult = RegOpenKeyEx(subkey, keyname, 0, KEY_READ, &endkey);
if (endresult != ERROR_SUCCESS)
continue;
// do we have a match?
endparentid = reg_query_string(endkey, TEXT("ParentIdPrefix"));
if (endparentid != NULL && _tcsncmp(parentid, endparentid, _tcslen(endparentid)) == 0)
regstring = reg_query_string(endkey, TEXT("DeviceDesc"));
// free memory and close the key
if (endparentid != NULL)
global_free_array(endparentid);
RegCloseKey(endkey);
}
}
// close the subkey
RegCloseKey(subkey);
}
}
// if we didn't find anything, go to the exit
if (regstring == NULL)
goto exit;
convert:
// replace the name with the nicer one
global_free_array(name);
// remove anything prior to the final semicolon
chsrc = _tcsrchr(regstring, ';');
if (chsrc != NULL)
chsrc++;
else
chsrc = regstring;
name = global_alloc_array(TCHAR, _tcslen(chsrc) + 1);
_tcscpy(name, chsrc);
exit:
if (regstring != NULL)
global_free_array(regstring);
if (regpath != NULL)
global_free_array(regpath);
if (regkey != NULL)
RegCloseKey(regkey);
return name;
}
//============================================================
// rawinput_device class
//============================================================
class rawinput_device : public event_based_device<RAWINPUT>
{
private:
HANDLE m_handle;
public:
rawinput_device(running_machine& machine, const char* name, input_device_class deviceclass, input_module& module)
: event_based_device(machine, name, deviceclass, module)
{
}
HANDLE device_handle() { return m_handle; }
void set_handle(HANDLE handle) { m_handle = handle; }
};
//============================================================
// rawinput_keyboard_device
//============================================================
class rawinput_keyboard_device : public rawinput_device
{
public:
keyboard_state keyboard;
rawinput_keyboard_device(running_machine& machine, const char* name, input_module& module)
: rawinput_device(machine, name, DEVICE_CLASS_KEYBOARD, module),
keyboard({0})
{
}
void reset() override
{
memset(&keyboard, 0, sizeof(keyboard));
}
void process_event(RAWINPUT &rawinput) override
{
// determine the full DIK-compatible scancode
UINT8 scancode = (rawinput.data.keyboard.MakeCode & 0x7f) | ((rawinput.data.keyboard.Flags & RI_KEY_E0) ? 0x80 : 0x00);
// scancode 0xaa is a special shift code we need to ignore
if (scancode == 0xaa)
return;
// set or clear the key
keyboard.state[scancode] = (rawinput.data.keyboard.Flags & RI_KEY_BREAK) ? 0x00 : 0x80;
}
};
//============================================================
// rawinput_mouse_device
//============================================================
struct rawinput_mouse_state
{
int raw_x;
int raw_y;
int raw_z;
};
class rawinput_mouse_device : public rawinput_device
{
private:
std::mutex m_device_lock;
public:
//rawinput_mouse_state raw_mouse;
mouse_state mouse;
rawinput_mouse_device(running_machine& machine, const char* name, input_module& module)
: rawinput_device(machine, name, DEVICE_CLASS_MOUSE, module),
mouse({0})
{
}
void poll() override
{
mouse.lX = 0;
mouse.lY = 0;
mouse.lZ = 0;
rawinput_device::poll();
//std::lock_guard<std::mutex> scope_lock(m_device_lock);
//// copy the accumulated raw state to the actual state
//mouse.lX = raw_mouse.raw_x;
//mouse.lY = raw_mouse.raw_y;
//mouse.lZ = raw_mouse.raw_z;
//raw_mouse.raw_x = 0;
//raw_mouse.raw_y = 0;
//raw_mouse.raw_z = 0;
//osd_printf_verbose("At poll: lX=%d, lY=%d, lZ=%d\n", (int)mouse.lX, (int)mouse.lY, (int)mouse.lZ);
}
void reset() override
{
memset(&mouse, 0, sizeof(mouse));
}
void process_event(RAWINPUT &rawinput) override
{
// If this data was intended for a rawinput lightgun, ignore it.
if (rawinput.data.mouse.usFlags & MOUSE_MOVE_ABSOLUTE)
return;
mouse.lX += rawinput.data.mouse.lLastX * INPUT_RELATIVE_PER_PIXEL;
mouse.lY += rawinput.data.mouse.lLastY * INPUT_RELATIVE_PER_PIXEL;
/*osd_printf_verbose(
"Mouse Abs : lastX = %d, lastY = %d, rawx = %d, rawy = %d\n",
(int)rawinput.data.mouse.lLastX,
(int)rawinput.data.mouse.lLastY,
(int)raw_mouse.raw_x,
(int)raw_mouse.raw_y);*/
// update zaxis
if (rawinput.data.mouse.usButtonFlags & RI_MOUSE_WHEEL)
mouse.lZ += (INT16)rawinput.data.mouse.usButtonData * 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;
if (rawinput.data.mouse.usButtonFlags & RI_MOUSE_BUTTON_1_UP) mouse.rgbButtons[0] = 0x00;
if (rawinput.data.mouse.usButtonFlags & RI_MOUSE_BUTTON_2_DOWN) mouse.rgbButtons[1] = 0x80;
if (rawinput.data.mouse.usButtonFlags & RI_MOUSE_BUTTON_2_UP) mouse.rgbButtons[1] = 0x00;
if (rawinput.data.mouse.usButtonFlags & RI_MOUSE_BUTTON_3_DOWN) mouse.rgbButtons[2] = 0x80;
if (rawinput.data.mouse.usButtonFlags & RI_MOUSE_BUTTON_3_UP) mouse.rgbButtons[2] = 0x00;
if (rawinput.data.mouse.usButtonFlags & RI_MOUSE_BUTTON_4_DOWN) mouse.rgbButtons[3] = 0x80;
if (rawinput.data.mouse.usButtonFlags & RI_MOUSE_BUTTON_4_UP) mouse.rgbButtons[3] = 0x00;
if (rawinput.data.mouse.usButtonFlags & RI_MOUSE_BUTTON_5_DOWN) mouse.rgbButtons[4] = 0x80;
if (rawinput.data.mouse.usButtonFlags & RI_MOUSE_BUTTON_5_UP) mouse.rgbButtons[4] = 0x00;
}
};
//============================================================
// rawinput_module - base class for rawinput modules
//============================================================
class rawinput_module : public wininput_module
{
private:
// RawInput variables
get_rawinput_device_list_ptr get_rawinput_device_list;
get_rawinput_data_ptr get_rawinput_data;
get_rawinput_device_info_ptr get_rawinput_device_info;
register_rawinput_devices_ptr register_rawinput_devices;
std::mutex m_module_lock;
public:
rawinput_module(const char *type, const char* name)
: wininput_module(type, name),
get_rawinput_device_list(nullptr),
get_rawinput_data(nullptr),
get_rawinput_device_info(nullptr),
register_rawinput_devices(nullptr)
{
}
void input_init(running_machine &machine) override
{
// get the number of devices, allocate a device list, and fetch it
int device_count = 0;
if ((*get_rawinput_device_list)(NULL, &device_count, sizeof(RAWINPUTDEVICELIST)) != 0)
return;
if (device_count == 0)
return;
auto rawinput_devices = std::make_unique<RAWINPUTDEVICELIST[]>(device_count);
if ((*get_rawinput_device_list)(rawinput_devices.get(), &device_count, sizeof(RAWINPUTDEVICELIST)) == -1)
return;
// iterate backwards through devices; new devices are added at the head
for (int devnum = device_count - 1; devnum >= 0; devnum--)
{
RAWINPUTDEVICELIST *device = &rawinput_devices[devnum];
add_rawinput_device(machine, device);
}
// don't enable global inputs when debugging
if (!machine.options().debug())
{
m_global_inputs_enabled = downcast<windows_options &>(machine.options()).global_inputs();
}
// If we added no devices, no need to register for notifications
if (devicelist()->size() == 0)
return;
// finally, register to receive raw input WM_INPUT messages if we found devices
RAWINPUTDEVICE registration;
registration.usUsagePage = usagepage();
registration.usUsage = usage();
registration.dwFlags = m_global_inputs_enabled ? 0x00000100 : 0;
registration.hwndTarget = win_window_list->m_hwnd;
// register the device
(*register_rawinput_devices)(&registration, 1, sizeof(registration));
}
protected:
virtual void add_rawinput_device(running_machine& machine, RAWINPUTDEVICELIST * device) = 0;
virtual USHORT usagepage() = 0;
virtual USHORT usage() = 0;
int init_internal() override
{
HMODULE user32;
// look in user32 for the raw input APIs
user32 = LoadLibrary(TEXT("user32.dll"));
if (user32 == NULL)
return 1;
// look up the entry points
register_rawinput_devices = (register_rawinput_devices_ptr)GetProcAddress(user32, "RegisterRawInputDevices");
get_rawinput_device_list = (get_rawinput_device_list_ptr)GetProcAddress(user32, "GetRawInputDeviceList");
get_rawinput_device_info = (get_rawinput_device_info_ptr)GetProcAddress(user32, "GetRawInputDeviceInfo" UNICODE_SUFFIX);
get_rawinput_data = (get_rawinput_data_ptr)GetProcAddress(user32, "GetRawInputData");
if (register_rawinput_devices == NULL || get_rawinput_device_list == NULL || get_rawinput_device_info == NULL || get_rawinput_data == NULL)
return 1;
osd_printf_verbose("RawInput: APIs detected\n");
return 0;
}
template<class TDevice>
TDevice* create_rawinput_device(running_machine &machine, PRAWINPUTDEVICELIST rawinputdevice)
{
TDevice* devinfo = nullptr;
INT name_length = 0;
// determine the length of the device name, allocate it, and fetch it if not nameless
if ((*get_rawinput_device_info)(rawinputdevice->hDevice, RIDI_DEVICENAME, NULL, &name_length) != 0)
return nullptr;
std::unique_ptr<TCHAR[]> tname = std::make_unique<TCHAR[]>(name_length + 1);
if (name_length > 1 && (*get_rawinput_device_info)(rawinputdevice->hDevice, RIDI_DEVICENAME, tname.get(), &name_length) == -1)
return nullptr;
// if this is an RDP name, skip it
if (_tcsstr(tname.get(), TEXT("Root#RDP_")) != NULL)
return nullptr;
// improve the name and then allocate a device
tname = std::unique_ptr<TCHAR[]>(rawinput_device_improve_name(tname.release()));
// convert name to utf8
auto osd_deleter = [](void *ptr) { osd_free(ptr); };
auto utf8_name = std::unique_ptr<char, decltype(osd_deleter)>(utf8_from_tstring(tname.get()), osd_deleter);
devinfo = devicelist()->create_device<TDevice>(machine, utf8_name.get(), *this);
// Add the handle
devinfo->set_handle(rawinputdevice->hDevice);
return devinfo;
}
bool handle_input_event(input_event eventid, void* eventdata) override
{
// Only handle raw input data
if (!input_enabled() || eventid != INPUT_EVENT_RAWINPUT)
return FALSE;
HRAWINPUT rawinputdevice = *(HRAWINPUT*)eventdata;
BYTE small_buffer[4096];
std::unique_ptr<BYTE[]> larger_buffer;
LPBYTE data = small_buffer;
BOOL result = FALSE;
int size;
// ignore if not enabled
if (!input_enabled())
return FALSE;
// determine the size of databuffer we need
if ((*get_rawinput_data)(rawinputdevice, RID_INPUT, NULL, &size, sizeof(RAWINPUTHEADER)) != 0)
return FALSE;
// if necessary, allocate a temporary buffer and fetch the data
if (size > sizeof(small_buffer))
{
larger_buffer = std::make_unique<BYTE[]>(size);
data = larger_buffer.get();
if (data == NULL)
return FALSE;
}
// fetch the data and process the appropriate message types
result = (*get_rawinput_data)((HRAWINPUT)rawinputdevice, RID_INPUT, data, &size, sizeof(RAWINPUTHEADER));
if (result)
{
std::lock_guard<std::mutex> scope_lock(m_module_lock);
rawinput_device *devinfo;
// find the device in the list and update
for (int i = 0; i < devicelist()->size(); i++)
{
devinfo = dynamic_cast<rawinput_device*>(devicelist()->at(i));
RAWINPUT *input = reinterpret_cast<RAWINPUT*>(data);
if (input->header.hDevice == devinfo->device_handle())
{
devinfo->queue_events(input, 1);
result = TRUE;
}
}
}
return result;
}
};
//============================================================
// keyboard_input_rawinput - rawinput keyboard module
//============================================================
class keyboard_input_rawinput : public rawinput_module
{
public:
keyboard_input_rawinput()
: rawinput_module(OSD_KEYBOARDINPUT_PROVIDER, "rawinput")
{
}
protected:
USHORT usagepage() { return 1; }
USHORT usage() { return 6; }
void add_rawinput_device(running_machine& machine, RAWINPUTDEVICELIST * device) override
{
// make sure this is a keyboard
if (device->dwType != RIM_TYPEKEYBOARD)
return;
// allocate and link in a new device
rawinput_keyboard_device *devinfo = create_rawinput_device<rawinput_keyboard_device>(machine, device);
if (devinfo == NULL)
return;
keyboard_trans_table &table = keyboard_trans_table::instance();
// populate it
for (int keynum = 0; keynum < MAX_KEYS; keynum++)
{
input_item_id itemid = table.map_di_scancode_to_itemid(keynum);
TCHAR keyname[100];
char *name;
// generate the name
if (GetKeyNameText(((keynum & 0x7f) << 16) | ((keynum & 0x80) << 17), keyname, ARRAY_LENGTH(keyname)) == 0)
_sntprintf(keyname, ARRAY_LENGTH(keyname), TEXT("Scan%03d"), keynum);
name = utf8_from_tstring(keyname);
// add the item to the device
devinfo->device()->add_item(name, itemid, generic_button_get_state, &devinfo->keyboard.state[keynum]);
osd_free(name);
}
}
};
//============================================================
// mouse_input_rawinput - rawinput mouse module
//============================================================
class mouse_input_rawinput : public rawinput_module
{
public:
mouse_input_rawinput()
: rawinput_module(OSD_MOUSEINPUT_PROVIDER, "rawinput")
{
}
protected:
USHORT usagepage() { return 1; }
USHORT usage() { return 2; }
void add_rawinput_device(running_machine& machine, RAWINPUTDEVICELIST * device) override
{
// make sure this is a mouse
if (device->dwType != RIM_TYPEMOUSE)
return;
// allocate and link in a new device
rawinput_mouse_device *devinfo = create_rawinput_device<rawinput_mouse_device>(machine, device);
if (devinfo == NULL)
return;
// populate the axes
for (int axisnum = 0; axisnum < 3; axisnum++)
{
devinfo->device()->add_item(default_axis_name[axisnum], (input_item_id)(ITEM_ID_XAXIS + axisnum), generic_axis_get_state, &devinfo->mouse.lX + axisnum);
}
// populate the buttons
for (int butnum = 0; butnum < 5; butnum++)
{
devinfo->device()->add_item(default_button_name(butnum), (input_item_id)(ITEM_ID_BUTTON1 + butnum), generic_button_get_state, &devinfo->mouse.rgbButtons[butnum]);
}
}
};
#else
MODULE_NOT_SUPPORTED(keyboard_input_rawinput, OSD_KEYBOARDINPUT_PROVIDER, "rawinput")
MODULE_NOT_SUPPORTED(mouse_input_rawinput, OSD_MOUSEINPUT_PROVIDER, "rawinput")
//MODULE_NOT_SUPPORTED(lightgun_input_rawinput, OSD_LIGHTGUNINPUT_PROVIDER, "rawinput")
#endif
MODULE_DEFINITION(KEYBOARDINPUT_RAWINPUT, keyboard_input_rawinput)
MODULE_DEFINITION(MOUSEINPUT_RAWINPUT, mouse_input_rawinput)
//MODULE_DEFINITION(LIGHTGUNINPUT_RAWINPUT, lightgun_input_rawinput)

View File

@ -0,0 +1,843 @@
// license:BSD-3-Clause
// copyright-holders:Olivier Galibert, R. Belmont, Brad Hughes
//============================================================
//
// input_sdl.cpp - SDL 2.0 implementation of MAME input routines
//
// SDLMAME by Olivier Galibert and R. Belmont
//
// SixAxis info: left analog is axes 0 & 1, right analog is axes 2 & 3,
// analog L2 is axis 12 and analog L3 is axis 13
//
//============================================================
#include "input_module.h"
#include "modules/osdmodule.h"
#if defined(SDLMAME_SDL2)
// standard sdl header
#include "sdlinc.h"
#include <ctype.h>
#include <stddef.h>
#include <mutex>
#include <memory>
#include <queue>
// MAME headers
#include "emu.h"
#include "osdepend.h"
#include "ui/ui.h"
#include "uiinput.h"
#include "strconv.h"
// MAMEOS headers
#include "input_common.h"
#include "../lib/osdobj_common.h"
#include "input_sdlcommon.h"
#include "../../sdl/osdsdl.h"
#include "../../sdl/window.h"
// winnt.h defines this
#ifdef DELETE
#undef DELETE
#endif
// FIXME: sdl does not properly report the window for certain OS.
#define GET_FOCUS_WINDOW(ev) focus_window()
//#define GET_FOCUS_WINDOW(ev) window_from_id((ev)->windowID)
struct key_lookup_table
{
int code;
const char *name;
};
#define KE(x) { SDL_SCANCODE_ ## x, "SDL_SCANCODE_" #x },
#define KE8(A, B, C, D, E, F, G, H) KE(A) KE(B) KE(C) KE(D) KE(E) KE(F) KE(G) KE(H)
#define KE7(A, B, C, D, E, F, G) KE(A) KE(B) KE(C) KE(D) KE(E) KE(F) KE(G)
#define KE5(A, B, C, D, E) KE(A) KE(B) KE(C) KE(D) KE(E)
#define KE3(A, B, C) KE(A) KE(B) KE(C)
static key_lookup_table sdl_lookup_table[] =
{
KE7(UNKNOWN, BACKSPACE, TAB, CLEAR, RETURN, PAUSE, ESCAPE)
KE(SPACE)
KE5(COMMA, MINUS, PERIOD, SLASH, 0)
KE8(1, 2, 3, 4, 5, 6, 7, 8)
KE3(9, SEMICOLON, EQUALS)
KE5(LEFTBRACKET,BACKSLASH, RIGHTBRACKET, A, B)
KE8(C, D, E, F, G, H, I, J)
KE8(K, L, M, N, O, P, Q, R)
KE8(S, T, U, V, W, X, Y, Z)
KE8(DELETE, KP_0, KP_1, KP_2, KP_3, KP_4, KP_5, KP_6)
KE8(KP_7, KP_8, KP_9, KP_PERIOD, KP_DIVIDE, KP_MULTIPLY,KP_MINUS, KP_PLUS)
KE8(KP_ENTER, KP_EQUALS, UP, DOWN, RIGHT, LEFT, INSERT, HOME)
KE8(END, PAGEUP, PAGEDOWN, F1, F2, F3, F4, F5)
KE8(F6, F7, F8, F9, F10, F11, F12, F13)
KE8(F14, F15, NUMLOCKCLEAR, CAPSLOCK, SCROLLLOCK, RSHIFT, LSHIFT, RCTRL)
KE5(LCTRL, RALT, LALT, LGUI, RGUI)
KE8(GRAVE, LEFTBRACKET,RIGHTBRACKET, SEMICOLON, APOSTROPHE, BACKSLASH, PRINTSCREEN,MENU)
KE(UNDO)
{
-1, ""
}
};
//============================================================
// lookup_sdl_code
//============================================================
static int lookup_sdl_code(const char *scode)
{
int i = 0;
while (sdl_lookup_table[i].code >= 0)
{
if (!strcmp(scode, sdl_lookup_table[i].name))
return sdl_lookup_table[i].code;
i++;
}
return -1;
}
//============================================================
// sdl_device
//============================================================
class sdl_device : public event_based_device<SDL_Event>
{
public:
sdl_device(running_machine &machine, const char* name, input_device_class devclass, input_module &module)
: event_based_device(machine, name, devclass, module)
{
}
protected:
sdl_window_info * focus_window()
{
return sdl_event_manager::instance().focus_window();
}
};
//============================================================
// sdl_keyboard_device
//============================================================
#define OSD_SDL_INDEX_KEYSYM(keysym) ((keysym)->scancode)
class sdl_keyboard_device : public sdl_device
{
public:
keyboard_state keyboard;
sdl_keyboard_device(running_machine &machine, const char* name, input_module &module)
: sdl_device(machine, name, DEVICE_CLASS_KEYBOARD, module),
keyboard({{0}})
{
}
void process_event(SDL_Event &sdlevent) override
{
switch (sdlevent.type)
{
case SDL_KEYDOWN:
keyboard.state[OSD_SDL_INDEX_KEYSYM(&sdlevent.key.keysym)] = 0x80;
if (sdlevent.key.keysym.sym < 0x20)
machine().ui_input().push_char_event(sdl_window_list->target(), sdlevent.key.keysym.sym);
break;
case SDL_KEYUP:
keyboard.state[OSD_SDL_INDEX_KEYSYM(&sdlevent.key.keysym)] = 0x00;
break;
case SDL_TEXTINPUT:
if (*sdlevent.text.text)
{
sdl_window_info *window = GET_FOCUS_WINDOW(&event.text);
//printf("Focus window is %p - wl %p\n", window, sdl_window_list);
unicode_char result;
if (window != NULL)
{
osd_uchar_from_osdchar(&result, sdlevent.text.text, 1);
machine().ui_input().push_char_event(window->target(), result);
}
}
break;
}
}
void reset() override
{
memset(&keyboard.state, 0, sizeof(keyboard.state));
}
};
//============================================================
// sdl_mouse_device
//============================================================
class sdl_mouse_device : public sdl_device
{
public:
mouse_state mouse;
sdl_mouse_device(running_machine &machine, const char* name, input_module &module)
: sdl_device(machine, name, DEVICE_CLASS_MOUSE, module),
mouse({0})
{
}
void reset() override
{
memset(&mouse, 0, sizeof(mouse));
}
void poll() override
{
mouse.lX = 0;
mouse.lY = 0;
sdl_device::poll();
}
virtual void process_event(SDL_Event &sdlevent) override
{
switch (sdlevent.type)
{
case SDL_MOUSEMOTION:
mouse.lX += sdlevent.motion.xrel * INPUT_RELATIVE_PER_PIXEL;
mouse.lY += sdlevent.motion.yrel * INPUT_RELATIVE_PER_PIXEL;
{
int cx = -1, cy = -1;
sdl_window_info *window = GET_FOCUS_WINDOW(&sdlevent.motion);
if (window != NULL && window->xy_to_render_target(sdlevent.motion.x, sdlevent.motion.y, &cx, &cy))
machine().ui_input().push_mouse_move_event(window->target(), cx, cy);
}
break;
case SDL_MOUSEBUTTONDOWN:
mouse.buttons[sdlevent.button.button - 1] = 0x80;
//printf("But down %d %d %d %d %s\n", event.button.which, event.button.button, event.button.x, event.button.y, devinfo->name.c_str());
if (sdlevent.button.button == 1)
{
// FIXME Move static declaration
static osd_ticks_t last_click = 0;
static int last_x = 0;
static int last_y = 0;
int cx, cy;
osd_ticks_t click = osd_ticks() * 1000 / osd_ticks_per_second();
sdl_window_info *window = GET_FOCUS_WINDOW(&sdlevent.button);
if (window != NULL && window->xy_to_render_target(sdlevent.button.x, sdlevent.button.y, &cx, &cy))
{
machine().ui_input().push_mouse_down_event(window->target(), cx, cy);
// FIXME Parameter ?
if ((click - last_click < 250)
&& (cx >= last_x - 4 && cx <= last_x + 4)
&& (cy >= last_y - 4 && cy <= last_y + 4))
{
last_click = 0;
machine().ui_input().push_mouse_double_click_event(window->target(), cx, cy);
}
else
{
last_click = click;
last_x = cx;
last_y = cy;
}
}
}
break;
case SDL_MOUSEBUTTONUP:
mouse.buttons[sdlevent.button.button - 1] = 0;
//printf("But up %d %d %d %d\n", event.button.which, event.button.button, event.button.x, event.button.y);
if (sdlevent.button.button == 1)
{
int cx, cy;
sdl_window_info *window = GET_FOCUS_WINDOW(&sdlevent.button);
if (window != NULL && window->xy_to_render_target(sdlevent.button.x, sdlevent.button.y, &cx, &cy))
{
machine().ui_input().push_mouse_up_event(window->target(), cx, cy);
}
}
break;
case SDL_MOUSEWHEEL:
sdl_window_info *window = GET_FOCUS_WINDOW(&sdlevent.wheel);
if (window != NULL)
machine().ui_input().push_mouse_wheel_event(window->target(), 0, 0, sdlevent.wheel.y, 3);
break;
}
}
};
//============================================================
// sdl_joystick_device
//============================================================
// state information for a joystick
struct sdl_joystick_state
{
INT32 axes[MAX_AXES];
INT32 buttons[MAX_BUTTONS];
INT32 hatsU[MAX_HATS], hatsD[MAX_HATS], hatsL[MAX_HATS], hatsR[MAX_HATS];
INT32 balls[MAX_AXES];
};
struct sdl_api_state
{
SDL_Joystick *device;
SDL_JoystickID joystick_id;
};
class sdl_joystick_device : public sdl_device
{
public:
sdl_joystick_state joystick;
sdl_api_state sdl_state;
sdl_joystick_device(running_machine &machine, const char *name, input_module &module)
: sdl_device(machine, name, DEVICE_CLASS_JOYSTICK, module),
joystick({{0}}),
sdl_state({0})
{
}
~sdl_joystick_device()
{
if (sdl_state.device != nullptr)
{
SDL_JoystickClose(sdl_state.device);
sdl_state.device = nullptr;
}
}
void reset() override
{
memset(&joystick, 0, sizeof(joystick));
}
void process_event(SDL_Event &sdlevent) override
{
switch (sdlevent.type)
{
case SDL_JOYAXISMOTION:
joystick.axes[sdlevent.jaxis.axis] = (sdlevent.jaxis.value * 2);
break;
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;
break;
case SDL_JOYHATMOTION:
if (sdlevent.jhat.value & SDL_HAT_UP)
{
joystick.hatsU[sdlevent.jhat.hat] = 0x80;
}
else
{
joystick.hatsU[sdlevent.jhat.hat] = 0;
}
if (sdlevent.jhat.value & SDL_HAT_DOWN)
{
joystick.hatsD[sdlevent.jhat.hat] = 0x80;
}
else
{
joystick.hatsD[sdlevent.jhat.hat] = 0;
}
if (sdlevent.jhat.value & SDL_HAT_LEFT)
{
joystick.hatsL[sdlevent.jhat.hat] = 0x80;
}
else
{
joystick.hatsL[sdlevent.jhat.hat] = 0;
}
if (sdlevent.jhat.value & SDL_HAT_RIGHT)
{
joystick.hatsR[sdlevent.jhat.hat] = 0x80;
}
else
{
joystick.hatsR[sdlevent.jhat.hat] = 0;
}
break;
case SDL_JOYBUTTONDOWN:
case SDL_JOYBUTTONUP:
joystick.buttons[sdlevent.jbutton.button] = (sdlevent.jbutton.state == SDL_PRESSED) ? 0x80 : 0;
break;
}
}
};
class sdl_sixaxis_joystick_device : public sdl_joystick_device
{
public:
sdl_sixaxis_joystick_device(running_machine &machine, const char *name, input_module &module)
: sdl_joystick_device(machine, name, module)
{
}
void process_event(SDL_Event &sdlevent) override
{
switch (sdlevent.type)
{
case SDL_JOYAXISMOTION:
{
int axis = sdlevent.jaxis.axis;
if (axis <= 3)
{
joystick.axes[sdlevent.jaxis.axis] = (sdlevent.jaxis.value * 2);
}
else
{
int magic = (sdlevent.jaxis.value / 2) + 16384;
joystick.axes[sdlevent.jaxis.axis] = magic;
}
}
break;
default:
// Call the base for other events
sdl_joystick_device::process_event(sdlevent);
break;
}
}
};
//============================================================
// sdl_input_module
//============================================================
class sdl_input_module : public input_module_base, public sdl_event_subscriber
{
public:
sdl_input_module(const char *type)
: input_module_base(type, "sdl")
{
}
void input_init(running_machine &machine) override
{
if (machine.debug_flags & DEBUG_FLAG_OSD_ENABLED)
{
osd_printf_warning("Debug Build: Disabling input grab for -debug\n");
set_mouse_enabled(false);
}
}
void before_poll(running_machine& machine) override
{
// Tell the event manager to process events and push them to the devices
sdl_event_manager::instance().process_events(machine);
}
bool should_poll_devices(running_machine& machine) override
{
return sdl_event_manager::instance().app_has_mouse_focus() && input_enabled();
}
virtual void handle_event(SDL_Event &sdlevent) override
{
// By default dispatch event to every device
for (int i = 0; i < devicelist()->size(); i++)
downcast<sdl_device*>(devicelist()->at(i))->queue_events(&sdlevent, 1);
}
};
//============================================================
// sdl_keyboard_module
//============================================================
class sdl_keyboard_module : public sdl_input_module
{
keyboard_trans_table * m_key_trans_table;
public:
sdl_keyboard_module()
: sdl_input_module(OSD_KEYBOARDINPUT_PROVIDER)
{
}
void input_init(running_machine &machine) override
{
sdl_input_module::input_init(machine);
SDL_EventType event_types[] = { SDL_KEYDOWN, SDL_KEYUP, SDL_TEXTINPUT };
sdl_event_manager::instance().subscribe(reinterpret_cast<int*>(event_types), ARRAY_LENGTH(event_types), this);
sdl_keyboard_device *devinfo;
// Read our keymap and store a pointer to our table
m_key_trans_table = sdlinput_read_keymap(machine);
keyboard_trans_table& local_table = *m_key_trans_table;
osd_printf_verbose("Keyboard: Start initialization\n");
// SDL only has 1 keyboard add it now
devinfo = devicelist()->create_device<sdl_keyboard_device>(machine, "System keyboard", *this);
// populate it
for (int keynum = 0; local_table[keynum].mame_key != ITEM_ID_INVALID; keynum++)
{
input_item_id itemid = local_table[keynum].mame_key;
// generate the default / modified name
char defname[20];
snprintf(defname, sizeof(defname) - 1, "%s", local_table[keynum].ui_name);
devinfo->device()->add_item(defname, itemid, generic_button_get_state, &devinfo->keyboard.state[local_table[keynum].sdl_scancode]);
}
osd_printf_verbose("Keyboard: Registered %s\n", devinfo->name());
osd_printf_verbose("Keyboard: End initialization\n");
}
private:
static keyboard_trans_table* sdlinput_read_keymap(running_machine &machine)
{
char *keymap_filename;
FILE *keymap_file;
int line = 1;
int index, i, sk, vk, ak;
char buf[256];
char mks[41];
char sks[41];
char kns[41];
int sdl2section = 0;
keyboard_trans_table &default_table = keyboard_trans_table::instance();
if (!machine.options().bool_value(SDLOPTION_KEYMAP))
return &default_table;
keymap_filename = (char *)downcast<sdl_options &>(machine.options()).keymap_file();
osd_printf_verbose("Keymap: Start reading keymap_file %s\n", keymap_filename);
keymap_file = fopen(keymap_filename, "r");
if (keymap_file == NULL)
{
osd_printf_warning("Keymap: Unable to open keymap %s, using default\n", keymap_filename);
return &default_table;
}
// Allocate a block of translation entries big enough to hold what's in the default table
auto key_trans_entries = std::make_unique<key_trans_entry[]>(default_table.size());
// copy the elements from the default table
for (int i = 0; i < default_table.size(); i++)
key_trans_entries[i] = default_table[i];
// Allocate the trans table to be associated with the machine so we don't have to free it
keyboard_trans_table *custom_table = auto_alloc(machine, keyboard_trans_table(std::move(key_trans_entries), default_table.size()));
while (!feof(keymap_file))
{
char *ret = fgets(buf, 255, keymap_file);
if (ret && buf[0] != '\n' && buf[0] != '#')
{
buf[255] = 0;
i = strlen(buf);
if (i && buf[i - 1] == '\n')
buf[i - 1] = 0;
if (strncmp(buf, "[SDL2]", 6) == 0)
{
sdl2section = 1;
}
else if (((SDLMAME_SDL2) ^ sdl2section) == 0)
{
mks[0] = 0;
sks[0] = 0;
memset(kns, 0, ARRAY_LENGTH(kns));
sscanf(buf, "%40s %40s %x %x %40c\n",
mks, sks, &vk, &ak, kns);
index = default_table.lookup_mame_index(mks);
sk = lookup_sdl_code(sks);
if (sk >= 0 && index >= 0)
{
key_trans_entry &entry = (*custom_table)[index];
entry.sdl_key = sk;
// vk and ak are not really needed
//key_trans_table[index][VIRTUAL_KEY] = vk;
//key_trans_table[index][ASCII_KEY] = ak;
entry.ui_name = auto_alloc_array(machine, char, strlen(kns) + 1);
strcpy(entry.ui_name, kns);
osd_printf_verbose("Keymap: Mapped <%s> to <%s> with ui-text <%s>\n", sks, mks, kns);
}
else
osd_printf_warning("Keymap: Error on line %d - %s key not found: %s\n", line, (sk<0) ? "sdl" : "mame", buf);
}
}
line++;
}
fclose(keymap_file);
osd_printf_verbose("Keymap: Processed %d lines\n", line);
return custom_table;
}
};
//============================================================
// sdl_mouse_module
//============================================================
class sdl_mouse_module : public sdl_input_module
{
public:
sdl_mouse_module()
: sdl_input_module(OSD_MOUSEINPUT_PROVIDER)
{
}
virtual void input_init(running_machine &machine) override
{
sdl_input_module::input_init(machine);
SDL_EventType event_types[] = { SDL_MOUSEMOTION, SDL_MOUSEBUTTONDOWN, SDL_MOUSEBUTTONUP, SDL_MOUSEWHEEL };
sdl_event_manager::instance().subscribe(reinterpret_cast<int*>(event_types), ARRAY_LENGTH(event_types), this);
sdl_mouse_device *devinfo;
char defname[20];
int button;
osd_printf_verbose("Mouse: Start initialization\n");
// SDL currently only supports one mouse
devinfo = devicelist()->create_device<sdl_mouse_device>(machine, "System mouse", *this);
// add the axes
devinfo->device()->add_item("X", ITEM_ID_XAXIS, generic_axis_get_state, &devinfo->mouse.lX);
devinfo->device()->add_item("Y", ITEM_ID_YAXIS, generic_axis_get_state, &devinfo->mouse.lY);
for (button = 0; button < 4; button++)
{
input_item_id itemid = (input_item_id)(ITEM_ID_BUTTON1 + button);
snprintf(defname, sizeof(defname), "B%d", button + 1);
devinfo->device()->add_item(defname, itemid, generic_button_get_state, &devinfo->mouse.buttons[button]);
}
osd_printf_verbose("Mouse: Registered %s\n", devinfo->name());
osd_printf_verbose("Mouse: End initialization\n");
}
};
static void devmap_register(device_map_t *devmap, int physical_idx, const std::string &name)
{
int found = 0;
int stick, i;
for (i = 0; i < MAX_DEVMAP_ENTRIES; i++)
{
if (strcmp(name.c_str(), devmap->map[i].name.c_str()) == 0 && devmap->map[i].physical < 0)
{
devmap->map[i].physical = physical_idx;
found = 1;
devmap->logical[physical_idx] = i;
}
}
if (found == 0)
{
stick = devmap_leastfree(devmap);
devmap->map[stick].physical = physical_idx;
devmap->map[stick].name = name;
devmap->logical[physical_idx] = stick;
}
}
//============================================================
// sdl_joystick_module
//============================================================
class sdl_joystick_module : public sdl_input_module
{
private:
device_map_t m_joy_map;
bool m_sixaxis_mode;
public:
sdl_joystick_module()
: sdl_input_module(OSD_JOYSTICKINPUT_PROVIDER)
{
}
virtual void input_init(running_machine &machine) override
{
sdl_input_module::input_init(machine);
char tempname[512];
m_sixaxis_mode = downcast<const sdl_options*>(options())->sixaxis();
devmap_init(machine, &m_joy_map, SDLOPTION_JOYINDEX, 8, "Joystick mapping");
osd_printf_verbose("Joystick: Start initialization\n");
int physical_stick;
for (physical_stick = 0; physical_stick < SDL_NumJoysticks(); physical_stick++)
{
SDL_Joystick *joy = SDL_JoystickOpen(physical_stick);
std::string joy_name = remove_spaces(SDL_JoystickName(joy));
SDL_JoystickClose(joy);
devmap_register(&m_joy_map, physical_stick, joy_name.c_str());
}
for (int stick = 0; stick < MAX_DEVMAP_ENTRIES; stick++)
{
sdl_joystick_device *devinfo = create_joystick_device(machine, &m_joy_map, stick, DEVICE_CLASS_JOYSTICK);
if (devinfo == NULL)
continue;
physical_stick = m_joy_map.map[stick].physical;
SDL_Joystick *joy = SDL_JoystickOpen(physical_stick);
devinfo->sdl_state.device = joy;
devinfo->sdl_state.joystick_id = SDL_JoystickInstanceID(joy);
osd_printf_verbose("Joystick: %s\n", devinfo->name());
osd_printf_verbose("Joystick: ... %d axes, %d buttons %d hats %d balls\n", SDL_JoystickNumAxes(joy), SDL_JoystickNumButtons(joy), SDL_JoystickNumHats(joy), SDL_JoystickNumBalls(joy));
osd_printf_verbose("Joystick: ... Physical id %d mapped to logical id %d\n", physical_stick, stick + 1);
// loop over all axes
for (int axis = 0; axis < SDL_JoystickNumAxes(joy); axis++)
{
input_item_id itemid;
if (axis < INPUT_MAX_AXIS)
itemid = (input_item_id)(ITEM_ID_XAXIS + axis);
else if (axis < INPUT_MAX_AXIS + INPUT_MAX_ADD_ABSOLUTE)
itemid = (input_item_id)(ITEM_ID_ADD_ABSOLUTE1 - INPUT_MAX_AXIS + axis);
else
itemid = ITEM_ID_OTHER_AXIS_ABSOLUTE;
snprintf(tempname, sizeof(tempname), "A%d %s", axis, devinfo->name());
devinfo->device()->add_item(tempname, itemid, generic_axis_get_state, &devinfo->joystick.axes[axis]);
}
// loop over all buttons
for (int button = 0; button < SDL_JoystickNumButtons(joy); button++)
{
input_item_id itemid;
devinfo->joystick.buttons[button] = 0;
if (button < INPUT_MAX_BUTTONS)
itemid = (input_item_id)(ITEM_ID_BUTTON1 + button);
else if (button < INPUT_MAX_BUTTONS + INPUT_MAX_ADD_SWITCH)
itemid = (input_item_id)(ITEM_ID_ADD_SWITCH1 - INPUT_MAX_BUTTONS + button);
else
itemid = ITEM_ID_OTHER_SWITCH;
snprintf(tempname, sizeof(tempname), "button %d", button);
devinfo->device()->add_item(tempname, itemid, generic_button_get_state, &devinfo->joystick.buttons[button]);
}
// loop over all hats
for (int hat = 0; hat < SDL_JoystickNumHats(joy); hat++)
{
input_item_id itemid;
snprintf(tempname, sizeof(tempname), "hat %d Up", hat);
itemid = (input_item_id)((hat < INPUT_MAX_HATS) ? ITEM_ID_HAT1UP + 4 * hat : ITEM_ID_OTHER_SWITCH);
devinfo->device()->add_item(tempname, itemid, generic_button_get_state, &devinfo->joystick.hatsU[hat]);
snprintf(tempname, sizeof(tempname), "hat %d Down", hat);
itemid = (input_item_id)((hat < INPUT_MAX_HATS) ? ITEM_ID_HAT1DOWN + 4 * hat : ITEM_ID_OTHER_SWITCH);
devinfo->device()->add_item(tempname, itemid, generic_button_get_state, &devinfo->joystick.hatsD[hat]);
snprintf(tempname, sizeof(tempname), "hat %d Left", hat);
itemid = (input_item_id)((hat < INPUT_MAX_HATS) ? ITEM_ID_HAT1LEFT + 4 * hat : ITEM_ID_OTHER_SWITCH);
devinfo->device()->add_item(tempname, itemid, generic_button_get_state, &devinfo->joystick.hatsL[hat]);
snprintf(tempname, sizeof(tempname), "hat %d Right", hat);
itemid = (input_item_id)((hat < INPUT_MAX_HATS) ? ITEM_ID_HAT1RIGHT + 4 * hat : ITEM_ID_OTHER_SWITCH);
devinfo->device()->add_item(tempname, itemid, generic_button_get_state, &devinfo->joystick.hatsR[hat]);
}
// loop over all (track)balls
for (int ball = 0; ball < SDL_JoystickNumBalls(joy); ball++)
{
int itemid;
if (ball * 2 < INPUT_MAX_ADD_RELATIVE)
itemid = ITEM_ID_ADD_RELATIVE1 + ball * 2;
else
itemid = ITEM_ID_OTHER_AXIS_RELATIVE;
snprintf(tempname, sizeof(tempname), "R%d %s", ball * 2, devinfo->name());
devinfo->device()->add_item(tempname, (input_item_id)itemid, generic_axis_get_state, &devinfo->joystick.balls[ball * 2]);
snprintf(tempname, sizeof(tempname), "R%d %s", ball * 2 + 1, devinfo->name());
devinfo->device()->add_item(tempname, (input_item_id)(itemid + 1), generic_axis_get_state, &devinfo->joystick.balls[ball * 2 + 1]);
}
}
SDL_EventType event_types[] = { SDL_JOYAXISMOTION, SDL_JOYBALLMOTION, SDL_JOYHATMOTION, SDL_JOYBUTTONDOWN, SDL_JOYBUTTONUP };
sdl_event_manager::instance().subscribe(reinterpret_cast<int*>(event_types), ARRAY_LENGTH(event_types), this);
osd_printf_verbose("Joystick: End initialization\n");
}
virtual void handle_event(SDL_Event &sdlevent) override
{
// Figure out which joystick this event id destined for
for (int i = 0; i < devicelist()->size(); i++)
{
auto joy = downcast<sdl_joystick_device*>(devicelist()->at(i));
// If we find a matching joystick, dispatch the event to the joystick
if (joy->sdl_state.joystick_id == sdlevent.jdevice.which)
joy->queue_events(&sdlevent, 1);
}
}
private:
sdl_joystick_device* create_joystick_device(running_machine &machine, device_map_t *devmap, int index, input_device_class devclass)
{
sdl_joystick_device *devinfo = NULL;
char tempname[20];
if (devmap->map[index].name.length() == 0)
{
/* only map place holders if there were mappings specified is enabled */
if (devmap->initialized)
{
snprintf(tempname, ARRAY_LENGTH(tempname), "NC%d", index);
devinfo = m_sixaxis_mode
? devicelist()->create_device<sdl_sixaxis_joystick_device>(machine, tempname, *this)
: devicelist()->create_device<sdl_joystick_device>(machine, tempname, *this);
}
return NULL;
}
else
{
devinfo = m_sixaxis_mode
? devicelist()->create_device<sdl_sixaxis_joystick_device>(machine, devmap->map[index].name.c_str(), *this)
: devicelist()->create_device<sdl_joystick_device>(machine, devmap->map[index].name.c_str(), *this);
}
return devinfo;
}
};
#else
MODULE_NOT_SUPPORTED(sdl_keyboard_module, OSD_KEYBOARDINPUT_PROVIDER, "sdl")
MODULE_NOT_SUPPORTED(sdl_mouse_module, OSD_MOUSEINPUT_PROVIDER, "sdl")
MODULE_NOT_SUPPORTED(sdl_joystick_module, OSD_JOYSTICKINPUT_PROVIDER, "sdl")
#endif
MODULE_DEFINITION(KEYBOARDINPUT_SDL, sdl_keyboard_module)
MODULE_DEFINITION(MOUSEINPUT_SDL, sdl_mouse_module)
MODULE_DEFINITION(JOYSTICKINPUT_SDL, sdl_joystick_module)

View File

@ -0,0 +1,283 @@
// license:BSD-3-Clause
// copyright-holders:Olivier Galibert, R. Belmont, Brad Hughes
//============================================================
//
// input_sdlcommon.cpp - SDL Common code shared by SDL modules
//
// Note: this code is also used by the X11 input modules
//
//============================================================
#include "input_module.h"
#include "modules/osdmodule.h"
#if defined(OSD_SDL)
// standard sdl header
#include "sdlinc.h"
#include <ctype.h>
#include <stddef.h>
#include <mutex>
#include <memory>
// MAME headers
#include "emu.h"
#include "osdepend.h"
#include "ui/ui.h"
#include "uiinput.h"
#include "window.h"
#include "strconv.h"
#include "../../sdl/osdsdl.h"
#include "input_common.h"
#include "input_sdlcommon.h"
#define GET_WINDOW(ev) window_from_id((ev)->windowID)
//#define GET_WINDOW(ev) ((ev)->windowID)
static inline sdl_window_info * window_from_id(Uint32 windowID)
{
sdl_window_info *w;
SDL_Window *window = SDL_GetWindowFromID(windowID);
for (w = sdl_window_list; w != NULL; w = w->m_next)
{
//printf("w->window_id: %d\n", w->window_id);
if (w->sdl_window() == window)
{
return w;
}
}
return NULL;
}
void sdl_event_manager::process_events(running_machine &machine)
{
std::lock_guard<std::mutex> scope_lock(m_lock);
SDL_Event sdlevent;
while (SDL_PollEvent(&sdlevent))
{
// process window events if they come in
if (sdlevent.type == SDL_WINDOWEVENT)
process_window_event(machine, sdlevent);
// Find all subscribers for the event type
auto subscribers = m_subscription_index.equal_range(sdlevent.type);
// Dispatch the events
for (auto iter = subscribers.first; iter != subscribers.second; iter++)
iter->second->handle_event(sdlevent);
}
}
void sdl_event_manager::process_window_event(running_machine &machine, SDL_Event &sdlevent)
{
sdl_window_info *window = GET_WINDOW(&sdlevent.window);
if (window == NULL)
return;
switch (sdlevent.window.event)
{
case SDL_WINDOWEVENT_CLOSE:
machine.schedule_exit();
break;
case SDL_WINDOWEVENT_LEAVE:
machine.ui_input().push_mouse_leave_event(window->target());
m_app_has_mouse_focus = 0;
break;
case SDL_WINDOWEVENT_MOVED:
window->notify_changed();
m_focus_window = window;
break;
case SDL_WINDOWEVENT_RESIZED:
#ifndef SDLMAME_WIN32
/* FIXME: SDL2 sends some spurious resize events on Ubuntu
* while in fullscreen mode. Ignore them for now.
*/
if (!window->fullscreen())
#endif
{
//printf("event data1,data2 %d x %d %ld\n", event.window.data1, event.window.data2, sizeof(SDL_Event));
window->resize(sdlevent.window.data1, sdlevent.window.data2);
}
m_focus_window = window;
break;
case SDL_WINDOWEVENT_ENTER:
m_app_has_mouse_focus = 1;
/* fall through */
case SDL_WINDOWEVENT_FOCUS_GAINED:
case SDL_WINDOWEVENT_EXPOSED:
case SDL_WINDOWEVENT_MAXIMIZED:
case SDL_WINDOWEVENT_RESTORED:
m_focus_window = window;
break;
}
}
//============================================================
// customize_input_type_list
//============================================================
void sdl_osd_interface::customize_input_type_list(simple_list<input_type_entry> &typelist)
{
input_item_id mameid_code;
input_code ui_code;
input_type_entry *entry;
const char* uimode;
char fullmode[64];
// loop over the defaults
for (entry = typelist.first(); entry != NULL; entry = entry->next())
{
switch (entry->type())
{
// configurable UI mode switch
case IPT_UI_TOGGLE_UI:
uimode = options().ui_mode_key();
if (!strcmp(uimode, "auto"))
{
#if defined(__APPLE__) && defined(__MACH__)
mameid_code = keyboard_trans_table::instance().lookup_mame_code("ITEM_ID_INSERT");
#else
mameid_code = keyboard_trans_table::instance().lookup_mame_code("ITEM_ID_SCRLOCK");
#endif
}
else
{
snprintf(fullmode, 63, "ITEM_ID_%s", uimode);
mameid_code = keyboard_trans_table::instance().lookup_mame_code(fullmode);
}
ui_code = input_code(DEVICE_CLASS_KEYBOARD, 0, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, input_item_id(mameid_code));
entry->defseq(SEQ_TYPE_STANDARD).set(ui_code);
break;
// alt-enter for fullscreen
case IPT_OSD_1:
entry->configure_osd("TOGGLE_FULLSCREEN", "Toggle Fullscreen");
entry->defseq(SEQ_TYPE_STANDARD).set(KEYCODE_ENTER, KEYCODE_LALT);
break;
// disable UI_SELECT when LALT is down, this stops selecting
// things in the menu when toggling fullscreen with LALT+ENTER
/* case IPT_UI_SELECT:
entry->defseq(SEQ_TYPE_STANDARD).set(KEYCODE_ENTER, input_seq::not_code, KEYCODE_LALT);
break;*/
// page down for fastforward (must be OSD_3 as per src/emu/ui.c)
case IPT_UI_FAST_FORWARD:
entry->defseq(SEQ_TYPE_STANDARD).set(KEYCODE_PGDN);
break;
// OSD hotkeys use LCTRL and start at F3, they start at
// F3 because F1-F2 are hardcoded into many drivers to
// various dipswitches, and pressing them together with
// LCTRL will still press/toggle these dipswitches.
// LCTRL-F3 to toggle fullstretch
case IPT_OSD_2:
entry->configure_osd("TOGGLE_FULLSTRETCH", "Toggle Uneven stretch");
entry->defseq(SEQ_TYPE_STANDARD).set(KEYCODE_F3, KEYCODE_LCONTROL);
break;
// add a Not lcrtl condition to the reset key
case IPT_UI_SOFT_RESET:
entry->defseq(SEQ_TYPE_STANDARD).set(KEYCODE_F3, input_seq::not_code, KEYCODE_LCONTROL, input_seq::not_code, KEYCODE_LSHIFT);
break;
// LCTRL-F4 to toggle keep aspect
case IPT_OSD_4:
entry->configure_osd("TOGGLE_KEEP_ASPECT", "Toggle Keepaspect");
entry->defseq(SEQ_TYPE_STANDARD).set(KEYCODE_F4, KEYCODE_LCONTROL);
break;
// add a Not lcrtl condition to the show gfx key
case IPT_UI_SHOW_GFX:
entry->defseq(SEQ_TYPE_STANDARD).set(KEYCODE_F4, input_seq::not_code, KEYCODE_LCONTROL);
break;
// LCTRL-F5 to toggle OpenGL filtering
case IPT_OSD_5:
entry->configure_osd("TOGGLE_FILTER", "Toggle Filter");
entry->defseq(SEQ_TYPE_STANDARD).set(KEYCODE_F5, KEYCODE_LCONTROL);
break;
// add a Not lcrtl condition to the toggle debug key
case IPT_UI_TOGGLE_DEBUG:
entry->defseq(SEQ_TYPE_STANDARD).set(KEYCODE_F5, input_seq::not_code, KEYCODE_LCONTROL);
break;
// LCTRL-F6 to decrease OpenGL prescaling
case IPT_OSD_6:
entry->configure_osd("DECREASE_PRESCALE", "Decrease Prescaling");
entry->defseq(SEQ_TYPE_STANDARD).set(KEYCODE_F6, KEYCODE_LCONTROL);
break;
// add a Not lcrtl condition to the toggle cheat key
case IPT_UI_TOGGLE_CHEAT:
entry->defseq(SEQ_TYPE_STANDARD).set(KEYCODE_F6, input_seq::not_code, KEYCODE_LCONTROL);
break;
// LCTRL-F7 to increase OpenGL prescaling
case IPT_OSD_7:
entry->configure_osd("INCREASE_PRESCALE", "Increase Prescaling");
entry->defseq(SEQ_TYPE_STANDARD).set(KEYCODE_F7, KEYCODE_LCONTROL);
break;
// add a Not lcrtl condition to the load state key
case IPT_UI_LOAD_STATE:
entry->defseq(SEQ_TYPE_STANDARD).set(KEYCODE_F7, input_seq::not_code, KEYCODE_LCONTROL, input_seq::not_code, KEYCODE_LSHIFT);
break;
// add a Not lcrtl condition to the throttle key
case IPT_UI_THROTTLE:
entry->defseq(SEQ_TYPE_STANDARD).set(KEYCODE_F10, input_seq::not_code, KEYCODE_LCONTROL);
break;
// disable the config menu if the ALT key is down
// (allows ALT-TAB to switch between apps)
case IPT_UI_CONFIGURE:
entry->defseq(SEQ_TYPE_STANDARD).set(KEYCODE_TAB, input_seq::not_code, KEYCODE_LALT, input_seq::not_code, KEYCODE_RALT);
break;
// leave everything else alone
default:
break;
}
}
}
void sdl_osd_interface::poll_inputs(running_machine &machine)
{
m_keyboard_input->poll_if_necessary(machine);
m_mouse_input->poll_if_necessary(machine);
m_lightgun_input->poll_if_necessary(machine);
m_joystick_input->poll_if_necessary(machine);
}
void sdl_osd_interface::release_keys()
{
downcast<input_module_base*>(m_keyboard_input)->devicelist()->reset_devices();
}
bool sdl_osd_interface::should_hide_mouse()
{
// if we are paused, no
if (machine().paused())
return false;
// if neither mice nor lightguns enabled in the core, then no
if (!options().mouse() && !options().lightgun())
return false;
if (!sdl_event_manager::instance().app_has_mouse_focus())
return false;
// otherwise, yes
return true;
}
void sdl_osd_interface::process_events_buf()
{
SDL_PumpEvents();
}
#endif

View File

@ -0,0 +1,204 @@
// license:BSD-3-Clause
// copyright-holders:Olivier Galibert, R. Belmont, Brad Hughes
//============================================================
//
// input_sdlcommon.h - SDL Common code shared by SDL modules
//
// Note: this code is also used by the X11 input modules
//
//============================================================
#ifndef INPUT_SDLCOMMON_H_
#define INPUT_SDLCOMMON_H_
#include <vector>
#include <unordered_map>
#include <algorithm>
#include <queue>
#define MAX_DEVMAP_ENTRIES 16
#define SDL_MODULE_EVENT_BUFFER_SIZE 5
// state information for a keyboard
struct keyboard_state
{
INT32 state[0x3ff]; // must be INT32!
INT8 oldkey[MAX_KEYS];
INT8 currkey[MAX_KEYS];
};
// state information for a mouse
struct mouse_state
{
INT32 lX, lY;
INT32 buttons[MAX_BUTTONS];
};
// state information for a joystick; DirectInput state must be first element
struct joystick_state
{
SDL_Joystick *device;
INT32 axes[MAX_AXES];
INT32 buttons[MAX_BUTTONS];
INT32 hatsU[MAX_HATS], hatsD[MAX_HATS], hatsL[MAX_HATS], hatsR[MAX_HATS];
INT32 balls[MAX_AXES];
};
struct device_map_t
{
struct {
std::string name;
int physical;
} map[MAX_DEVMAP_ENTRIES];
int logical[MAX_DEVMAP_ENTRIES];
int initialized;
};
//============================================================
// event_manager_t
//============================================================
class sdl_event_subscriber
{
public:
virtual void handle_event(SDL_Event &sdlevent) = 0;
};
template <class TSubscriber>
class event_manager_t
{
protected:
std::mutex m_lock;
std::unordered_multimap<int, TSubscriber*> m_subscription_index;
event_manager_t()
{
}
public:
void subscribe(int* event_types, int num_event_types, TSubscriber *subscriber)
{
std::lock_guard<std::mutex> scope_lock(m_lock);
// Add the subscription
for (int i = 0; i < num_event_types; i++)
{
m_subscription_index.emplace(event_types[i], subscriber);
}
}
void unsubscribe(TSubscriber *subscriber)
{
std::lock_guard<std::mutex> scope_lock(m_lock);
// Loop over the entries and find ones that match our subscriber
// remove those that match
for (auto iter = m_subscription_index.begin(); iter != m_subscription_index.end(); iter++)
{
if (iter->second == subscriber)
m_subscription_index.erase(iter);
}
}
virtual void process_events(running_machine &machine) = 0;
};
class sdl_window_info;
// REVIEW: Do we need to handle SDLMAME_EVENTS_IN_WORKER_THREAD eventually?
class sdl_event_manager : public event_manager_t<sdl_event_subscriber>
{
private:
bool m_app_has_mouse_focus;
sdl_window_info * m_focus_window;
sdl_event_manager()
: m_app_has_mouse_focus(true),
m_focus_window(nullptr)
{
}
public:
bool app_has_mouse_focus() { return m_app_has_mouse_focus; }
sdl_window_info * focus_window() { return m_focus_window; }
static sdl_event_manager& instance()
{
static sdl_event_manager s_instance;
return s_instance;
}
void process_events(running_machine &machine) override;
private:
void process_window_event(running_machine &machine, SDL_Event &sdlevent);
};
//============================================================
// INLINE FUNCTIONS
//============================================================
static inline int devmap_leastfree(device_map_t *devmap)
{
int i;
for (i = 0; i < MAX_DEVMAP_ENTRIES; i++)
{
if (devmap->map[i].name.length() == 0)
return i;
}
return -1;
}
static inline std::string remove_spaces(const char *s)
{
// Remove the spaces
auto output = std::string(s);
output.erase(std::remove_if(output.begin(), output.end(), isspace), output.end());
return output;
}
//============================================================
// devmap_init - initializes a device_map based on
// an input option prefix and max number of devices
//============================================================
static inline void devmap_init(running_machine &machine, device_map_t *devmap, const char *opt, int max_devices, const char *label)
{
int dev;
char defname[20];
// The max devices the user specified, better not be bigger than the max the arrays can old
assert(max_devices <= MAX_DEVMAP_ENTRIES);
// Initialize the map to default uninitialized values
for (dev = 0; dev < MAX_DEVMAP_ENTRIES; dev++)
{
devmap->map[dev].physical = -1;
devmap->logical[dev] = -1;
}
devmap->initialized = 0;
// populate the device map up to the max number of devices
for (dev = 0; dev < max_devices; dev++)
{
const char *dev_name;
// derive the parameter name from the option name and index. For instance: lightgun_index1 to lightgun_index8
sprintf(defname, "%s%d", opt, dev + 1);
// Get the user-specified name that matches the parameter
dev_name = machine.options().value(defname);
// If they've specified a name and it's not "auto", treat it as a custom mapping
if (dev_name && *dev_name && strcmp(dev_name, OSDOPTVAL_AUTO))
{
// remove the spaces from the name store it in the index
devmap->map[dev].name = remove_spaces(dev_name);
osd_printf_verbose("%s: Logical id %d: %s\n", label, dev + 1, devmap->map[dev].name.c_str());
devmap->initialized = 1;
}
}
}
#endif

View File

@ -0,0 +1,427 @@
// license:BSD-3-Clause
// copyright-holders:Aaron Giles, Brad Hughes
//============================================================
//
// input_win32.cpp - Win32 input implementation
//
//============================================================
#include "input_module.h"
#include "modules/osdmodule.h"
#if defined(OSD_WINDOWS)
// standard windows headers
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <winioctl.h>
#include <tchar.h>
#undef interface
#include <mutex>
// MAME headers
#include "emu.h"
#include "osdepend.h"
#include "ui/ui.h"
#include "strconv.h"
// MAMEOS headers
#include "winmain.h"
#include "window.h"
#include "../../windows/input.h"
#include "input_common.h"
#include "input_windows.h"
//============================================================
// win32_keyboard_device
//============================================================
// This device is purely event driven so the implementation is in the module
class win32_keyboard_device : public event_based_device<KeyPressEventArgs>
{
public:
keyboard_state keyboard;
win32_keyboard_device(running_machine& machine, const char *name, input_module &module)
: event_based_device(machine, name, DEVICE_CLASS_KEYBOARD, module),
keyboard({0})
{
}
void reset() override
{
memset(&keyboard, 0, sizeof(keyboard));
}
protected:
void process_event(KeyPressEventArgs &args) override
{
keyboard.state[args.scancode] = args.event_id == INPUT_EVENT_KEYDOWN ? 0x80 : 0x00;
}
};
//============================================================
// keyboard_input_win32 - win32 keyboard input module
//============================================================
class keyboard_input_win32 : public wininput_module
{
private:
const osd_options * m_options;
public:
keyboard_input_win32()
: wininput_module(OSD_KEYBOARDINPUT_PROVIDER, "win32")
{
}
virtual void input_init(running_machine &machine) override
{
// Add a single win32 keyboard device that we'll monitor using Win32
win32_keyboard_device *devinfo = devicelist()->create_device<win32_keyboard_device>(machine, "Win32 Keyboard 1", *this);
keyboard_trans_table &table = keyboard_trans_table::instance();
// populate it
for (int keynum = 0; keynum < MAX_KEYS; keynum++)
{
input_item_id itemid = table.map_di_scancode_to_itemid(keynum);
char name[20];
// generate/fetch the name
_snprintf(name, ARRAY_LENGTH(name), "Scan%03d", keynum);
// add the item to the device
devinfo->device()->add_item(name, itemid, generic_button_get_state, &devinfo->keyboard.state[keynum]);
}
}
bool handle_input_event(input_event eventid, void *eventdata) override
{
if (!input_enabled())
return FALSE;
KeyPressEventArgs *args = nullptr;
switch (eventid)
{
case INPUT_EVENT_KEYDOWN:
case INPUT_EVENT_KEYUP:
args = (KeyPressEventArgs*)eventdata;
for (int i = 0; i < devicelist()->size(); i++)
downcast<win32_keyboard_device*>(devicelist()->at(i))->queue_events(args, 1);
return TRUE;
default:
return FALSE;
}
}
};
//============================================================
// win32_mouse_device
//============================================================
struct win32_mouse_state
{
POINT last_point;
};
class win32_mouse_device : public event_based_device<MouseButtonEventArgs>
{
public:
mouse_state mouse;
win32_mouse_state win32_mouse;
win32_mouse_device(running_machine& machine, const char *name, input_module &module)
: event_based_device(machine, name, DEVICE_CLASS_MOUSE, module),
mouse({0}),
win32_mouse({0})
{
}
void poll() override
{
event_based_device::poll();
CURSORINFO cursor_info = {0};
cursor_info.cbSize = sizeof(CURSORINFO);
GetCursorInfo(&cursor_info);
// We only take over the mouse if the cursor isn't showing
// This should happen anyway in mouse mode
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;
RECT window_pos = {0};
GetWindowRect(win_window_list->m_hwnd, &window_pos);
// We reset the cursor position to the middle of the window each frame
win32_mouse.last_point.x = window_pos.left + (window_pos.right - window_pos.left) / 2;
win32_mouse.last_point.y = window_pos.top + (window_pos.bottom - window_pos.top) / 2;
SetCursorPos(win32_mouse.last_point.x, win32_mouse.last_point.y);
}
}
void reset() override
{
memset(&mouse, 0, sizeof(mouse));
}
protected:
void process_event(MouseButtonEventArgs &args)
{
// set the button state
mouse.rgbButtons[args.button] = args.keydown ? 0x80 : 0x00;
// Make sure we have a fresh mouse position on button down
if (args.keydown)
module().poll_if_necessary(machine());
}
};
//============================================================
// mouse_input_win32 - win32 mouse input module
//============================================================
class mouse_input_win32 : public wininput_module
{
private:
const osd_options * m_options;
public:
mouse_input_win32()
: wininput_module(OSD_MOUSEINPUT_PROVIDER, "win32")
{
}
virtual void input_init(running_machine &machine) override
{
win32_mouse_device *devinfo;
int axisnum, butnum;
if (!input_enabled() || !mouse_enabled())
return;
// allocate a device
devinfo = devicelist()->create_device<win32_mouse_device>(machine, "Win32 Mouse 1", *this);
if (devinfo == NULL)
return;
// populate the axes
for (axisnum = 0; axisnum < 2; axisnum++)
{
devinfo->device()->add_item(default_axis_name[axisnum], (input_item_id)(ITEM_ID_XAXIS + axisnum), generic_axis_get_state, &devinfo->mouse.lX + axisnum);
}
// populate the buttons
for (butnum = 0; butnum < 2; butnum++)
{
devinfo->device()->add_item(default_button_name(butnum), (input_item_id)(ITEM_ID_BUTTON1 + butnum), generic_button_get_state, &devinfo->mouse.rgbButtons[butnum]);
}
}
bool handle_input_event(input_event eventid, void *eventdata) override
{
if (!input_enabled() || !mouse_enabled() || eventid != INPUT_EVENT_MOUSE_BUTTON)
return FALSE;
auto args = static_cast<MouseButtonEventArgs*>(eventdata);
for (int i = 0; i < devicelist()->size(); i++)
downcast<win32_mouse_device*>(devicelist()->at(i))->queue_events(args, 1);
return TRUE;
}
};
//============================================================
// win32_lightgun_device
//============================================================
class win32_lightgun_device : public event_based_device<MouseButtonEventArgs>
{
private:
BOOL m_lightgun_shared_axis_mode;
int m_gun_index;
public:
mouse_state mouse;
win32_lightgun_device(running_machine& machine, const char *name, input_module &module)
: event_based_device(machine, name, DEVICE_CLASS_LIGHTGUN, module),
m_lightgun_shared_axis_mode(FALSE),
m_gun_index(0)
{
m_lightgun_shared_axis_mode = downcast<windows_options &>(machine.options()).dual_lightgun();
// Since we are about to be added to the list, the current size is the zero-based index of where we will be
m_gun_index = downcast<wininput_module&>(module).devicelist()->size();
}
void poll() override
{
event_based_device::poll();
INT32 xpos = 0, ypos = 0;
POINT mousepos;
// if we are using the shared axis hack, the data is updated via Windows messages only
if (m_lightgun_shared_axis_mode)
return;
// get the cursor position and transform into final results
GetCursorPos(&mousepos);
if (win_window_list != NULL)
{
RECT client_rect;
// get the position relative to the window
GetClientRect(win_window_list->m_hwnd, &client_rect);
ScreenToClient(win_window_list->m_hwnd, &mousepos);
// convert to absolute coordinates
xpos = normalize_absolute_axis(mousepos.x, client_rect.left, client_rect.right);
ypos = normalize_absolute_axis(mousepos.y, client_rect.top, client_rect.bottom);
}
// update the X/Y positions
mouse.lX = xpos;
mouse.lY = ypos;
}
void reset() override
{
memset(&mouse, 0, sizeof(mouse));
}
protected:
void process_event(MouseButtonEventArgs &args)
{
// Are we in shared axis mode?
if (m_lightgun_shared_axis_mode)
{
handle_shared_axis_mode(args);
}
else
{
// In non-shared axis mode, just update the button state
mouse.rgbButtons[args.button] = args.keydown ? 0x80 : 0x00;
}
}
private:
void handle_shared_axis_mode(MouseButtonEventArgs &args)
{
int button = args.button;
// We only handle the first four buttons in shared axis mode
if (button > 3)
return;
// First gun doesn't handle buttons 2 & 3
if (button >= 2 && m_gun_index == 0)
return;
// Second gun doesn't handle buttons 0 & 1
if (button < 2 && m_gun_index == 1)
return;
// Adjust the button if we're the second lightgun
int logical_button = m_gun_index == 1 ? button - 2 : button;
// set the button state
mouse.rgbButtons[logical_button] = args.keydown ? 0x80 : 0x00;
if (args.keydown)
{
RECT client_rect;
POINT mousepos;
// get the position relative to the window
GetClientRect(win_window_list->m_hwnd, &client_rect);
mousepos.x = args.xpos;
mousepos.y = args.ypos;
ScreenToClient(win_window_list->m_hwnd, &mousepos);
// convert to absolute coordinates
mouse.lX = normalize_absolute_axis(mousepos.x, client_rect.left, client_rect.right);
mouse.lY = normalize_absolute_axis(mousepos.y, client_rect.top, client_rect.bottom);
}
}
};
//============================================================
// lightgun_input_win32 - win32 lightgun input module
//============================================================
class lightgun_input_win32 : public wininput_module
{
public:
lightgun_input_win32()
: wininput_module(OSD_LIGHTGUNINPUT_PROVIDER, "win32")
{
}
int init_internal() override
{
return 0;
}
virtual void input_init(running_machine &machine) override
{
int max_guns = downcast<windows_options&>(machine.options()).dual_lightgun() ? 2 : 1;
// allocate the lightgun devices
for (int gunnum = 0; gunnum < max_guns; gunnum++)
{
static const char *const gun_names[] = { "Win32 Gun 1", "Win32 Gun 2" };
win32_lightgun_device *devinfo;
int axisnum, butnum;
// allocate a device
devinfo = devicelist()->create_device<win32_lightgun_device>(machine, gun_names[gunnum], *this);
if (devinfo == NULL)
break;
// populate the axes
for (axisnum = 0; axisnum < 2; axisnum++)
{
devinfo->device()->add_item(default_axis_name[axisnum], (input_item_id)(ITEM_ID_XAXIS + axisnum), generic_axis_get_state, &devinfo->mouse.lX + axisnum);
}
// populate the buttons
for (butnum = 0; butnum < 2; butnum++)
{
devinfo->device()->add_item(default_button_name(butnum), (input_item_id)(ITEM_ID_BUTTON1 + butnum), generic_button_get_state, &devinfo->mouse.rgbButtons[butnum]);
}
}
}
bool handle_input_event(input_event eventid, void* eventdata) override
{
if (!input_enabled() || !lightgun_enabled() || eventid != INPUT_EVENT_MOUSE_BUTTON)
return false;
for (int i = 0; i < devicelist()->size(); i++)
downcast<win32_lightgun_device*>(devicelist()->at(i))->queue_events(static_cast<MouseButtonEventArgs*>(eventdata), 1);
return true;
}
};
#else
MODULE_NOT_SUPPORTED(keyboard_input_win32, OSD_KEYBOARDINPUT_PROVIDER, "win32")
MODULE_NOT_SUPPORTED(mouse_input_win32, OSD_MOUSEINPUT_PROVIDER, "win32")
MODULE_NOT_SUPPORTED(lightgun_input_win32, OSD_LIGHTGUNINPUT_PROVIDER, "win32")
#endif
MODULE_DEFINITION(KEYBOARDINPUT_WIN32, keyboard_input_win32)
MODULE_DEFINITION(MOUSEINPUT_WIN32, mouse_input_win32)
MODULE_DEFINITION(LIGHTGUNINPUT_WIN32, lightgun_input_win32)

View File

@ -0,0 +1,144 @@
// license:BSD-3-Clause
// copyright-holders:Aaron Giles, Brad Hughes
//============================================================
//
// input_windows.cpp - Common code used by Windows input modules
//
//============================================================
#include "input_module.h"
#include "modules/osdmodule.h"
#if defined(OSD_WINDOWS)
// standard windows headers
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <winioctl.h>
#include <tchar.h>
#undef interface
// MAME headers
#include "emu.h"
#include "osdepend.h"
#include "ui/ui.h"
// MAMEOS headers
#include "winmain.h"
#include "window.h"
#include "../../windows/input.h"
#include "input_common.h"
#include "input_windows.h"
bool windows_osd_interface::should_hide_mouse()
{
bool hidemouse = false;
hidemouse |= downcast<wininput_module*>(m_keyboard_input)->should_hide_mouse();
hidemouse |= downcast<wininput_module*>(m_mouse_input)->should_hide_mouse();
hidemouse |= downcast<wininput_module*>(m_lightgun_input)->should_hide_mouse();
hidemouse |= downcast<wininput_module*>(m_joystick_input)->should_hide_mouse();
return hidemouse;
}
bool windows_osd_interface::handle_input_event(input_event eventid, void* eventdata)
{
bool handled = false;
handled |= downcast<wininput_module*>(m_keyboard_input)->handle_input_event(eventid, eventdata);
handled |= downcast<wininput_module*>(m_mouse_input)->handle_input_event(eventid, eventdata);
handled |= downcast<wininput_module*>(m_lightgun_input)->handle_input_event(eventid, eventdata);
handled |= downcast<wininput_module*>(m_joystick_input)->handle_input_event(eventid, eventdata);
return handled;
}
void windows_osd_interface::poll_input(running_machine &machine)
{
m_keyboard_input->poll_if_necessary(machine);
m_mouse_input->poll_if_necessary(machine);
m_lightgun_input->poll_if_necessary(machine);
m_joystick_input->poll_if_necessary(machine);
}
//============================================================
// customize_input_type_list
//============================================================
void windows_osd_interface::customize_input_type_list(simple_list<input_type_entry> &typelist)
{
input_type_entry *entry;
const char* uimode;
// loop over the defaults
for (entry = typelist.first(); entry != NULL; entry = entry->next())
switch (entry->type())
{
// disable the config menu if the ALT key is down
// (allows ALT-TAB to switch between windows apps)
case IPT_UI_CONFIGURE:
entry->defseq(SEQ_TYPE_STANDARD).set(KEYCODE_TAB, input_seq::not_code, KEYCODE_LALT, input_seq::not_code, KEYCODE_RALT);
break;
// configurable UI mode switch
case IPT_UI_TOGGLE_UI:
uimode = options().ui_mode_key();
if (strcmp(uimode, "auto"))
{
std::string fullmode = "ITEM_ID_";
fullmode += uimode;
input_item_id const mameid_code = keyboard_trans_table::instance().lookup_mame_code(fullmode.c_str());
if (ITEM_ID_INVALID != mameid_code)
{
input_code const ui_code = input_code(DEVICE_CLASS_KEYBOARD, 0, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, input_item_id(mameid_code));
entry->defseq(SEQ_TYPE_STANDARD).set(ui_code);
}
}
break;
// alt-enter for fullscreen
case IPT_OSD_1:
entry->configure_osd("TOGGLE_FULLSCREEN", "Toggle Fullscreen");
entry->defseq(SEQ_TYPE_STANDARD).set(KEYCODE_ENTER, KEYCODE_LALT, input_seq::or_code, KEYCODE_ENTER, KEYCODE_RALT);
break;
// lalt-F12 for fullscreen snap (HLSL)
case IPT_OSD_2:
entry->configure_osd("RENDER_SNAP", "Take Rendered Snapshot");
entry->defseq(SEQ_TYPE_STANDARD).set(KEYCODE_F12, KEYCODE_LALT, input_seq::not_code, KEYCODE_LSHIFT);
break;
// add a NOT-lalt to our default F12
case IPT_UI_SNAPSHOT: // emu/input.c: input_seq(KEYCODE_F12, input_seq::not_code, KEYCODE_LSHIFT)
entry->defseq(SEQ_TYPE_STANDARD).set(KEYCODE_F12, input_seq::not_code, KEYCODE_LSHIFT, input_seq::not_code, KEYCODE_LALT);
break;
// lshift-lalt-F12 for fullscreen video (HLSL)
case IPT_OSD_3:
entry->configure_osd("RENDER_AVI", "Record Rendered Video");
entry->defseq(SEQ_TYPE_STANDARD).set(KEYCODE_F12, KEYCODE_LSHIFT, KEYCODE_LALT);
break;
// add a NOT-lalt to our default shift-F12
case IPT_UI_RECORD_MOVIE: // emu/input.c: input_seq(KEYCODE_F12, KEYCODE_LSHIFT)
entry->defseq(SEQ_TYPE_STANDARD).set(KEYCODE_F12, KEYCODE_LSHIFT, input_seq::not_code, KEYCODE_LALT);
break;
// add a NOT-lalt to write timecode file
case IPT_UI_TIMECODE: // emu/input.c: input_seq(KEYCODE_F12, input_seq::not_code, KEYCODE_LSHIFT)
entry->defseq(SEQ_TYPE_STANDARD).set(KEYCODE_F12, input_seq::not_code, KEYCODE_LSHIFT, input_seq::not_code, KEYCODE_LALT);
break;
// lctrl-lalt-F5 to toggle post-processing
case IPT_OSD_4:
entry->configure_osd("POST_PROCESS", "Toggle Post-Processing");
entry->defseq(SEQ_TYPE_STANDARD).set(KEYCODE_F5, KEYCODE_LALT, KEYCODE_LCONTROL);
break;
// add a NOT-lctrl-lalt to our default F5
case IPT_UI_TOGGLE_DEBUG: // emu/input.c: input_seq(KEYCODE_F5)
entry->defseq(SEQ_TYPE_STANDARD).set(KEYCODE_F5, input_seq::not_code, KEYCODE_LCONTROL, input_seq::not_code, KEYCODE_LALT);
break;
// leave everything else alone
default:
break;
}
}
#endif

View File

@ -0,0 +1,83 @@
// license:BSD-3-Clause
// copyright-holders:Aaron Giles, Brad Hughes
//============================================================
//
// input_windows.h - Common code used by Windows input modules
//
//============================================================
#ifndef INPUT_WIN_H_
#define INPUT_WIN_H_
//============================================================
// TYPEDEFS
//============================================================
// state information for a keyboard
struct keyboard_state
{
UINT8 state[MAX_KEYS];
INT8 oldkey[MAX_KEYS];
INT8 currkey[MAX_KEYS];
};
// state information for a mouse (matches DIMOUSESTATE exactly)
struct mouse_state
{
LONG lX;
LONG lY;
LONG lZ;
BYTE rgbButtons[8];
};
class wininput_module : public input_module_base
{
protected:
bool m_global_inputs_enabled;
public:
wininput_module(const char * type, const char * name)
: input_module_base(type, name)
{
}
virtual bool should_hide_mouse()
{
if (winwindow_has_focus() // has focus
&& (!video_config.windowed || !win_window_list->win_has_menu()) // not windowed or doesn't have a menu
&& (input_enabled() && !input_paused()) // input enabled and not paused
&& (mouse_enabled() || lightgun_enabled())) // either mouse or lightgun enabled in the core
{
return true;
}
return false;
}
virtual bool handle_input_event(input_event eventid, void* data)
{
return false;
}
protected:
void before_poll(running_machine& machine) override
{
// periodically process events, in case they're not coming through
// this also will make sure the mouse state is up-to-date
winwindow_process_events_periodic(machine);
}
bool should_poll_devices(running_machine &machine) override
{
return input_enabled() && (m_global_inputs_enabled || winwindow_has_focus());
}
};
//============================================================
// INLINE FUNCTIONS
//============================================================
INT32 generic_button_get_state(void *device_internal, void *item_internal);
INT32 generic_axis_get_state(void *device_internal, void *item_internal);
#endif

View File

@ -0,0 +1,605 @@
// license:BSD-3-Clause
// copyright-holders:Olivier Galibert, R. Belmont, Brad Hughes
//============================================================
//
// input_x11.cpp - X11 XLib/XInput routines
//
// SDLMAME by Olivier Galibert and R. Belmont
//
//============================================================
#include "input_module.h"
#include "modules/osdmodule.h"
#if defined(SDLMAME_SDL2) && !defined(SDLMAME_WIN32) && defined(USE_XINPUT) && USE_XINPUT
// for X11 xinput
#include <X11/Xlib.h>
#include <X11/extensions/XInput.h>
#include <X11/Xutil.h>
// standard sdl header
#include "sdlinc.h"
#include <ctype.h>
#include <stddef.h>
#include <mutex>
#include <memory>
#include <queue>
#include <string>
// MAME headers
#include "emu.h"
#include "osdepend.h"
// MAMEOS headers
#include "../lib/osdobj_common.h"
#include "input_common.h"
#include "../../sdl/osdsdl.h"
#include "input_sdlcommon.h"
#define MAX_DEVMAP_ENTRIES 16
#define INVALID_EVENT_TYPE -1
static int motion_type = INVALID_EVENT_TYPE;
static int button_press_type = INVALID_EVENT_TYPE;
static int button_release_type = INVALID_EVENT_TYPE;
static int key_press_type = INVALID_EVENT_TYPE;
static int key_release_type = INVALID_EVENT_TYPE;
static int proximity_in_type = INVALID_EVENT_TYPE;
static int proximity_out_type = INVALID_EVENT_TYPE;
// state information for a lightgun
struct lightgun_state
{
INT32 lX, lY;
INT32 buttons[MAX_BUTTONS];
};
struct x11_api_state
{
XID deviceid; // X11 device id
INT32 maxx, maxy;
INT32 minx, miny;
};
//============================================================
// DEBUG MACROS
//============================================================
#if defined(XINPUT_DEBUG) && XINPUT_DEBUG
#define XI_DBG(format, ...) osd_printf_verbose(format, __VA_ARGS__)
#define print_motion_event(motion) print_motion_event_impl(motion)
static inline void print_motion_event_impl(XDeviceMotionEvent *motion)
{
/*
* print a lot of debug informations of the motion event(s).
*/
osd_printf_verbose(
"XDeviceMotionEvent:\n"
" type: %d\n"
" serial: %lu\n"
" send_event: %d\n"
" display: %p\n"
" window: --\n"
" deviceid: %lu\n"
" root: --\n"
" subwindow: --\n"
" time: --\n"
" x: %d, y: %d\n"
" x_root: %d, y_root: %d\n"
" state: %u\n"
" is_hint: %2.2X\n"
" same_screen: %d\n"
" device_state: %u\n"
" axes_count: %2.2X\n"
" first_axis: %2.2X\n"
" axis_data[6]: {%d,%d,%d,%d,%d,%d}\n",
motion->type,
motion->serial,
motion->send_event,
motion->display,
/* motion->window, */
motion->deviceid,
/* motion->root */
/* motion->subwindow */
/* motion->time, */
motion->x, motion->y,
motion->x_root, motion->y_root,
motion->state,
motion->is_hint,
motion->same_screen,
motion->device_state,
motion->axes_count,
motion->first_axis,
motion->axis_data[0], motion->axis_data[1], motion->axis_data[2], motion->axis_data[3], motion->axis_data[4], motion->axis_data[5]
);
}
#else
#define XI_DBG(format, ...) while(0) {}
#define print_motion_event(motion) while(0) {}
#endif
//============================================================
// lightgun helpers: copy-past from xinfo
//============================================================
XDeviceInfo*
find_device_info(Display *display,
const char *name,
bool only_extended)
{
XDeviceInfo *devices;
XDeviceInfo *found = NULL;
int loop;
int num_devices;
int len = strlen(name);
bool is_id = true;
XID id = (XID)-1;
for(loop = 0; loop < len; loop++)
{
if (!isdigit(name[loop]))
{
is_id = false;
break;
}
}
if (is_id)
{
id = atoi(name);
}
devices = XListInputDevices(display, &num_devices);
for(loop = 0; loop < num_devices; loop++)
{
osd_printf_verbose("Evaluating device with name: %s\n", devices[loop].name);
// if only extended devices and our device isn't extended, skip
if (only_extended && devices[loop].use < IsXExtensionDevice)
continue;
// Adjust name to remove spaces for accurate comparison
std::string name_no_space = remove_spaces(devices[loop].name);
if ((!is_id && strcmp(name_no_space.c_str(), name) == 0)
|| (is_id && devices[loop].id == id))
{
if (found)
{
osd_printf_verbose(
"Warning: There are multiple devices named \"%s\".\n"
"To ensure the correct one is selected, please use "
"the device ID instead.\n\n", name);
}
else
{
found = &devices[loop];
}
}
}
return found;
}
//Copypasted from xinfo
static int
register_events(
Display *dpy,
XDeviceInfo *info,
const char *dev_name,
bool handle_proximity)
{
int number = 0; /* number of events registered */
XEventClass event_list[7];
int i;
XDevice * device;
Window root_win;
unsigned long screen;
XInputClassInfo * ip;
screen = DefaultScreen(dpy);
root_win = RootWindow(dpy, screen);
device = XOpenDevice(dpy, info->id);
if (device == nullptr)
{
osd_printf_verbose("unable to open device %s\n", dev_name);
return 0;
}
if (device->num_classes > 0)
{
for (ip = device->classes, i = 0; i < info->num_classes; ip++, i++)
{
switch (ip->input_class)
{
case KeyClass:
DeviceKeyPress(device, key_press_type, event_list[number]); number++;
DeviceKeyRelease(device, key_release_type, event_list[number]); number++;
break;
case ButtonClass:
DeviceButtonPress(device, button_press_type, event_list[number]); number++;
DeviceButtonRelease(device, button_release_type, event_list[number]); number++;
break;
case ValuatorClass:
DeviceMotionNotify(device, motion_type, event_list[number]); number++;
osd_printf_verbose("Motion = %i\n",motion_type);
if (handle_proximity)
{
ProximityIn(device, proximity_in_type, event_list[number]); number++;
ProximityOut(device, proximity_out_type, event_list[number]); number++;
}
break;
default:
osd_printf_verbose("unknown class\n");
break;
}
}
if (XSelectExtensionEvent(dpy, root_win, event_list, number))
{
osd_printf_verbose("error selecting extended events\n");
return 0;
}
}
return number;
}
//============================================================
// x11_event_manager
//============================================================
class x11_event_handler
{
public:
virtual void handle_event(XEvent &xevent) = 0;
};
class x11_event_manager : public event_manager_t<x11_event_handler>
{
private:
Display * m_display;
x11_event_manager()
: event_manager_t(),
m_display(nullptr)
{
}
public:
Display * display() { return m_display; }
static x11_event_manager& instance()
{
static x11_event_manager s_instance;
return s_instance;
}
int initialize()
{
std::lock_guard<std::mutex> scope_lock(m_lock);
if (m_display != nullptr)
return 0;
m_display = XOpenDisplay(NULL);
if (m_display == nullptr)
{
osd_printf_verbose("Unable to connect to X server\n");
return -1;
}
XExtensionVersion *version = XGetExtensionVersion(m_display, INAME);
if (!version || (version == (XExtensionVersion*)NoSuchExtension))
{
osd_printf_verbose("xinput extension not available!\n");
return -1;
}
return 0;
}
void process_events(running_machine &machine) override
{
std::lock_guard<std::mutex> scope_lock(m_lock);
XEvent xevent;
//Get XInput events
while (XPending(m_display) != 0)
{
XNextEvent(m_display, &xevent);
// Find all subscribers for the event type
auto subscribers = m_subscription_index.equal_range(xevent.type);
// Dispatch the events
for (auto iter = subscribers.first; iter != subscribers.second; iter++)
iter->second->handle_event(xevent);
}
}
};
//============================================================
// x11_input_device
//============================================================
class x11_input_device : public event_based_device<XEvent>
{
public:
x11_api_state x11_state;
x11_input_device(running_machine &machine, const char* name, input_device_class devclass, input_module &module)
: event_based_device(machine, name, devclass, module),
x11_state({0})
{
}
};
//============================================================
// x11_lightgun_device
//============================================================
class x11_lightgun_device : public x11_input_device
{
public:
lightgun_state lightgun;
x11_lightgun_device(running_machine &machine, const char* name, input_module &module)
: x11_input_device(machine, name, DEVICE_CLASS_LIGHTGUN, module),
lightgun({0})
{
}
void process_event(XEvent &xevent) override
{
if (xevent.type == motion_type)
{
XDeviceMotionEvent *motion = (XDeviceMotionEvent *)&xevent;
print_motion_event(motion);
/*
* We have to check with axis will start on array index 0.
* We have also to check the number of axes that are stored in the array.
*/
switch (motion->first_axis)
{
/*
* Starting with x, check number of axis, if there is also the y axis stored.
*/
case 0:
if (motion->axes_count >= 1)
{
lightgun.lX = normalize_absolute_axis(motion->axis_data[0], x11_state.minx, x11_state.maxx);
if (motion->axes_count >= 2)
{
lightgun.lY = normalize_absolute_axis(motion->axis_data[1], x11_state.miny, x11_state.maxy);
}
}
break;
/*
* Starting with y, ...
*/
case 1:
if (motion->axes_count >= 1)
{
lightgun.lY = normalize_absolute_axis(motion->axis_data[0], x11_state.miny, x11_state.maxy);
}
break;
}
}
else if (xevent.type == button_press_type || xevent.type == button_release_type)
{
XDeviceButtonEvent *button = (XDeviceButtonEvent *)&xevent;
lightgun.buttons[button->button] = (xevent.type == button_press_type) ? 0x80 : 0;
}
}
void reset() override
{
memset(&lightgun, 0, sizeof(lightgun));
}
};
//============================================================
// x11_lightgun_module
//============================================================
class x11_lightgun_module : public input_module_base, public x11_event_handler
{
private:
device_map_t m_lightgun_map;
Display * m_display;
public:
x11_lightgun_module()
: input_module_base(OSD_LIGHTGUNINPUT_PROVIDER, "x11")
{
}
void input_init(running_machine &machine) override
{
int index;
osd_printf_verbose("Lightgun: Begin initialization\n");
devmap_init(machine, &m_lightgun_map, SDLOPTION_LIGHTGUNINDEX, 8, "Lightgun mapping");
x11_event_manager::instance().initialize();
m_display = x11_event_manager::instance().display();
// Loop through all 8 possible devices
for (index = 0; index < 8; index++)
{
XDeviceInfo *info;
// Skip if the name is empty
if (m_lightgun_map.map[index].name.length() == 0)
continue;
x11_lightgun_device *devinfo;
std::string const &name = m_lightgun_map.map[index].name;
char defname[512];
// Register and add the device
devinfo = create_lightgun_device(machine, index);
osd_printf_verbose("%i: %s\n", index, name.c_str());
// Find the device info associated with the name
info = find_device_info(m_display, name.c_str(), 0);
// If we couldn't find the device, skip
if (info == nullptr)
{
osd_printf_verbose("Can't find device %s!\n", name.c_str());
continue;
}
//Grab device info and translate to stuff mame can use
if (info->num_classes > 0)
{
// Add the lightgun buttons based on what we read
add_lightgun_buttons((XAnyClassPtr)info->inputclassinfo, info->num_classes, devinfo);
// Also, set the axix min/max ranges if we got them
set_lightgun_axis_props((XAnyClassPtr)info->inputclassinfo, info->num_classes, devinfo);
}
// Add X and Y axis
sprintf(defname, "X %s", devinfo->name());
devinfo->device()->add_item(defname, ITEM_ID_XAXIS, generic_axis_get_state, &devinfo->lightgun.lX);
sprintf(defname, "Y %s", devinfo->name());
devinfo->device()->add_item(defname, ITEM_ID_YAXIS, generic_axis_get_state, &devinfo->lightgun.lY);
// Save the device id
devinfo->x11_state.deviceid = info->id;
// Register this device to receive event notifications
int events_registered = register_events(m_display, info, m_lightgun_map.map[index].name.c_str(), 0);
osd_printf_verbose("Device %i: Registered %i events.\n", (int)info->id, events_registered);
// register ourself to handle events from event manager
int event_types[] = { motion_type, button_press_type, button_release_type };
osd_printf_verbose("Events types to register: motion:%d, press:%d, release:%d\n", motion_type, button_press_type, button_release_type);
x11_event_manager::instance().subscribe(event_types, ARRAY_LENGTH(event_types), this);
}
osd_printf_verbose("Lightgun: End initialization\n");
}
bool should_poll_devices(running_machine &machine) override
{
return sdl_event_manager::instance().app_has_mouse_focus();
}
void before_poll(running_machine &machine) override
{
if (!should_poll_devices(machine))
return;
// Tell the event manager to process events and push them to the devices
x11_event_manager::instance().process_events(machine);
// Also trigger the SDL event manager so it can process window events
sdl_event_manager::instance().process_events(machine);
}
void handle_event(XEvent &xevent) override
{
for (int i = 0; i < devicelist()->size(); i++)
{
downcast<x11_input_device*>(devicelist()->at(i))->queue_events(&xevent, 1);
}
}
private:
x11_lightgun_device* create_lightgun_device(running_machine &machine, int index)
{
x11_lightgun_device *devinfo = nullptr;
char tempname[20];
if (m_lightgun_map.map[index].name.length() == 0)
{
if (m_lightgun_map.initialized)
{
snprintf(tempname, ARRAY_LENGTH(tempname), "NC%d", index);
devinfo = devicelist()->create_device<x11_lightgun_device>(machine, tempname, *this);
}
return nullptr;
}
else
{
devinfo = devicelist()->create_device<x11_lightgun_device>(machine, m_lightgun_map.map[index].name.c_str(), *this);
}
return devinfo;
}
void add_lightgun_buttons(XAnyClassPtr first_info_class, int num_classes, x11_lightgun_device *devinfo)
{
XAnyClassPtr any = first_info_class;
for (int i = 0; i < num_classes; i++)
{
switch (any->c_class)
{
case ButtonClass:
XButtonInfoPtr b = (XButtonInfoPtr)any;
for (int button = 0; button < b->num_buttons; button++)
{
input_item_id itemid = (input_item_id)(ITEM_ID_BUTTON1 + button);
devinfo->device()->add_item(default_button_name(button), itemid, generic_button_get_state, &devinfo->lightgun.buttons[button]);
}
break;
}
any = (XAnyClassPtr)((char *)any + any->length);
}
}
void set_lightgun_axis_props(XAnyClassPtr first_info_class, int num_classes, x11_lightgun_device *devinfo)
{
XAnyClassPtr any = first_info_class;
for (int i = 0; i < num_classes; i++)
{
switch (any->c_class)
{
case ValuatorClass:
XValuatorInfoPtr valuator_info = (XValuatorInfoPtr)any;
XAxisInfoPtr axis_info = (XAxisInfoPtr)((char *)valuator_info + sizeof(XValuatorInfo));
for (int j = 0; j < valuator_info->num_axes; j++, axis_info++)
{
if (j == 0)
{
XI_DBG("Set minx=%d, maxx=%d\n", axis_info->min_value, axis_info->max_value);
devinfo->x11_state.maxx = axis_info->max_value;
devinfo->x11_state.minx = axis_info->min_value;
}
if (j == 1)
{
XI_DBG("Set miny=%d, maxy=%d\n", axis_info->min_value, axis_info->max_value);
devinfo->x11_state.maxy = axis_info->max_value;
devinfo->x11_state.miny = axis_info->min_value;
}
}
break;
}
any = (XAnyClassPtr)((char *)any + any->length);
}
}
};
#else
MODULE_NOT_SUPPORTED(x11_lightgun_module, OSD_LIGHTGUNINPUT_PROVIDER, "x11")
#endif
MODULE_DEFINITION(LIGHTGUN_X11, x11_lightgun_module)

View File

@ -25,6 +25,12 @@ const options_entry osd_options::s_option_entries[] =
{ nullptr, nullptr, OPTION_HEADER, "OSD FONT OPTIONS" },
{ OSD_FONT_PROVIDER, OSDOPTVAL_AUTO, OPTION_STRING, "provider for ui font: " },
{ nullptr, nullptr, OPTION_HEADER, "OSD INPUT OPTIONS" },
{ OSD_KEYBOARDINPUT_PROVIDER, OSDOPTVAL_AUTO, OPTION_STRING, "provider for keyboard input: " },
{ OSD_MOUSEINPUT_PROVIDER, OSDOPTVAL_AUTO, OPTION_STRING, "provider for mouse input: " },
{ OSD_LIGHTGUNINPUT_PROVIDER, OSDOPTVAL_AUTO, OPTION_STRING, "provider for lightgun input: " },
{ OSD_JOYSTICKINPUT_PROVIDER, OSDOPTVAL_AUTO, OPTION_STRING, "provider for joystick input: " },
{ nullptr, nullptr, OPTION_HEADER, "OSD CLI OPTIONS" },
{ OSDCOMMAND_LIST_MIDI_DEVICES ";mlist", "0", OPTION_COMMAND, "list available MIDI I/O devices" },
{ OSDCOMMAND_LIST_NETWORK_ADAPTERS ";nlist", "0", OPTION_COMMAND, "list available network adapters" },
@ -155,7 +161,11 @@ osd_common_t::osd_common_t(osd_options &options)
m_options(options),
m_print_verbose(false),
m_sound(nullptr),
m_debugger(nullptr)
m_debugger(nullptr),
m_keyboard_input(nullptr),
m_mouse_input(nullptr),
m_lightgun_input(nullptr),
m_joystick_input(nullptr)
{
osd_output::push(this);
}
@ -207,6 +217,26 @@ void osd_common_t::register_options()
#endif
REGISTER_MODULE(m_mod_man, MIDI_NONE);
REGISTER_MODULE(m_mod_man, KEYBOARDINPUT_SDL);
REGISTER_MODULE(m_mod_man, KEYBOARDINPUT_RAWINPUT);
REGISTER_MODULE(m_mod_man, KEYBOARDINPUT_DINPUT);
REGISTER_MODULE(m_mod_man, KEYBOARDINPUT_WIN32);
REGISTER_MODULE(m_mod_man, KEYBOARD_NONE);
REGISTER_MODULE(m_mod_man, MOUSEINPUT_SDL);
REGISTER_MODULE(m_mod_man, MOUSEINPUT_RAWINPUT);
REGISTER_MODULE(m_mod_man, MOUSEINPUT_DINPUT);
REGISTER_MODULE(m_mod_man, MOUSEINPUT_WIN32);
REGISTER_MODULE(m_mod_man, MOUSE_NONE);
REGISTER_MODULE(m_mod_man, LIGHTGUN_X11);
REGISTER_MODULE(m_mod_man, LIGHTGUNINPUT_WIN32);
REGISTER_MODULE(m_mod_man, LIGHTGUN_NONE);
REGISTER_MODULE(m_mod_man, JOYSTICKINPUT_SDL);
REGISTER_MODULE(m_mod_man, JOYSTICKINPUT_DINPUT);
REGISTER_MODULE(m_mod_man, JOYSTICK_NONE);
// after initialization we know which modules are supported
const char *names[20];
@ -217,6 +247,30 @@ void osd_common_t::register_options()
dnames.push_back(names[i]);
update_option(OSD_FONT_PROVIDER, dnames);
m_mod_man.get_module_names(OSD_KEYBOARDINPUT_PROVIDER, 20, &num, names);
dnames.clear();
for (int i = 0; i < num; i++)
dnames.push_back(names[i]);
update_option(OSD_KEYBOARDINPUT_PROVIDER, dnames);
m_mod_man.get_module_names(OSD_MOUSEINPUT_PROVIDER, 20, &num, names);
dnames.clear();
for (int i = 0; i < num; i++)
dnames.push_back(names[i]);
update_option(OSD_MOUSEINPUT_PROVIDER, dnames);
m_mod_man.get_module_names(OSD_LIGHTGUNINPUT_PROVIDER, 20, &num, names);
dnames.clear();
for (int i = 0; i < num; i++)
dnames.push_back(names[i]);
update_option(OSD_LIGHTGUNINPUT_PROVIDER, dnames);
m_mod_man.get_module_names(OSD_JOYSTICKINPUT_PROVIDER, 20, &num, names);
dnames.clear();
for (int i = 0; i < num; i++)
dnames.push_back(names[i]);
update_option(OSD_JOYSTICKINPUT_PROVIDER, dnames);
m_mod_man.get_module_names(OSD_SOUND_PROVIDER, 20, &num, names);
dnames.clear();
for (int i = 0; i < num; i++)
@ -545,15 +599,14 @@ void osd_common_t::init_subsystems()
exit(-1);
}
input_init();
// we need pause callbacks
machine().add_notifier(MACHINE_NOTIFY_PAUSE, machine_notify_delegate(FUNC(osd_common_t::input_pause), this));
machine().add_notifier(MACHINE_NOTIFY_RESUME, machine_notify_delegate(FUNC(osd_common_t::input_resume), this));
output_init();
m_font_module = select_module_options<font_module *>(options(), OSD_FONT_PROVIDER);
m_keyboard_input = select_module_options<input_module *>(options(), OSD_KEYBOARDINPUT_PROVIDER);
m_mouse_input = select_module_options<input_module *>(options(), OSD_MOUSEINPUT_PROVIDER);
m_lightgun_input = select_module_options<input_module *>(options(), OSD_LIGHTGUNINPUT_PROVIDER);
m_joystick_input = select_module_options<input_module *>(options(), OSD_JOYSTICKINPUT_PROVIDER);
m_font_module = select_module_options<font_module *>(options(), OSD_FONT_PROVIDER);
m_sound = select_module_options<sound_module *>(options(), OSD_SOUND_PROVIDER);
m_sound->m_sample_rate = options().sample_rate();
m_sound->m_audio_latency = options().audio_latency();
@ -566,6 +619,10 @@ void osd_common_t::init_subsystems()
m_mod_man.init(options());
input_init();
// we need pause callbacks
machine().add_notifier(MACHINE_NOTIFY_PAUSE, machine_notify_delegate(FUNC(osd_common_t::input_pause), this));
machine().add_notifier(MACHINE_NOTIFY_RESUME, machine_notify_delegate(FUNC(osd_common_t::input_resume), this));
}
bool osd_common_t::video_init()
@ -589,15 +646,27 @@ void osd_common_t::video_register()
bool osd_common_t::input_init()
{
m_keyboard_input->input_init(machine());
m_mouse_input->input_init(machine());
m_lightgun_input->input_init(machine());
m_joystick_input->input_init(machine());
return true;
}
void osd_common_t::input_pause()
{
m_keyboard_input->pause();
m_mouse_input->pause();
m_lightgun_input->pause();
m_joystick_input->pause();
}
void osd_common_t::input_resume()
{
m_keyboard_input->resume();
m_mouse_input->resume();
m_lightgun_input->resume();
m_joystick_input->resume();
}
bool osd_common_t::output_init()
@ -622,6 +691,10 @@ void osd_common_t::window_exit()
void osd_common_t::input_exit()
{
m_keyboard_input->exit();
m_mouse_input->exit();
m_lightgun_input->exit();
m_joystick_input->exit();
}
void osd_common_t::output_exit()

View File

@ -16,6 +16,7 @@
#include "osdepend.h"
#include "modules/osdmodule.h"
#include "modules/font/font_module.h"
#include "modules/input/input_module.h"
#include "modules/sound/sound_module.h"
#include "modules/debugger/debug_module.h"
#include "modules/netdev/netdev_module.h"
@ -269,6 +270,10 @@ protected:
sound_module* m_sound;
debug_module* m_debugger;
midi_module* m_midi;
input_module* m_keyboard_input;
input_module* m_mouse_input;
input_module* m_lightgun_input;
input_module* m_joystick_input;
private:
std::vector<const char *> m_video_names;
};

File diff suppressed because it is too large Load Diff

View File

@ -1,28 +0,0 @@
// license:BSD-3-Clause
// copyright-holders:Olivier Galibert, R. Belmont
//============================================================
//
// input.h - SDL implementation of MAME input routines
//
// SDLMAME by Olivier Galibert and R. Belmont
//
//============================================================
#ifndef __SDLINPUT_H__
#define __SDLINPUT_H__
#include "window.h"
//============================================================
// PROTOTYPES
//============================================================
void sdlinput_poll(running_machine &machine);
int sdlinput_should_hide_mouse();
sdl_window_info *sdlinput_get_focus_window();
void sdlinput_process_events_buf();
void sdlinput_release_keys();
#endif /* __SDLINPUT_H__ */

View File

@ -149,18 +149,28 @@ public:
virtual bool video_init() override;
virtual bool window_init() override;
#ifdef USE_OLD_SDL_INPUT
virtual bool input_init() override;
virtual void input_pause() override;
virtual void input_resume() override;
#endif
virtual bool output_init() override;
//virtual bool midi_init();
virtual void video_exit() override;
virtual void window_exit() override;
#ifdef USE_OLD_SDL_INPUT
virtual void input_exit() override;
#endif
virtual void output_exit() override;
//virtual void midi_exit();
// sdl specific
void poll_inputs(running_machine &machine);
void release_keys();
bool should_hide_mouse();
void process_events_buf();
sdl_options &options() { return m_options; }
private:

View File

@ -42,7 +42,6 @@
// OSD headers
#include "video.h"
#include "input.h"
#include "osdsdl.h"
#include "modules/lib/osdlib.h"
@ -524,3 +523,4 @@ void sdl_osd_interface::init(running_machine &machine)
SDL_EventState(SDL_TEXTINPUT, SDL_TRUE);
#endif
}

View File

@ -20,7 +20,6 @@
// MAMEOS headers
#include "video.h"
#include "window.h"
#include "input.h"
#include "osdsdl.h"
#include "modules/lib/osdlib.h"
@ -163,7 +162,8 @@ void sdl_osd_interface::update(bool skip_redraw)
}
// poll the joystick values here
sdlinput_poll(machine());
downcast<sdl_osd_interface&>(machine().osd()).poll_inputs(machine());
check_osd_inputs(machine());
// if we're running, disable some parts of the debugger
if ((machine().debug_flags & DEBUG_FLAG_OSD_ENABLED) != 0)
@ -286,7 +286,12 @@ finishit:
static void check_osd_inputs(running_machine &machine)
{
#ifdef USE_OLD_SDL_INPUT
sdl_window_info *window = sdlinput_get_focus_window();
#else
// BUG: TODO: Fix focus window support
sdl_window_info *window = sdl_window_list;
#endif
// check for toggling fullscreen mode
if (machine.ui_input().pressed(IPT_OSD_1))

View File

@ -34,7 +34,6 @@
// OSD headers
#include "window.h"
#include "input.h"
#include "osdsdl.h"
#include "modules/render/drawbgfx.h"
#include "modules/render/drawsdl.h"
@ -250,14 +249,14 @@ bool sdl_osd_interface::window_init()
if (renderer_sdl2::init(machine()))
{
video_config.mode = VIDEO_MODE_SOFT;
}
}
}
if (video_config.mode == VIDEO_MODE_SOFT)
{
if (renderer_sdl1::init(machine()))
{
return false;
}
}
}
/* We may want to set a number of the hints SDL2 provides.
@ -579,7 +578,8 @@ OSDWORK_CALLBACK( sdl_window_info::sdlwindow_toggle_full_screen_wt )
SDL_SetWindowFullscreen(window->sdl_window(), SDL_WINDOW_FULLSCREEN); // Try to set mode
}
SDL_DestroyWindow(window->sdl_window());
sdlinput_release_keys();
downcast<sdl_osd_interface &>(window->machine().osd()).release_keys();
window->set_renderer(osd_renderer::make_for_type(video_config.mode, reinterpret_cast<osd_window *>(window)));
@ -651,7 +651,12 @@ void sdl_window_info::update_cursor_state()
{
//FIXME: SDL1.3: really broken: the whole SDL code
// will only work correct with relative mouse movements ...
if (!fullscreen() && !sdlinput_should_hide_mouse())
#ifdef USE_OLD_SDL_INPUT
bool should_hide_mouse = sdlinput_should_hide_mouse();
#else
bool should_hide_mouse = downcast<sdl_osd_interface&>(machine().osd()).should_hide_mouse();
#endif
if (!fullscreen() && !should_hide_mouse)
{
SDL_ShowCursor(SDL_ENABLE);
if (SDL_GetWindowGrab(sdl_window() ))
@ -666,7 +671,7 @@ void sdl_window_info::update_cursor_state()
SDL_SetRelativeMouseMode(SDL_TRUE);
}
SDL_SetCursor(nullptr); // Force an update in case the underlying driver has changed visibility
}
}
#endif
}
@ -775,7 +780,11 @@ OSDWORK_CALLBACK( sdl_window_info::sdlwindow_video_window_destroy_wt )
}
SDL_DestroyWindow(window->sdl_window());
// release all keys ...
#ifdef USE_OLD_SDL_INPUT
sdlinput_release_keys();
#else
downcast<sdl_osd_interface &>(window->machine().osd()).release_keys();
#endif
osd_free(wp);
@ -1119,11 +1128,11 @@ OSDWORK_CALLBACK( sdl_window_info::complete_create_wt )
for (auto w = sdl_window_list; w != nullptr; w = w->m_next)
{
if (w->m_index == 0)
{
{
window->m_main = w;
break;
}
}
}
}
}
window->monitor()->refresh();
// initialize the drawing backend
@ -1194,7 +1203,11 @@ OSDWORK_CALLBACK( sdl_window_info::draw_video_contents_wt )
ASSERT_REDRAW_THREAD();
// Some configurations require events to be polled in the worker thread
#ifdef USE_OLD_SDL_INPUT
sdlinput_process_events_buf();
#else
downcast< sdl_osd_interface& >(window->machine().osd()).process_events_buf();
#endif
// Check whether window has vector screens

File diff suppressed because it is too large Load Diff

View File

@ -10,18 +10,6 @@
#define __INPUT_H
//============================================================
// PROTOTYPES
//============================================================
void wininput_poll(running_machine &machine);
BOOL wininput_handle_mouse_button(int button, int down, int x, int y);
BOOL wininput_handle_raw(HANDLE device);
bool wininput_should_hide_mouse(void);
int wininput_vkey_for_mame_code(input_code code);
#endif /* __INPUT_H */

View File

@ -206,7 +206,7 @@ void windows_osd_interface::update(bool skip_redraw)
// poll the joystick values here
winwindow_process_events(machine(), TRUE, FALSE);
wininput_poll(machine());
poll_input(machine());
check_osd_inputs(machine());
// if we're running, disable some parts of the debugger
if ((machine().debug_flags & DEBUG_FLAG_OSD_ENABLED) != 0)

View File

@ -36,6 +36,12 @@
#include "modules/render/drawogl.h"
#endif
#define NOT_ALREADY_DOWN(x) (x & 0x40000000) == 0
#define SCAN_CODE(x) ((x >> 16) & 0xff)
#define IS_EXTENDED(x) (0x01000000 & x)
#define MAKE_DI_SCAN(scan, isextended) (scan & 0x7f) | (isextended ? 0x80 : 0x00)
#define WINOSD(machine) downcast<windows_osd_interface*>(&machine.osd())
//============================================================
// PARAMETERS
//============================================================
@ -188,7 +194,7 @@ bool windows_osd_interface::window_init()
fatalerror("Failed to create window thread ready event\n");
// create a thread to run the windows from
temp = _beginthreadex(nullptr, 0, win_window_info::thread_entry, nullptr, 0, (unsigned *)&window_threadid);
temp = _beginthreadex(nullptr, 0, win_window_info::thread_entry, this, 0, (unsigned *)&window_threadid);
window_thread = (HANDLE)temp;
if (window_thread == nullptr)
fatalerror("Failed to create window thread\n");
@ -225,7 +231,7 @@ bool windows_osd_interface::window_init()
{
bool error = false;
switch(current_mode)
{
{
case VIDEO_MODE_NONE:
error = renderer_none::init(machine());
break;
@ -401,7 +407,7 @@ win_window_info::~win_window_info()
if (m_renderer != nullptr)
{
delete m_renderer;
}
}
}
@ -437,7 +443,31 @@ static BOOL is_mame_window(HWND hwnd)
return FALSE;
}
inline static BOOL handle_mouse_button(windows_osd_interface *osd, int button, int down, int x, int y)
{
MouseButtonEventArgs args;
args.button = button;
args.keydown = down;
args.xpos = x;
args.ypos = y;
bool handled = osd->handle_input_event(INPUT_EVENT_MOUSE_BUTTON, &args);
// When in lightgun mode or mouse mode, the mouse click may be routed to the input system
// because the mouse interactions in the UI are routed from the video_window_proc below
// we need to make sure they aren't suppressed in these cases.
return handled && !osd->options().lightgun() && !osd->options().mouse();
}
inline static BOOL handle_keypress(windows_osd_interface *osd, int vkey, int down, int scancode, BOOL extended_key)
{
KeyPressEventArgs args;
args.event_id = down ? INPUT_EVENT_KEYDOWN : INPUT_EVENT_KEYUP;
args.scancode = MAKE_DI_SCAN(scancode, extended_key);
args.vkey = vkey;
return osd->handle_input_event(args.event_id, &args);
}
//============================================================
// winwindow_process_events
@ -478,36 +508,45 @@ void winwindow_process_events(running_machine &machine, int ingame, bool nodispa
// forward mouse button downs to the input system
case WM_LBUTTONDOWN:
dispatch = !wininput_handle_mouse_button(0, TRUE, GET_X_LPARAM(message.lParam), GET_Y_LPARAM(message.lParam));
dispatch = !handle_mouse_button(WINOSD(machine), 0, TRUE, GET_X_LPARAM(message.lParam), GET_Y_LPARAM(message.lParam));
break;
case WM_RBUTTONDOWN:
dispatch = !wininput_handle_mouse_button(1, TRUE, GET_X_LPARAM(message.lParam), GET_Y_LPARAM(message.lParam));
dispatch = !handle_mouse_button(WINOSD(machine), 1, TRUE, GET_X_LPARAM(message.lParam), GET_Y_LPARAM(message.lParam));
break;
case WM_MBUTTONDOWN:
dispatch = !wininput_handle_mouse_button(2, TRUE, GET_X_LPARAM(message.lParam), GET_Y_LPARAM(message.lParam));
dispatch = !handle_mouse_button(WINOSD(machine), 2, TRUE, GET_X_LPARAM(message.lParam), GET_Y_LPARAM(message.lParam));
break;
case WM_XBUTTONDOWN:
dispatch = !wininput_handle_mouse_button(3, TRUE, GET_X_LPARAM(message.lParam), GET_Y_LPARAM(message.lParam));
dispatch = !handle_mouse_button(WINOSD(machine), 3, TRUE, GET_X_LPARAM(message.lParam), GET_Y_LPARAM(message.lParam));
break;
// forward mouse button ups to the input system
case WM_LBUTTONUP:
dispatch = !wininput_handle_mouse_button(0, FALSE, GET_X_LPARAM(message.lParam), GET_Y_LPARAM(message.lParam));
dispatch = !handle_mouse_button(WINOSD(machine), 0, FALSE, GET_X_LPARAM(message.lParam), GET_Y_LPARAM(message.lParam));
break;
case WM_RBUTTONUP:
dispatch = !wininput_handle_mouse_button(1, FALSE, GET_X_LPARAM(message.lParam), GET_Y_LPARAM(message.lParam));
dispatch = !handle_mouse_button(WINOSD(machine), 1, FALSE, GET_X_LPARAM(message.lParam), GET_Y_LPARAM(message.lParam));
break;
case WM_MBUTTONUP:
dispatch = !wininput_handle_mouse_button(2, FALSE, GET_X_LPARAM(message.lParam), GET_Y_LPARAM(message.lParam));
dispatch = !handle_mouse_button(WINOSD(machine), 2, FALSE, GET_X_LPARAM(message.lParam), GET_Y_LPARAM(message.lParam));
break;
case WM_XBUTTONUP:
dispatch = !wininput_handle_mouse_button(3, FALSE, GET_X_LPARAM(message.lParam), GET_Y_LPARAM(message.lParam));
dispatch = !handle_mouse_button(WINOSD(machine), 3, FALSE, GET_X_LPARAM(message.lParam), GET_Y_LPARAM(message.lParam));
break;
case WM_KEYDOWN:
if (NOT_ALREADY_DOWN(message.lParam))
dispatch = !handle_keypress(WINOSD(machine), message.wParam, TRUE, SCAN_CODE(message.lParam), IS_EXTENDED(message.lParam));
break;
case WM_KEYUP:
dispatch = !handle_keypress(WINOSD(machine), message.wParam, FALSE, SCAN_CODE(message.lParam), IS_EXTENDED(message.lParam));
break;
}
}
@ -688,7 +727,7 @@ void winwindow_update_cursor_state(running_machine &machine)
// 2. we also hide the cursor in full screen mode and when the window doesn't have a menu
// 3. we also hide the cursor in windowed mode if we're not paused and
// the input system requests it
if (winwindow_has_focus() && ((!video_config.windowed && !win_window_list->win_has_menu()) || (!machine.paused() && wininput_should_hide_mouse())))
if (winwindow_has_focus() && ((!video_config.windowed && !win_window_list->win_has_menu()) || (!machine.paused() && downcast<windows_osd_interface&>(machine.osd()).should_hide_mouse())))
{
win_window_info *window = win_window_list;
RECT bounds;
@ -1152,6 +1191,7 @@ int win_window_info::wnd_extra_height()
unsigned __stdcall win_window_info::thread_entry(void *param)
{
MSG message;
windows_osd_interface *osd = static_cast<windows_osd_interface*>(param);
// make a bogus user call to make us a message thread
PeekMessage(&message, nullptr, 0, 0, PM_NOREMOVE);
@ -1179,36 +1219,36 @@ unsigned __stdcall win_window_info::thread_entry(void *param)
// forward mouse button downs to the input system
case WM_LBUTTONDOWN:
dispatch = !wininput_handle_mouse_button(0, TRUE, GET_X_LPARAM(message.lParam), GET_Y_LPARAM(message.lParam));
dispatch = !handle_mouse_button(osd, 0, TRUE, GET_X_LPARAM(message.lParam), GET_Y_LPARAM(message.lParam));
break;
case WM_RBUTTONDOWN:
dispatch = !wininput_handle_mouse_button(1, TRUE, GET_X_LPARAM(message.lParam), GET_Y_LPARAM(message.lParam));
dispatch = !handle_mouse_button(osd, 1, TRUE, GET_X_LPARAM(message.lParam), GET_Y_LPARAM(message.lParam));
break;
case WM_MBUTTONDOWN:
dispatch = !wininput_handle_mouse_button(2, TRUE, GET_X_LPARAM(message.lParam), GET_Y_LPARAM(message.lParam));
dispatch = !handle_mouse_button(osd, 2, TRUE, GET_X_LPARAM(message.lParam), GET_Y_LPARAM(message.lParam));
break;
case WM_XBUTTONDOWN:
dispatch = !wininput_handle_mouse_button(3, TRUE, GET_X_LPARAM(message.lParam), GET_Y_LPARAM(message.lParam));
dispatch = !handle_mouse_button(osd, 3, TRUE, GET_X_LPARAM(message.lParam), GET_Y_LPARAM(message.lParam));
break;
// forward mouse button ups to the input system
case WM_LBUTTONUP:
dispatch = !wininput_handle_mouse_button(0, FALSE, GET_X_LPARAM(message.lParam), GET_Y_LPARAM(message.lParam));
dispatch = !handle_mouse_button(osd, 0, FALSE, GET_X_LPARAM(message.lParam), GET_Y_LPARAM(message.lParam));
break;
case WM_RBUTTONUP:
dispatch = !wininput_handle_mouse_button(1, FALSE, GET_X_LPARAM(message.lParam), GET_Y_LPARAM(message.lParam));
dispatch = !handle_mouse_button(osd, 1, FALSE, GET_X_LPARAM(message.lParam), GET_Y_LPARAM(message.lParam));
break;
case WM_MBUTTONUP:
dispatch = !wininput_handle_mouse_button(2, FALSE, GET_X_LPARAM(message.lParam), GET_Y_LPARAM(message.lParam));
dispatch = !handle_mouse_button(osd, 2, FALSE, GET_X_LPARAM(message.lParam), GET_Y_LPARAM(message.lParam));
break;
case WM_XBUTTONUP:
dispatch = !wininput_handle_mouse_button(3, FALSE, GET_X_LPARAM(message.lParam), GET_Y_LPARAM(message.lParam));
dispatch = !handle_mouse_button(osd, 3, FALSE, GET_X_LPARAM(message.lParam), GET_Y_LPARAM(message.lParam));
break;
// a terminate message to the thread posts a quit
@ -1369,7 +1409,7 @@ LRESULT CALLBACK win_window_info::video_window_proc(HWND wnd, UINT message, WPAR
// input: handle the raw input
case WM_INPUT:
wininput_handle_raw((HRAWINPUT)lparam);
downcast<windows_osd_interface&>(window->machine().osd()).handle_input_event(INPUT_EVENT_RAWINPUT, &lparam);
break;
// syskeys - ignore

View File

@ -238,6 +238,29 @@ private:
// TYPE DEFINITIONS
//============================================================
enum input_event
{
INPUT_EVENT_KEYDOWN,
INPUT_EVENT_KEYUP,
INPUT_EVENT_RAWINPUT,
INPUT_EVENT_MOUSE_BUTTON
};
struct KeyPressEventArgs
{
input_event event_id;
UINT8 vkey;
UINT8 scancode;
};
struct MouseButtonEventArgs
{
int button;
int keydown;
int xpos;
int ypos;
};
class windows_osd_interface : public osd_common_t
{
public:
@ -252,25 +275,25 @@ public:
// video overridables
virtual slider_state *get_slider_list() override;
// input overridables
virtual void customize_input_type_list(simple_list<input_type_entry> &typelist) override;
virtual void video_register() override;
virtual bool video_init() override;
virtual bool window_init() override;
virtual bool input_init() override;
virtual void input_pause() override;
virtual void input_resume() override;
virtual bool output_init() override;
virtual void video_exit() override;
virtual void window_exit() override;
virtual void input_exit() override;
virtual void output_exit() override;
void extract_video_config();
// windows osd specific
bool handle_input_event(input_event eventid, void *eventdata);
bool should_hide_mouse();
void poll_input(running_machine &machine);
windows_options &options() { return m_options; }
private: