From 7dfb5785594a359ce9886ef6eebf564ea73af729 Mon Sep 17 00:00:00 2001 From: Brad Hughes Date: Fri, 29 Jan 2016 15:02:27 -0500 Subject: [PATCH] Refactor OSD input into modules --- scripts/src/osd/modules.lua | 13 + scripts/src/osd/sdl.lua | 2 - scripts/src/osd/windows.lua | 1 - src/osd/modules/debugger/debugwin.cpp | 7 +- src/osd/modules/input/input_common.cpp | 266 +++ src/osd/modules/input/input_common.h | 605 ++++++ src/osd/modules/input/input_dinput.cpp | 683 ++++++ src/osd/modules/input/input_module.h | 39 + src/osd/modules/input/input_none.cpp | 66 + src/osd/modules/input/input_rawinput.cpp | 649 ++++++ src/osd/modules/input/input_sdl.cpp | 843 ++++++++ src/osd/modules/input/input_sdlcommon.cpp | 283 +++ src/osd/modules/input/input_sdlcommon.h | 204 ++ src/osd/modules/input/input_win32.cpp | 427 ++++ src/osd/modules/input/input_windows.cpp | 144 ++ src/osd/modules/input/input_windows.h | 83 + src/osd/modules/input/input_x11.cpp | 605 ++++++ src/osd/modules/lib/osdobj_common.cpp | 87 +- src/osd/modules/lib/osdobj_common.h | 5 + src/osd/sdl/input.cpp | 2362 --------------------- src/osd/sdl/input.h | 28 - src/osd/sdl/osdsdl.h | 10 + src/osd/sdl/sdlmain.cpp | 2 +- src/osd/sdl/video.cpp | 9 +- src/osd/sdl/window.cpp | 28 +- src/osd/windows/input.cpp | 2255 -------------------- src/osd/windows/input.h | 16 +- src/osd/windows/video.cpp | 2 +- src/osd/windows/window.cpp | 84 +- src/osd/windows/winmain.h | 33 +- 30 files changed, 5134 insertions(+), 4707 deletions(-) create mode 100644 src/osd/modules/input/input_common.cpp create mode 100644 src/osd/modules/input/input_common.h create mode 100644 src/osd/modules/input/input_dinput.cpp create mode 100644 src/osd/modules/input/input_module.h create mode 100644 src/osd/modules/input/input_none.cpp create mode 100644 src/osd/modules/input/input_rawinput.cpp create mode 100644 src/osd/modules/input/input_sdl.cpp create mode 100644 src/osd/modules/input/input_sdlcommon.cpp create mode 100644 src/osd/modules/input/input_sdlcommon.h create mode 100644 src/osd/modules/input/input_win32.cpp create mode 100644 src/osd/modules/input/input_windows.cpp create mode 100644 src/osd/modules/input/input_windows.h create mode 100644 src/osd/modules/input/input_x11.cpp delete mode 100644 src/osd/sdl/input.cpp delete mode 100644 src/osd/sdl/input.h delete mode 100644 src/osd/windows/input.cpp diff --git a/scripts/src/osd/modules.lua b/scripts/src/osd/modules.lua index 87e684a50f6..c7ebb399be8 100644 --- a/scripts/src/osd/modules.lua +++ b/scripts/src/osd/modules.lua @@ -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 diff --git a/scripts/src/osd/sdl.lua b/scripts/src/osd/sdl.lua index 6acb5a2d262..6f52f1879ba 100644 --- a/scripts/src/osd/sdl.lua +++ b/scripts/src/osd/sdl.lua @@ -419,8 +419,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", diff --git a/scripts/src/osd/windows.lua b/scripts/src/osd/windows.lua index fd508e645c5..2957f7ade9f 100644 --- a/scripts/src/osd/windows.lua +++ b/scripts/src/osd/windows.lua @@ -162,7 +162,6 @@ project ("osd_" .. _OPTIONS["osd"]) MAME_DIR .. "src/osd/modules/render/drawdd.cpp", MAME_DIR .. "src/osd/modules/render/drawgdi.cpp", MAME_DIR .. "src/osd/modules/render/drawnone.cpp", - 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", diff --git a/src/osd/modules/debugger/debugwin.cpp b/src/osd/modules/debugger/debugwin.cpp index b31d12ea67a..634332899c3 100644 --- a/src/osd/modules/debugger/debugwin.cpp +++ b/src/osd/modules/debugger/debugwin.cpp @@ -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(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 diff --git a/src/osd/modules/input/input_common.cpp b/src/osd/modules/input/input_common.cpp new file mode 100644 index 00000000000..c3d6367da5f --- /dev/null +++ b/src/osd/modules/input/input_common.cpp @@ -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 +#include + +// 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 +#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 +#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 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; +} \ No newline at end of file diff --git a/src/osd/modules/input/input_common.h b/src/osd/modules/input/input_common.h new file mode 100644 index 00000000000..23d9c958c8c --- /dev/null +++ b/src/osd/modules/input/input_common.h @@ -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 +#include +#include +#include + +//============================================================ +// 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 event_based_device : public device_info +{ +private: + std::queue 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 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 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> 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 + TActual* create_device(running_machine &machine, const char *name, input_module &module) + { + // allocate the device object + auto devinfo = std::make_unique(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 + 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 m_custom_table; + + key_trans_entry * m_table; + UINT32 m_table_size; + +public: + // constructor + keyboard_trans_table(std::unique_ptr 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 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(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 diff --git a/src/osd/modules/input/input_dinput.cpp b/src/osd/modules/input/input_dinput.cpp new file mode 100644 index 00000000000..a08a62af636 --- /dev/null +++ b/src/osd/modules/input/input_dinput.cpp @@ -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 +#include +#include + +// undef WINNT for dinput.h to prevent duplicate definition +#undef WINNT +#include +#undef interface + +#include +#include + +// 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 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 + 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(utf8_from_tstring(instance->tszInstanceName), osd_deleter); + + // allocate memory for the device object + TDevice* devinfo = devicelist()->create_device(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(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(strlen(namestring.get()) + 1 + _tcslen(suffix) + 1); + + // convert the suffix to utf8 + auto suffix_utf8 = std::unique_ptr(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(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(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(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) \ No newline at end of file diff --git a/src/osd/modules/input/input_module.h b/src/osd/modules/input/input_module.h new file mode 100644 index 00000000000..f031bbb6fad --- /dev/null +++ b/src/osd/modules/input/input_module.h @@ -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_ */ diff --git a/src/osd/modules/input/input_none.cpp b/src/osd/modules/input/input_none.cpp new file mode 100644 index 00000000000..e485faca4f6 --- /dev/null +++ b/src/osd/modules/input/input_none.cpp @@ -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) \ No newline at end of file diff --git a/src/osd/modules/input/input_rawinput.cpp b/src/osd/modules/input/input_rawinput.cpp new file mode 100644 index 00000000000..3b9c621b015 --- /dev/null +++ b/src/osd/modules/input/input_rawinput.cpp @@ -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 +#include +#include +#undef interface + +#include + +// 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, ®key); + 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, ®key); + 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 +{ +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 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(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(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)(®istration, 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 + 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 tname = std::make_unique(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(rawinput_device_improve_name(tname.release())); + + // convert name to utf8 + auto osd_deleter = [](void *ptr) { osd_free(ptr); }; + auto utf8_name = std::unique_ptr(utf8_from_tstring(tname.get()), osd_deleter); + + devinfo = devicelist()->create_device(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 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(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 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(devicelist()->at(i)); + RAWINPUT *input = reinterpret_cast(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(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(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) \ No newline at end of file diff --git a/src/osd/modules/input/input_sdl.cpp b/src/osd/modules/input/input_sdl.cpp new file mode 100644 index 00000000000..3894f25e1b4 --- /dev/null +++ b/src/osd/modules/input/input_sdl.cpp @@ -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 +#include +#include +#include +#include + +// 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 +{ +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(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(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(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(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(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(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(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(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(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(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(machine, tempname, *this) + : devicelist()->create_device(machine, tempname, *this); + } + + return NULL; + } + else + { + devinfo = m_sixaxis_mode + ? devicelist()->create_device(machine, devmap->map[index].name.c_str(), *this) + : devicelist()->create_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) \ No newline at end of file diff --git a/src/osd/modules/input/input_sdlcommon.cpp b/src/osd/modules/input/input_sdlcommon.cpp new file mode 100644 index 00000000000..e22606f9fb3 --- /dev/null +++ b/src/osd/modules/input/input_sdlcommon.cpp @@ -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 +#include +#include +#include + +// 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 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 &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(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 \ No newline at end of file diff --git a/src/osd/modules/input/input_sdlcommon.h b/src/osd/modules/input/input_sdlcommon.h new file mode 100644 index 00000000000..a4bde246967 --- /dev/null +++ b/src/osd/modules/input/input_sdlcommon.h @@ -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 +#include +#include +#include + +#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 event_manager_t +{ +protected: + std::mutex m_lock; + std::unordered_multimap m_subscription_index; + event_manager_t() + { + } + +public: + void subscribe(int* event_types, int num_event_types, TSubscriber *subscriber) + { + std::lock_guard 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 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 +{ +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 \ No newline at end of file diff --git a/src/osd/modules/input/input_win32.cpp b/src/osd/modules/input/input_win32.cpp new file mode 100644 index 00000000000..f0477a414fc --- /dev/null +++ b/src/osd/modules/input/input_win32.cpp @@ -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 +#include +#include +#undef interface + +#include + +// 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 +{ +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(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(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 +{ +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(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(eventdata); + for (int i = 0; i < devicelist()->size(); i++) + downcast(devicelist()->at(i))->queue_events(args, 1); + + return TRUE; + } +}; + +//============================================================ +// win32_lightgun_device +//============================================================ + +class win32_lightgun_device : public event_based_device +{ +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(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(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(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(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(devicelist()->at(i))->queue_events(static_cast(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) + diff --git a/src/osd/modules/input/input_windows.cpp b/src/osd/modules/input/input_windows.cpp new file mode 100644 index 00000000000..d5761d37708 --- /dev/null +++ b/src/osd/modules/input/input_windows.cpp @@ -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 +#include +#include +#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(m_keyboard_input)->should_hide_mouse(); + hidemouse |= downcast(m_mouse_input)->should_hide_mouse(); + hidemouse |= downcast(m_lightgun_input)->should_hide_mouse(); + hidemouse |= downcast(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(m_keyboard_input)->handle_input_event(eventid, eventdata); + handled |= downcast(m_mouse_input)->handle_input_event(eventid, eventdata); + handled |= downcast(m_lightgun_input)->handle_input_event(eventid, eventdata); + handled |= downcast(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 &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 \ No newline at end of file diff --git a/src/osd/modules/input/input_windows.h b/src/osd/modules/input/input_windows.h new file mode 100644 index 00000000000..b79560c97a7 --- /dev/null +++ b/src/osd/modules/input/input_windows.h @@ -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 \ No newline at end of file diff --git a/src/osd/modules/input/input_x11.cpp b/src/osd/modules/input/input_x11.cpp new file mode 100644 index 00000000000..3a4073ef8c7 --- /dev/null +++ b/src/osd/modules/input/input_x11.cpp @@ -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 +#include +#include + +// standard sdl header +#include "sdlinc.h" +#include +#include +#include +#include +#include +#include + +// 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 +{ +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 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 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 +{ +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(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(machine, tempname, *this); + } + + return nullptr; + } + else + { + devinfo = devicelist()->create_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) \ No newline at end of file diff --git a/src/osd/modules/lib/osdobj_common.cpp b/src/osd/modules/lib/osdobj_common.cpp index b36bbf60df3..b3e0d428b49 100644 --- a/src/osd/modules/lib/osdobj_common.cpp +++ b/src/osd/modules/lib/osdobj_common.cpp @@ -25,6 +25,12 @@ const options_entry osd_options::s_option_entries[] = { NULL, NULL, OPTION_HEADER, "OSD FONT OPTIONS" }, { OSD_FONT_PROVIDER, OSDOPTVAL_AUTO, OPTION_STRING, "provider for ui font: " }, + { NULL, NULL, 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: " }, + { NULL, NULL, 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(NULL), - m_debugger(NULL) + m_debugger(NULL), + m_keyboard_input(NULL), + m_mouse_input(NULL), + m_lightgun_input(NULL), + m_joystick_input(NULL) { 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++) @@ -544,15 +598,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(options(), OSD_FONT_PROVIDER); + m_keyboard_input = select_module_options(options(), OSD_KEYBOARDINPUT_PROVIDER); + m_mouse_input = select_module_options(options(), OSD_MOUSEINPUT_PROVIDER); + m_lightgun_input = select_module_options(options(), OSD_LIGHTGUNINPUT_PROVIDER); + m_joystick_input = select_module_options(options(), OSD_JOYSTICKINPUT_PROVIDER); + m_font_module = select_module_options(options(), OSD_FONT_PROVIDER); m_sound = select_module_options(options(), OSD_SOUND_PROVIDER); m_sound->m_sample_rate = options().sample_rate(); m_sound->m_audio_latency = options().audio_latency(); @@ -565,6 +618,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() @@ -588,15 +645,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() @@ -621,6 +690,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() diff --git a/src/osd/modules/lib/osdobj_common.h b/src/osd/modules/lib/osdobj_common.h index a73931f3fa1..69d0250ff3e 100644 --- a/src/osd/modules/lib/osdobj_common.h +++ b/src/osd/modules/lib/osdobj_common.h @@ -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 m_video_names; }; diff --git a/src/osd/sdl/input.cpp b/src/osd/sdl/input.cpp deleted file mode 100644 index a050cbf024b..00000000000 --- a/src/osd/sdl/input.cpp +++ /dev/null @@ -1,2362 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Olivier Galibert, R. Belmont -//============================================================ -// -// input.c - SDL 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 -// -//============================================================ - -// standard sdl header -#include "sdlinc.h" -#include -#include -#include - -#if USE_XINPUT -// for xinput -#include -#include -#include -#endif - -// MAME headers -#include "emu.h" -#include "ui/ui.h" -#include "uiinput.h" -#include "emuopts.h" - - -// MAMEOS headers -#include "input.h" -#include "osdsdl.h" -#include "window.h" - -// winnt.h defines this -#ifdef DELETE -#undef DELETE -#endif - -//============================================================ -// 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 -#define MAX_DEVMAP_ENTRIES 16 - -#if (USE_XINPUT) -//For xinput -#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; -#endif - -//============================================================ -// MACROS -//============================================================ - -// introduced in 1.3 - -#ifndef SDLK_INDEX -#define SDLK_INDEX(x) (x) -#endif - - -//============================================================ -// TYPEDEFS -//============================================================ - -// 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]; -}; - -#if (USE_XINPUT) -// state information for a lightgun -struct lightgun_state -{ - INT32 lX, lY; - INT32 buttons[MAX_BUTTONS]; - XID deviceid; //Xinput device id - INT32 maxx,maxy; - INT32 minx,miny; -}; -#endif - -// generic device information -struct device_info -{ - // device information - device_info ** head; - device_info * next; - std::string name; - - // MAME information - input_device * device; - - // device state - union - { - keyboard_state keyboard; - mouse_state mouse; - joystick_state joystick; -#if (USE_XINPUT) - lightgun_state lightgun; -#endif - }; -}; - - -//============================================================ -// LOCAL VARIABLES -//============================================================ - -// global states -static std::mutex input_lock; -static UINT8 input_paused; - -static sdl_window_info * focus_window = NULL; - -// input buffer - only for SDLMAME_EVENTS_IN_WORKER_THREAD -#define MAX_BUF_EVENTS (1000) /* 100 not enough for SDL 1.3 */ -static SDL_Event event_buf[MAX_BUF_EVENTS]; -static int event_buf_count; - -// keyboard states -static device_info * keyboard_list; - -// mouse states -static UINT8 app_has_mouse_focus; -static UINT8 mouse_enabled; -static device_info * mouse_list; - -// lightgun states -static UINT8 lightgun_enabled; -static device_info * lightgun_list; - -// joystick states -static device_info * joystick_list; - -// joystick mapper - -struct device_map_t -{ - struct { - char *name; - int physical; - } map[MAX_DEVMAP_ENTRIES]; - int logical[MAX_DEVMAP_ENTRIES]; - int initialized; -}; - -static device_map_t joy_map; -static device_map_t mouse_map; -static device_map_t keyboard_map; -#if (USE_XINPUT) -static device_map_t lightgun_map; -Display *XDisplay; -#endif - -static int sixaxis_mode; - - -//============================================================ -// PROTOTYPES -//============================================================ - -// deivce list management -static void device_list_reset_devices(device_info *devlist_head); -static void device_list_free_devices(device_info **devlist_head); - -// generic device management -static device_info *generic_device_alloc(device_info **devlist_head_ptr, const char *name); -static void generic_device_free(device_info *devinfo); -static int generic_device_index(device_info *devlist_head, device_info *devinfo); -static void generic_device_reset(device_info *devinfo); -static INT32 generic_button_get_state(void *device_internal, void *item_internal); -static INT32 generic_axis_get_state(void *device_internal, void *item_internal); -static device_info *generic_device_find_index(device_info *devlist_head, int index); - - -//============================================================ -// KEYBOARD/JOYSTICK LIST -//============================================================ - -// master keyboard translation table -struct kt_table { - input_item_id mame_key; - INT32 sdl_key; - //const char * vkey; - //const char * ascii; - const char * mame_key_name; - char * ui_name; -}; - -#if (SDLMAME_SDL2) - -#define OSD_SDL_INDEX(x) (x) -#define OSD_SDL_INDEX_KEYSYM(keysym) ((keysym)->scancode) - -#define GET_WINDOW(ev) window_from_id((ev)->windowID) -//#define GET_WINDOW(ev) ((ev)->windowID) -// 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) - - -#define KTT_ENTRY0(MAME, SDL, VK, AS, UI) { ITEM_ID_ ## MAME, SDL_SCANCODE_ ## SDL, "ITEM_ID_" #MAME, (char *) UI } -#define KTT_ENTRY1(MAME, SDL) KTT_ENTRY0(MAME, SDL, MAME, MAME, #MAME) -// only for reference ... -#define KTT_ENTRY2(MAME, SDL) KTT_ENTRY0(MAME, SDL, 0, 0, #MAME) - - -static kt_table sdl_key_trans_table[] = -{ - // MAME key SDL key vkey ascii - KTT_ENTRY0( ESC, ESCAPE, 0x1b, 0x1b, "ESC" ), // 0 - KTT_ENTRY1( 1, 1 ), // 1 - KTT_ENTRY1( 2, 2 ), // 2 - KTT_ENTRY1( 3, 3 ), // 3 - KTT_ENTRY1( 4, 4 ), // 4 - KTT_ENTRY1( 5, 5 ), // 5 - KTT_ENTRY1( 6, 6 ), // 6 - KTT_ENTRY1( 7, 7 ), // 7 - KTT_ENTRY1( 8, 8 ), // 8 - KTT_ENTRY1( 9, 9 ), // 9 - KTT_ENTRY1( 0, 0 ), // 10 - KTT_ENTRY0( MINUS, MINUS, 0xbd, '-', "MINUS" ), // 11 - KTT_ENTRY0( EQUALS, EQUALS, 0xbb, '=', "EQUALS" ), // 12 - KTT_ENTRY0( BACKSPACE, BACKSPACE, 0x08, 0x08, "BACKSPACE" ), // 13 - KTT_ENTRY0( TAB, TAB, 0x09, 0x09, "TAB" ), // 14 - KTT_ENTRY1( Q, Q ), // 15 - KTT_ENTRY1( W, W ), // 16 - KTT_ENTRY1( E, E ), // 17 - KTT_ENTRY1( R, R ), // 18 - KTT_ENTRY1( T, T ), // 19 - KTT_ENTRY1( Y, Y ), // 20 - KTT_ENTRY1( U, U ), // 21 - KTT_ENTRY1( I, I ), // 22 - KTT_ENTRY1( O, O ), // 23 - KTT_ENTRY1( P, P ), // 24 - KTT_ENTRY0( OPENBRACE, LEFTBRACKET, 0xdb, '[', "OPENBRACE" ), // 25 - KTT_ENTRY0( CLOSEBRACE,RIGHTBRACKET, 0xdd, ']', "CLOSEBRACE" ), // 26 - KTT_ENTRY0( ENTER, RETURN, 0x0d, 0x0d, "RETURN" ), // 27 - KTT_ENTRY2( LCONTROL, LCTRL ), // 28 - KTT_ENTRY1( A, A ), // 29 - KTT_ENTRY1( S, S ), // 30 - KTT_ENTRY1( D, D ), // 31 - KTT_ENTRY1( F, F ), // 32 - KTT_ENTRY1( G, G ), // 33 - KTT_ENTRY1( H, H ), // 34 - KTT_ENTRY1( J, J ), // 35 - KTT_ENTRY1( K, K ), // 36 - KTT_ENTRY1( L, L ), // 37 - KTT_ENTRY0( COLON, SEMICOLON, 0xba, ';', "COLON" ), // 38 - KTT_ENTRY0( QUOTE, APOSTROPHE, 0xde, '\'', "QUOTE" ), // 39 - KTT_ENTRY2( LSHIFT, LSHIFT ), // 40 - KTT_ENTRY0( BACKSLASH, BACKSLASH, 0xdc, '\\', "BACKSLASH" ), // 41 - KTT_ENTRY1( Z, Z ), // 42 - KTT_ENTRY1( X, X ), // 43 - KTT_ENTRY1( C, C ), // 44 - KTT_ENTRY1( V, V ), // 45 - KTT_ENTRY1( B, B ), // 46 - KTT_ENTRY1( N, N ), // 47 - KTT_ENTRY1( M, M ), // 48 - KTT_ENTRY0( COMMA, COMMA, 0xbc, ',', "COMMA" ), // 49 - KTT_ENTRY0( STOP, PERIOD, 0xbe, '.', "STOP" ), // 50 - KTT_ENTRY0( SLASH, SLASH, 0xbf, '/', "SLASH" ), // 51 - KTT_ENTRY2( RSHIFT, RSHIFT ), // 52 - KTT_ENTRY0( ASTERISK, KP_MULTIPLY, '*', '*', "ASTERIX" ), // 53 - KTT_ENTRY2( LALT, LALT ), // 54 - KTT_ENTRY0( SPACE, SPACE, ' ', ' ', "SPACE" ), // 55 - KTT_ENTRY2( CAPSLOCK, CAPSLOCK ), // 56 - KTT_ENTRY2( F1, F1 ), // 57 - KTT_ENTRY2( F2, F2 ), // 58 - KTT_ENTRY2( F3, F3 ), // 59 - KTT_ENTRY2( F4, F4 ), // 60 - KTT_ENTRY2( F5, F5 ), // 61 - KTT_ENTRY2( F6, F6 ), // 62 - KTT_ENTRY2( F7, F7 ), // 63 - KTT_ENTRY2( F8, F8 ), // 64 - KTT_ENTRY2( F9, F9 ), // 65 - KTT_ENTRY2( F10, F10 ), // 66 - KTT_ENTRY2( NUMLOCK, NUMLOCKCLEAR ), // 67 - KTT_ENTRY2( SCRLOCK, SCROLLLOCK ), // 68 - KTT_ENTRY2( 7_PAD, KP_7 ), // 69 - KTT_ENTRY2( 8_PAD, KP_8 ), - KTT_ENTRY2( 9_PAD, KP_9 ), - KTT_ENTRY2( MINUS_PAD, KP_MINUS ), - KTT_ENTRY2( 4_PAD, KP_4 ), - KTT_ENTRY2( 5_PAD, KP_5 ), - KTT_ENTRY2( 6_PAD, KP_6 ), - KTT_ENTRY2( PLUS_PAD, KP_PLUS ), - KTT_ENTRY2( 1_PAD, KP_1 ), - KTT_ENTRY2( 2_PAD, KP_2 ), - KTT_ENTRY2( 3_PAD, KP_3 ), - KTT_ENTRY2( 0_PAD, KP_0 ), - KTT_ENTRY2( DEL_PAD, KP_PERIOD ), - KTT_ENTRY2( F11, F11 ), - KTT_ENTRY2( F12, F12 ), - KTT_ENTRY2( F13, F13 ), - KTT_ENTRY2( F14, F14 ), - KTT_ENTRY2( F15, F15 ), - KTT_ENTRY2( ENTER_PAD, KP_ENTER ), - KTT_ENTRY2( RCONTROL, RCTRL ), - KTT_ENTRY2( SLASH_PAD, KP_DIVIDE ), - KTT_ENTRY2( PRTSCR, PRINTSCREEN ), - KTT_ENTRY2( RALT, RALT ), - KTT_ENTRY2( HOME, HOME ), - KTT_ENTRY2( UP, UP ), - KTT_ENTRY2( PGUP, PAGEUP ), - KTT_ENTRY2( LEFT, LEFT ), - KTT_ENTRY2( RIGHT, RIGHT ), - KTT_ENTRY2( END, END ), - KTT_ENTRY2( DOWN, DOWN ), - KTT_ENTRY2( PGDN, PAGEDOWN ), - KTT_ENTRY2( INSERT, INSERT ), - { ITEM_ID_DEL, SDL_SCANCODE_DELETE, "ITEM_ID_DEL", (char *)"DELETE" }, - KTT_ENTRY2( LWIN, LGUI ), - KTT_ENTRY2( RWIN, RGUI ), - KTT_ENTRY2( MENU, MENU ), - KTT_ENTRY0( TILDE, GRAVE, 0xc0, '`', "TILDE" ), - KTT_ENTRY0( BACKSLASH2, NONUSBACKSLASH, 0xdc, '\\', "BACKSLASH2" ), - { ITEM_ID_INVALID } -}; -#else - -#define OSD_SDL_INDEX(x) (SDLK_INDEX(x)-SDLK_FIRST) -#define OSD_SDL_INDEX_KEYSYM(keysym) (OSD_SDL_INDEX((keysym)->sym)) -#define GET_WINDOW(ev) sdl_window_list -#define GET_FOCUS_WINDOW(ev) sdl_window_list - -#define KTT_ENTRY0(MAME, SDL, VK, AS, UI) { ITEM_ID_ ## MAME, SDLK_ ## SDL, "ITEM_ID_" #MAME, (char *) UI } -#define KTT_ENTRY1(MAME, SDL) KTT_ENTRY0(MAME, SDL, MAME, MAME, #MAME) -// only for reference ... -#define KTT_ENTRY2(MAME, SDL) KTT_ENTRY0(MAME, SDL, 0, 0, #MAME) - - -static kt_table sdl_key_trans_table[] = -{ - // MAME key SDL key vkey ascii - KTT_ENTRY0( ESC, ESCAPE, 0x1b, 0x1b, "ESC" ), - KTT_ENTRY1( 1, 1 ), - KTT_ENTRY1( 2, 2 ), - KTT_ENTRY1( 3, 3 ), - KTT_ENTRY1( 4, 4 ), - KTT_ENTRY1( 5, 5 ), - KTT_ENTRY1( 6, 6 ), - KTT_ENTRY1( 7, 7 ), - KTT_ENTRY1( 8, 8 ), - KTT_ENTRY1( 9, 9 ), - KTT_ENTRY1( 0, 0 ), - KTT_ENTRY0( MINUS, MINUS, 0xbd, '-', "MINUS" ), - KTT_ENTRY0( EQUALS, EQUALS, 0xbb, '=', "EQUALS" ), - KTT_ENTRY0( BACKSPACE, BACKSPACE, 0x08, 0x08, "BACKSPACE" ), - KTT_ENTRY0( TAB, TAB, 0x09, 0x09, "TAB" ), - KTT_ENTRY1( Q, q ), - KTT_ENTRY1( W, w ), - KTT_ENTRY1( E, e ), - KTT_ENTRY1( R, r ), - KTT_ENTRY1( T, t ), - KTT_ENTRY1( Y, y ), - KTT_ENTRY1( U, u ), - KTT_ENTRY1( I, i ), - KTT_ENTRY1( O, o ), - KTT_ENTRY1( P, p ), - KTT_ENTRY0( OPENBRACE, LEFTBRACKET, 0xdb, '[', "OPENBRACE" ), - KTT_ENTRY0( CLOSEBRACE,RIGHTBRACKET, 0xdd, ']', "CLOSEBRACE" ), - KTT_ENTRY0( ENTER, RETURN, 0x0d, 0x0d, "RETURN" ), - KTT_ENTRY2( LCONTROL, LCTRL ), - KTT_ENTRY1( A, a ), - KTT_ENTRY1( S, s ), - KTT_ENTRY1( D, d ), - KTT_ENTRY1( F, f ), - KTT_ENTRY1( G, g ), - KTT_ENTRY1( H, h ), - KTT_ENTRY1( J, j ), - KTT_ENTRY1( K, k ), - KTT_ENTRY1( L, l ), - KTT_ENTRY0( COLON, SEMICOLON, 0xba, ';', "COLON" ), - KTT_ENTRY0( QUOTE, QUOTE, 0xde, '\'', "QUOTE" ), - KTT_ENTRY2( LSHIFT, LSHIFT ), - KTT_ENTRY0( BACKSLASH, BACKSLASH, 0xdc, '\\', "BACKSLASH" ), - KTT_ENTRY1( Z, z ), - KTT_ENTRY1( X, x ), - KTT_ENTRY1( C, c ), - KTT_ENTRY1( V, v ), - KTT_ENTRY1( B, b ), - KTT_ENTRY1( N, n ), - KTT_ENTRY1( M, m ), - KTT_ENTRY0( COMMA, COMMA, 0xbc, ',', "COMMA" ), - KTT_ENTRY0( STOP, PERIOD, 0xbe, '.', "STOP" ), - KTT_ENTRY0( SLASH, SLASH, 0xbf, '/', "SLASH" ), - KTT_ENTRY2( RSHIFT, RSHIFT ), - KTT_ENTRY0( ASTERISK, KP_MULTIPLY, '*', '*', "ASTERIX" ), - KTT_ENTRY2( LALT, LALT ), - KTT_ENTRY0( SPACE, SPACE, ' ', ' ', "SPACE" ), - KTT_ENTRY2( CAPSLOCK, CAPSLOCK ), - KTT_ENTRY2( F1, F1 ), - KTT_ENTRY2( F2, F2 ), - KTT_ENTRY2( F3, F3 ), - KTT_ENTRY2( F4, F4 ), - KTT_ENTRY2( F5, F5 ), - KTT_ENTRY2( F6, F6 ), - KTT_ENTRY2( F7, F7 ), - KTT_ENTRY2( F8, F8 ), - KTT_ENTRY2( F9, F9 ), - KTT_ENTRY2( F10, F10 ), - KTT_ENTRY2( NUMLOCK, NUMLOCK ), - KTT_ENTRY2( SCRLOCK, SCROLLOCK ), - KTT_ENTRY2( 7_PAD, KP7 ), - KTT_ENTRY2( 8_PAD, KP8 ), - KTT_ENTRY2( 9_PAD, KP9 ), - KTT_ENTRY2( MINUS_PAD, KP_MINUS ), - KTT_ENTRY2( 4_PAD, KP4 ), - KTT_ENTRY2( 5_PAD, KP5 ), - KTT_ENTRY2( 6_PAD, KP6 ), - KTT_ENTRY2( PLUS_PAD, KP_PLUS ), - KTT_ENTRY2( 1_PAD, KP1 ), - KTT_ENTRY2( 2_PAD, KP2 ), - KTT_ENTRY2( 3_PAD, KP3 ), - KTT_ENTRY2( 0_PAD, KP0 ), - KTT_ENTRY2( DEL_PAD, KP_PERIOD ), - KTT_ENTRY2( F11, F11 ), - KTT_ENTRY2( F12, F12 ), - KTT_ENTRY2( F13, F13 ), - KTT_ENTRY2( F14, F14 ), - KTT_ENTRY2( F15, F15 ), - KTT_ENTRY2( ENTER_PAD, KP_ENTER ), - KTT_ENTRY2( RCONTROL, RCTRL ), - KTT_ENTRY2( SLASH_PAD, KP_DIVIDE ), - KTT_ENTRY2( PRTSCR, PRINT ), - KTT_ENTRY2( RALT, RALT ), - KTT_ENTRY2( HOME, HOME ), - KTT_ENTRY2( UP, UP ), - KTT_ENTRY2( PGUP, PAGEUP ), - KTT_ENTRY2( LEFT, LEFT ), - KTT_ENTRY2( RIGHT, RIGHT ), - KTT_ENTRY2( END, END ), - KTT_ENTRY2( DOWN, DOWN ), - KTT_ENTRY2( PGDN, PAGEDOWN ), - KTT_ENTRY2( INSERT, INSERT ), - { ITEM_ID_DEL, SDLK_DELETE, "ITEM_ID_DEL", (char *)"DELETE" }, - KTT_ENTRY2( LWIN, LSUPER ), - KTT_ENTRY2( RWIN, RSUPER ), - KTT_ENTRY2( MENU, MENU ), - KTT_ENTRY0( TILDE, BACKQUOTE, 0xc0, '`', "TILDE" ), - KTT_ENTRY0( BACKSLASH2, HASH, 0xdc, '\\', "BACKSLASH2" ), - { ITEM_ID_INVALID } -}; -#endif - -struct key_lookup_table -{ - int code; - const char *name; -}; - -#if (SDLMAME_SDL2) -#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, ""} -}; -#else -#define KE(x) { SDLK_ ## x, "SDLK_" #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) - -static key_lookup_table sdl_lookup_table[] = -{ - KE8(UNKNOWN, FIRST, BACKSPACE, TAB, CLEAR, RETURN, PAUSE, ESCAPE ) - KE8(SPACE, EXCLAIM, QUOTEDBL, HASH, DOLLAR, AMPERSAND, QUOTE, LEFTPAREN ) - KE8(RIGHTPAREN, ASTERISK, PLUS, COMMA, MINUS, PERIOD, SLASH, 0 ) - KE8(1, 2, 3, 4, 5, 6, 7, 8 ) - KE8(9, COLON, SEMICOLON, LESS, EQUALS, GREATER, QUESTION, AT ) - KE8(LEFTBRACKET,BACKSLASH, RIGHTBRACKET, CARET, UNDERSCORE, BACKQUOTE, 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, WORLD_0, WORLD_1, WORLD_2, WORLD_3, WORLD_4, WORLD_5, WORLD_6 ) - KE8(WORLD_7, WORLD_8, WORLD_9, WORLD_10, WORLD_11, WORLD_12, WORLD_13, WORLD_14 ) - KE8(WORLD_15, WORLD_16, WORLD_17, WORLD_18, WORLD_19, WORLD_20, WORLD_21, WORLD_22 ) - KE8(WORLD_23, WORLD_24, WORLD_25, WORLD_26, WORLD_27, WORLD_28, WORLD_29, WORLD_30 ) - KE8(WORLD_31, WORLD_32, WORLD_33, WORLD_34, WORLD_35, WORLD_36, WORLD_37, WORLD_38 ) - KE8(WORLD_39, WORLD_40, WORLD_41, WORLD_42, WORLD_43, WORLD_44, WORLD_45, WORLD_46 ) - KE8(WORLD_47, WORLD_48, WORLD_49, WORLD_50, WORLD_51, WORLD_52, WORLD_53, WORLD_54 ) - KE8(WORLD_55, WORLD_56, WORLD_57, WORLD_58, WORLD_59, WORLD_60, WORLD_61, WORLD_62 ) - KE8(WORLD_63, WORLD_64, WORLD_65, WORLD_66, WORLD_67, WORLD_68, WORLD_69, WORLD_70 ) - KE8(WORLD_71, WORLD_72, WORLD_73, WORLD_74, WORLD_75, WORLD_76, WORLD_77, WORLD_78 ) - KE8(WORLD_79, WORLD_80, WORLD_81, WORLD_82, WORLD_83, WORLD_84, WORLD_85, WORLD_86 ) - KE8(WORLD_87, WORLD_88, WORLD_89, WORLD_90, WORLD_91, WORLD_92, WORLD_93, WORLD_94 ) - KE8(WORLD_95, KP0, KP1, KP2, KP3, KP4, KP5, KP6 ) - KE8(KP7, KP8, KP9, 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, NUMLOCK, CAPSLOCK, SCROLLOCK, RSHIFT, LSHIFT, RCTRL ) - KE8(LCTRL, RALT, LALT, RMETA, LMETA, LSUPER, RSUPER, MODE ) - KE8(COMPOSE, HELP, PRINT, SYSREQ, BREAK, MENU, POWER, EURO ) - KE(UNDO) - KE(LAST) - {-1, ""} -}; -#endif - -//============================================================ -// INLINE FUNCTIONS -//============================================================ - -static int devmap_leastfree(device_map_t *devmap) -{ - int i; - for (i=0;imap[i].name == 0) - return i; - } - return -1; -} - -static char *remove_spaces(running_machine &machine, const char *s) -{ - char *r, *p; - static const char *def_name[] = { "Unknown" }; - - while (*s && *s == ' ') - s++; - - if (strlen(s) == 0) - { - r = auto_alloc_array(machine, char, strlen((char *)def_name) + 1); - strcpy(r, (char *)def_name); - return r; - } - - r = auto_alloc_array(machine, char, strlen(s) + 1); - p = r; - while (*s) - { - if (*s != ' ') - *p++ = *s++; - else - { - while (*s && *s == ' ') - s++; - if (*s) - *p++ = ' '; - } - } - *p = 0; - return r; -} - -static void devmap_register(device_map_t *devmap, int physical_idx, char *name) -{ - int found = 0; - int stick, i; - - for (i=0;imap[i].name) == 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; - } - -} - -//============================================================ -// init_joymap -//============================================================ - -static void devmap_init(running_machine &machine, device_map_t *devmap, const char *opt, int max_devices, const char *label) -{ - int dev; - char defname[20]; - - assert(max_devices <= MAX_DEVMAP_ENTRIES); - - for (dev = 0; dev < MAX_DEVMAP_ENTRIES; dev++) - { - devmap->map[dev].name = (char *)""; - devmap->map[dev].physical = -1; - devmap->logical[dev] = -1; - } - devmap->initialized = 0; - - for (dev = 0; dev < max_devices; dev++) - { - const char *dev_name; - sprintf(defname, "%s%d", opt, dev + 1); - - dev_name = machine.options().value(defname); - if (dev_name && *dev_name && strcmp(dev_name,OSDOPTVAL_AUTO)) - { - devmap->map[dev].name = remove_spaces(machine, dev_name); - osd_printf_verbose("%s: Logical id %d: %s\n", label, dev + 1, devmap->map[dev].name); - devmap->initialized = 1; - } - } -} - -static device_info *devmap_class_register(running_machine &machine, device_map_t *devmap, - int index, device_info **devlist, input_device_class devclass) -{ - device_info *devinfo = NULL; - char tempname[20]; - - if (*devmap->map[index].name == 0) - { - /* only map place holders if there were mappings specified is enabled */ - if (devmap->initialized) - { - sprintf(tempname, "NC%d", index); - devinfo = generic_device_alloc(devlist, tempname); - devinfo->device = machine.input().device_class(devclass).add_device(devinfo->name.c_str(), devinfo); - } - return NULL; - } - else - { - devinfo = generic_device_alloc(devlist, devmap->map[index].name); - devinfo->device = machine.input().device_class(devclass).add_device(devinfo->name.c_str(), devinfo); - } - return devinfo; -} - - -//============================================================ -// sdlinput_register_joysticks -//============================================================ - -static void sdlinput_register_joysticks(running_machine &machine) -{ - device_info *devinfo; - int physical_stick, axis, button, hat, stick, ball; - char tempname[512]; - SDL_Joystick *joy; - - devmap_init(machine, &joy_map, SDLOPTION_JOYINDEX, 8, "Joystick mapping"); - - osd_printf_verbose("Joystick: Start initialization\n"); - for (physical_stick = 0; physical_stick < SDL_NumJoysticks(); physical_stick++) - { - char *joy_name; - -#if (SDLMAME_SDL2) - joy = SDL_JoystickOpen(physical_stick); - joy_name = remove_spaces(machine, SDL_JoystickName(joy)); - SDL_JoystickClose(joy); -#else - joy_name = remove_spaces(machine, SDL_JoystickName(physical_stick)); -#endif - - devmap_register(&joy_map, physical_stick, joy_name); - } - - for (stick = 0; stick < MAX_DEVMAP_ENTRIES; stick++) - { - devinfo = devmap_class_register(machine, &joy_map, stick, &joystick_list, DEVICE_CLASS_JOYSTICK); - - if (devinfo == NULL) - continue; - - physical_stick = joy_map.map[stick].physical; - - joy = SDL_JoystickOpen(physical_stick); - - devinfo->joystick.device = joy; - - osd_printf_verbose("Joystick: %s\n", devinfo->name.c_str()); - 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 (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; - - sprintf(tempname, "A%d %s", axis, devinfo->name.c_str()); - devinfo->device->add_item(tempname, itemid, generic_axis_get_state, &devinfo->joystick.axes[axis]); - } - - // loop over all buttons - for (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; - - sprintf(tempname, "button %d", button); - devinfo->device->add_item(tempname, itemid, generic_button_get_state, &devinfo->joystick.buttons[button]); - } - - // loop over all hats - for (hat = 0; hat < SDL_JoystickNumHats(joy); hat++) - { - input_item_id itemid; - - sprintf(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]); - sprintf(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]); - sprintf(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]); - sprintf(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 (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; - - sprintf(tempname, "R%d %s", ball * 2, devinfo->name.c_str()); - devinfo->device->add_item(tempname, (input_item_id) itemid, generic_axis_get_state, &devinfo->joystick.balls[ball * 2]); - sprintf(tempname, "R%d %s", ball * 2 + 1, devinfo->name.c_str()); - devinfo->device->add_item(tempname, (input_item_id) (itemid + 1), generic_axis_get_state, &devinfo->joystick.balls[ball * 2 + 1]); - } - } - osd_printf_verbose("Joystick: End initialization\n"); -} - -//============================================================ -// sdlinput_deregister_joysticks -//============================================================ - -static void sdlinput_deregister_joysticks(running_machine &machine) -{ - device_info *curdev; - - osd_printf_verbose("Joystick: Start deinitialization\n"); - - for (curdev = joystick_list; curdev != NULL; curdev = curdev->next) - { - SDL_JoystickClose(curdev->joystick.device); - } - - osd_printf_verbose("Joystick: End deinitialization\n"); -} - -//============================================================ -// sdlinput_register_mice -//============================================================ - -#if defined(SDL2_MULTIAPI) && 0 -static void sdlinput_register_mice(running_machine &machine) -{ - int index, physical_mouse; - - mouse_enabled = machine.options().mouse(); - - devmap_init(machine, &mouse_map, SDLOPTION_MOUSEINDEX, 8, "Mouse mapping"); - - for (physical_mouse = 0; physical_mouse < SDL_GetNumMice(); physical_mouse++) - { - char *mouse_name = remove_spaces(machine, SDL_GetMouseName(physical_mouse)); - - devmap_register(&mouse_map, physical_mouse, mouse_name); - } - - osd_printf_verbose("Mouse: Start initialization\n"); - for (index = 0; index < MAX_DEVMAP_ENTRIES; index++) - { - device_info *devinfo; - char defname[90]; - int button; - - devinfo = devmap_class_register(machine, &mouse_map, index, &mouse_list, DEVICE_CLASS_MOUSE); - - if (devinfo == NULL) - continue; - - // add the axes - sprintf(defname, "X %s", devinfo->name.c_str()); - devinfo->device->add_item(defname, ITEM_ID_XAXIS, generic_axis_get_state, &devinfo->mouse.lX); - sprintf(defname, "Y %s", devinfo->name.c_str()); - devinfo->device->add_item(defname, ITEM_ID_YAXIS, generic_axis_get_state, &devinfo->mouse.lY); - - for (button = 0; button < 4; button++) - { - input_item_id itemid; - - sprintf(defname, "B%d", button + 1); - itemid = (input_item_id) (ITEM_ID_BUTTON1+button); - - devinfo->device->add_item(defname, itemid, generic_button_get_state, &devinfo->mouse.buttons[button]); - } - - if (0 && mouse_enabled) - SDL_SetRelativeMouseMode(index, SDL_TRUE); - osd_printf_verbose("Mouse: Registered %s\n", devinfo->name.c_str()); - } - osd_printf_verbose("Mouse: End initialization\n"); -} -#else -static void sdlinput_register_mice(running_machine &machine) -{ - device_info *devinfo; - char defname[20]; - int button; - - osd_printf_verbose("Mouse: Start initialization\n"); - - mouse_map.logical[0] = 0; - - // SDL 1.2 has only 1 mouse - 1.3+ will also change that, so revisit this then - devinfo = generic_device_alloc(&mouse_list, "System mouse"); - devinfo->device = machine.input().device_class(DEVICE_CLASS_MOUSE).add_device(devinfo->name.c_str(), devinfo); - - mouse_enabled = machine.options().mouse(); - - // 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); - sprintf(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.c_str()); - osd_printf_verbose("Mouse: End initialization\n"); -} -#endif - -#if (USE_XINPUT) -//============================================================ -// lightgun helpers: copy-past from xinfo -//============================================================ - -XDeviceInfo* -find_device_info(Display *display, - 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= IsXExtensionDevice)) && - ((!is_id && strcmp(devices[loop].name, name) == 0) || - (is_id && devices[loop].id == id))) { - if (found) { - fprintf(stderr, - "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, - 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) { - fprintf(stderr, "unable to open device %s\n", dev_name); - return 0; - } - - if (device->num_classes > 0) { - for (ip = device->classes, i=0; inum_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++; - fprintf(stderr, "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: - fprintf(stderr, "unknown class\n"); - break; - } - } - - if (XSelectExtensionEvent(dpy, root_win, event_list, number)) { - fprintf(stderr, "error selecting extended events\n"); - return 0; - } - } - return number; -} - -//============================================================ -// sdlinput_register_lightguns -//============================================================ - -static void sdlinput_register_lightguns(running_machine &machine) -{ - int index; - XExtensionVersion *version; - - lightgun_enabled = machine.options().lightgun(); - devmap_init(machine, &lightgun_map, SDLOPTION_LIGHTGUNINDEX, 8, "Lightgun mapping"); - - XDisplay = XOpenDisplay(NULL); - - if (XDisplay == NULL) { - fprintf(stderr, "Unable to connect to X server\n"); - return; - } - - version = XGetExtensionVersion(XDisplay, INAME); - - if (!version || (version == (XExtensionVersion*) NoSuchExtension)) { - fprintf(stderr, "xinput extension not available!\n"); - return; - } - - - for (index=0; index<8; index++) { - XDeviceInfo *info; - if (strlen(lightgun_map.map[index].name)!=0) { - device_info *devinfo; - char *name=lightgun_map.map[index].name; - char defname[512]; - devinfo = devmap_class_register(machine, &lightgun_map, index, &lightgun_list, DEVICE_CLASS_LIGHTGUN); - fprintf(stderr, "%i: %s\n",index, name); - info=find_device_info(XDisplay, name, 0); - if (!info) continue; - - //Grab device info and translate to stuff mame can use - if (info->num_classes > 0) { - XAnyClassPtr any = (XAnyClassPtr) (info->inputclassinfo); - int i; - for (i=0; inum_classes; i++) { - int button; - XValuatorInfoPtr v; - XAxisInfoPtr a; - int j; - XButtonInfoPtr b; -#if defined(__cplusplus) || defined(c_plusplus) - switch (any->c_class) { -#else - switch (any->class) { -#endif - case ButtonClass: - b = (XButtonInfoPtr) any; - for (button = 0; button < b->num_buttons; button++) - { - input_item_id itemid; - itemid = (input_item_id) (ITEM_ID_BUTTON1 + button); - sprintf(defname, "B%d", button + 1); - devinfo->device->add_item(defname, itemid, generic_button_get_state, &devinfo->lightgun.buttons[button]); - } - break; - case ValuatorClass: - v = (XValuatorInfoPtr) any; - a = (XAxisInfoPtr) ((char *) v + sizeof (XValuatorInfo)); - for (j=0; jnum_axes; j++, a++) { - if (j==0) { -#if (USE_XINPUT_DEBUG) - fprintf(stderr, "For index %d: Set minx=%d, maxx=%d\n", - index, - a->min_value, a->max_value); -#endif - devinfo->lightgun.maxx=a->max_value; - devinfo->lightgun.minx=a->min_value; - } - if (j==1) { -#if (USE_XINPUT_DEBUG) - fprintf(stderr, "For index %d: Set miny=%d, maxy=%d\n", - index, - a->min_value, a->max_value); -#endif - devinfo->lightgun.maxy=a->max_value; - devinfo->lightgun.miny=a->min_value; - } - } - break; - } - any = (XAnyClassPtr) ((char *) any + any->length); - } - } - - - sprintf(defname, "X %s", devinfo->name.c_str()); - devinfo->device->add_item(defname, ITEM_ID_XAXIS, generic_axis_get_state, &devinfo->lightgun.lX); - sprintf(defname, "Y %s", devinfo->name.c_str()); - devinfo->device->add_item(defname, ITEM_ID_YAXIS, generic_axis_get_state, &devinfo->lightgun.lY); - - - devinfo->lightgun.deviceid=info->id; - if (!info) { - fprintf(stderr, "Can't find device %s!\n", lightgun_map.map[index].name); - } else { - fprintf(stderr, "Device %i: Registered %i events.\n",(int)info->id, register_events(XDisplay, info, lightgun_map.map[index].name, 0)); - } - } - } - osd_printf_verbose("Lightgun: End initialization\n"); -} -#endif - -//============================================================ -// 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; -} - - -//============================================================ -// lookup_mame_code -//============================================================ - -static int lookup_mame_index(const char *scode) -{ - int index, i; - - index=-1; - i=0; - while (sdl_key_trans_table[i].mame_key != ITEM_ID_INVALID) - { - if (!strcmp(scode, sdl_key_trans_table[i].mame_key_name)) - { - index=i; - break; - } - i++; - } - return index; -} - -static input_item_id lookup_mame_code(const char *scode) -{ - int index; - index = lookup_mame_index(scode); - if (index >= 0) - return sdl_key_trans_table[index].mame_key; - else - return ITEM_ID_INVALID; -} - - -//============================================================ -// sdlinput_read_keymap -//============================================================ - -static kt_table * sdlinput_read_keymap(running_machine &machine) -{ - char *keymap_filename; - kt_table *key_trans_table; - 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; - - if (!machine.options().bool_value(SDLOPTION_KEYMAP)) - return sdl_key_trans_table; - - keymap_filename = (char *)downcast(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 sdl_key_trans_table; - } - - key_trans_table = auto_alloc_array(machine, kt_table, ARRAY_LENGTH(sdl_key_trans_table)); - memcpy((void *) key_trans_table, sdl_key_trans_table, sizeof(sdl_key_trans_table)); - - 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=lookup_mame_index(mks); - sk = lookup_sdl_code(sks); - - if ( sk >= 0 && index >=0) - { - key_trans_table[index].sdl_key = sk; - // vk and ak are not really needed - //key_trans_table[index][VIRTUAL_KEY] = vk; - //key_trans_table[index][ASCII_KEY] = ak; - key_trans_table[index].ui_name = auto_alloc_array(machine, char, strlen(kns)+1); - strcpy(key_trans_table[index].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 key_trans_table; -} - - -//============================================================ -// sdlinput_register_keyboards -//============================================================ - -#ifdef SDL2_MULTIAPI -static void sdlinput_register_keyboards(running_machine &machine) -{ - int physical_keyboard; - int index; - kt_table *key_trans_table; - - key_trans_table = sdlinput_read_keymap(machine); - - devmap_init(machine, &keyboard_map, SDLOPTION_KEYBINDEX, 8, "Keyboard mapping"); - - for (physical_keyboard = 0; physical_keyboard < SDL_GetNumKeyboards(); physical_keyboard++) - { - //char defname[90]; - //snprintf(defname, sizeof(defname)-1, "Keyboard #%d", physical_keyboard + 1); - char *defname = remove_spaces(machine, SDL_GetKeyboardName(SDL_GetKeyboard(physical_keyboard) )); - - devmap_register(&keyboard_map, physical_keyboard, defname); - } - - osd_printf_verbose("Keyboard: Start initialization\n"); - for (index = 0; index < MAX_DEVMAP_ENTRIES; index++) - { - device_info *devinfo; - char defname[90]; - int keynum; - - devinfo = devmap_class_register(machine, &keyboard_map, index, &keyboard_list, DEVICE_CLASS_KEYBOARD); - - if (devinfo == NULL) - continue; - - // populate it - for (keynum = 0; sdl_key_trans_table[keynum].mame_key!= ITEM_ID_INVALID; keynum++) - { - input_item_id itemid; - - itemid = key_trans_table[keynum].mame_key; - - // generate the default / modified name - snprintf(defname, sizeof(defname)-1, "%s", key_trans_table[keynum].ui_name); - - // add the item to the device - devinfo->device->add_item(defname, itemid, generic_button_get_state, &devinfo->keyboard.state[OSD_SDL_INDEX(key_trans_table[keynum].sdl_key)]); - } - - osd_printf_verbose("Keyboard: Registered %s\n", devinfo->name.c_str()); - } - osd_printf_verbose("Keyboard: End initialization\n"); -} -#else -static void sdlinput_register_keyboards(running_machine &machine) -{ - device_info *devinfo; - char defname[20]; - int keynum; - kt_table *key_trans_table; - - key_trans_table = sdlinput_read_keymap(machine); - - keyboard_map.logical[0] = 0; - - osd_printf_verbose("Keyboard: Start initialization\n"); - - // SDL 1.2 only has 1 keyboard (1.3+ will have multiple, this must be revisited then) - // add it now - devinfo = generic_device_alloc(&keyboard_list, "System keyboard"); - devinfo->device = machine.input().device_class(DEVICE_CLASS_KEYBOARD).add_device(devinfo->name.c_str(), devinfo); - - // populate it - for (keynum = 0; sdl_key_trans_table[keynum].mame_key != ITEM_ID_INVALID; keynum++) - { - input_item_id itemid; - - itemid = key_trans_table[keynum].mame_key; - - // generate the default / modified name - snprintf(defname, sizeof(defname)-1, "%s", key_trans_table[keynum].ui_name); - - // add the item to the device -// printf("Keynum %d => sdl key %d\n", keynum, OSD_SDL_INDEX(key_trans_table[keynum].sdl_key)); - devinfo->device->add_item(defname, itemid, generic_button_get_state, &devinfo->keyboard.state[OSD_SDL_INDEX(key_trans_table[keynum].sdl_key)]); - } - - osd_printf_verbose("Keyboard: Registered %s\n", devinfo->name.c_str()); - osd_printf_verbose("Keyboard: End initialization\n"); -} -#endif - -//============================================================ -// input_init -//============================================================ - -bool sdl_osd_interface::input_init() -{ - keyboard_list = NULL; - joystick_list = NULL; - mouse_list = NULL; - lightgun_list = NULL; - - app_has_mouse_focus = 1; - - // register the keyboards - sdlinput_register_keyboards(machine()); - - // register the mice - sdlinput_register_mice(machine()); - -#if (USE_XINPUT) - // register the lightguns - sdlinput_register_lightguns(machine()); -#endif - - if (machine().debug_flags & DEBUG_FLAG_OSD_ENABLED) - { - osd_printf_warning("Debug Build: Disabling input grab for -debug\n"); - mouse_enabled = 0; - } - - // get Sixaxis special mode info - sixaxis_mode = options().sixaxis(); - - // register the joysticks - sdlinput_register_joysticks(machine()); - - // now reset all devices - device_list_reset_devices(keyboard_list); - device_list_reset_devices(mouse_list); - device_list_reset_devices(joystick_list); -#if (USE_XINPUT) - device_list_reset_devices(lightgun_list); -#endif - return true; -} - - -//============================================================ -// sdlinput_pause -//============================================================ - -void sdl_osd_interface::input_pause() -{ - // keep track of the paused state - input_paused = true; -} - -void sdl_osd_interface::input_resume() -{ - // keep track of the paused state - input_paused = false; -} - - -//============================================================ -// sdlinput_exit -//============================================================ - -void sdl_osd_interface::input_exit() -{ - // deregister - - sdlinput_deregister_joysticks(machine()); - - // free all devices - device_list_free_devices(&keyboard_list); - device_list_free_devices(&mouse_list); - device_list_free_devices(&joystick_list); -} - - -//============================================================ -// sdlinput_get_focus_window -//============================================================ - -sdl_window_info *sdlinput_get_focus_window() -{ - if (focus_window) // only be set on SDL >= 1.3 - return focus_window; - else - return sdl_window_list; -} - -#if (USE_XINPUT) -device_info *get_lightgun_info_for_deviceid(XID deviceid) { - device_info *devinfo; - int index; - //Find lightgun according to device id - for (index=0; ; index++) { - devinfo = generic_device_find_index(lightgun_list, index); - if (devinfo==NULL) break; - if (devinfo->lightgun.deviceid==deviceid) break; - } - return devinfo; -} - -INT32 normalize_absolute_axis(INT32 raw, INT32 rawmin, INT32 rawmax) -{ - INT32 rv; - - INT32 center = ((INT64)rawmax + (INT64)rawmin) / 2; - - // make sure we have valid data - if (rawmin >= rawmax) - { - rv = raw; - goto out; - } - - // above center - if (raw >= center) - { - INT32 result = (INT64)(raw - center) * (INT64)INPUT_ABSOLUTE_MAX / (INT64)(rawmax - center); - rv = MIN(result, INPUT_ABSOLUTE_MAX); - goto out; - } - - // below center - else - { - INT32 result = -((INT64)(center - raw) * (INT64)-INPUT_ABSOLUTE_MIN / (INT64)(center - rawmin)); - rv = MAX(result, INPUT_ABSOLUTE_MIN); - goto out; - } - - out: - -#if (USE_XINPUT_DEBUG) - fprintf(stderr, "raw: %d, rawmin: %d, rawmax: %d, center: %d, rv: %d, ABS_MIN: %d, ABS_MAX: %d\n", - raw, rawmin, rawmax, center, rv, INPUT_ABSOLUTE_MIN, INPUT_ABSOLUTE_MAX); -#endif - - return rv; -} -#endif - -//============================================================ -// sdlinput_poll -//============================================================ - -#if (SDLMAME_SDL2) -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; -} - -static inline void resize_all_windows(void) -{ - sdl_window_info *w; - osd_ticks_t now = osd_ticks(); - - if (SDL13_COMBINE_RESIZE) - { - for (w = sdl_window_list; w != NULL; w = w->m_next) - { - if (w->m_resize_width && w->m_resize_height && ((now - w->m_last_resize) > osd_ticks_per_second() / 10)) - { - w->resize(w->m_resize_width, w->m_resize_height); - w->m_resize_width = 0; - w->m_resize_height = 0; - } - } - } -} - -#endif - -void sdlinput_process_events_buf() -{ - SDL_Event event; - - if (SDLMAME_EVENTS_IN_WORKER_THREAD) - { - std::lock_guard lock(input_lock); - #if (SDLMAME_SDL2) - /* Make sure we get all pending events */ - SDL_PumpEvents(); - #endif - while(SDL_PollEvent(&event)) - { - if (event_buf_count < MAX_BUF_EVENTS) - event_buf[event_buf_count++] = event; - else - osd_printf_warning("Event Buffer Overflow!\n"); - } - } - else - SDL_PumpEvents(); -} - - -void sdlinput_poll(running_machine &machine) -{ - device_info *devinfo; - SDL_Event event; - int index; - - // only for SDLMAME_EVENTS_IN_WORKER_THREAD - SDL_Event loc_event_buf[MAX_BUF_EVENTS]; - int loc_event_buf_count; - int bufp; - -#if (USE_XINPUT) - XEvent xevent; -#endif - - for (index=0; ;index++) - { - devinfo = generic_device_find_index( mouse_list, index); - if (devinfo == NULL) - break; - devinfo->mouse.lX = 0; - devinfo->mouse.lY = 0; - } - -#if (USE_XINPUT) - //Get XInput events - while (XPending(XDisplay)!=0) - { - XNextEvent(XDisplay, &xevent); - if (xevent.type==motion_type) - { - XDeviceMotionEvent *motion = (XDeviceMotionEvent *) &xevent; - -#if (USE_XINPUT_DEBUG) - /* - * print a lot of debug informations of the motion event(s). - */ - fprintf(stderr, - "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] - ); -#endif - - devinfo=get_lightgun_info_for_deviceid(motion->deviceid); - - /* - * 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) - { - devinfo->lightgun.lX=normalize_absolute_axis(motion->axis_data[0], devinfo->lightgun.minx, devinfo->lightgun.maxx); - if (motion->axes_count >= 2) - { - devinfo->lightgun.lY=normalize_absolute_axis(motion->axis_data[1], devinfo->lightgun.miny, devinfo->lightgun.maxy); - } - } - break; - - /* - * Starting with y, ... - */ - case 1: - if (motion->axes_count >= 1) - { - devinfo->lightgun.lY=normalize_absolute_axis(motion->axis_data[0], devinfo->lightgun.miny, devinfo->lightgun.maxy); - } - break; - } - } - else if (xevent.type==button_press_type || xevent.type==button_release_type) - { - XDeviceButtonEvent *button = (XDeviceButtonEvent *) &xevent; - devinfo=get_lightgun_info_for_deviceid(button->deviceid); - devinfo->lightgun.buttons[button->button]=(xevent.type==button_press_type)?0x80:0; - } - } -#endif - - if (SDLMAME_EVENTS_IN_WORKER_THREAD) - { - std::lock_guard lock(input_lock); - memcpy(loc_event_buf, event_buf, sizeof(event_buf)); - loc_event_buf_count = event_buf_count; - event_buf_count = 0; - bufp = 0; - } - - while (TRUE) - { - if (SDLMAME_EVENTS_IN_WORKER_THREAD) - { - if (bufp >= loc_event_buf_count) - break; - event = loc_event_buf[bufp++]; - } - else - { - if (!SDL_PollEvent(&event)) - break; - } - switch(event.type) { - case SDL_KEYDOWN: -#ifdef SDL2_MULTIAPI - devinfo = generic_device_find_index( keyboard_list, keyboard_map.logical[event.key.which]); - //printf("Key down %d %d %s => %d %s (scrlock keycode is %d)\n", event.key.which, event.key.keysym.scancode, devinfo->name.c_str(), OSD_SDL_INDEX_KEYSYM(&event.key.keysym), sdl_key_trans_table[event.key.keysym.scancode].mame_key_name, KEYCODE_SCRLOCK); -#else - devinfo = generic_device_find_index( keyboard_list, keyboard_map.logical[0]); -#endif - devinfo->keyboard.state[OSD_SDL_INDEX_KEYSYM(&event.key.keysym)] = 0x80; -#if (SDLMAME_SDL2) - if (event.key.keysym.sym < 0x20) - machine.ui_input().push_char_event(sdl_window_list->target(), event.key.keysym.sym); -#else - ui_input_push_char_event(machine, sdl_window_list->target(), (unicode_char) event.key.keysym.unicode); -#endif - break; - case SDL_KEYUP: -#ifdef SDL2_MULTIAPI - devinfo = generic_device_find_index( keyboard_list, keyboard_map.logical[event.key.which]); - //printf("Key up: %d %d\n", OSD_SDL_INDEX_KEYSYM(&event.key.keysym), event.key.which); -#else - devinfo = generic_device_find_index( keyboard_list, keyboard_map.logical[0]); -#endif - devinfo->keyboard.state[OSD_SDL_INDEX_KEYSYM(&event.key.keysym)] = 0x00; - break; - case SDL_JOYAXISMOTION: - devinfo = generic_device_find_index(joystick_list, joy_map.logical[event.jaxis.which]); - if (devinfo) - { - if (sixaxis_mode) - { - int axis = event.jaxis.axis; - - if (axis <= 3) - { - devinfo->joystick.axes[event.jaxis.axis] = (event.jaxis.value * 2); - } - else - { - int magic = (event.jaxis.value / 2) + 16384; - - devinfo->joystick.axes[event.jaxis.axis] = magic; - } - } - else - { - devinfo->joystick.axes[event.jaxis.axis] = (event.jaxis.value * 2); - } - } - break; - case SDL_JOYHATMOTION: - devinfo = generic_device_find_index(joystick_list, joy_map.logical[event.jhat.which]); - if (devinfo) - { - if (event.jhat.value & SDL_HAT_UP) - { - devinfo->joystick.hatsU[event.jhat.hat] = 0x80; - } - else - { - devinfo->joystick.hatsU[event.jhat.hat] = 0; - } - if (event.jhat.value & SDL_HAT_DOWN) - { - devinfo->joystick.hatsD[event.jhat.hat] = 0x80; - } - else - { - devinfo->joystick.hatsD[event.jhat.hat] = 0; - } - if (event.jhat.value & SDL_HAT_LEFT) - { - devinfo->joystick.hatsL[event.jhat.hat] = 0x80; - } - else - { - devinfo->joystick.hatsL[event.jhat.hat] = 0; - } - if (event.jhat.value & SDL_HAT_RIGHT) - { - devinfo->joystick.hatsR[event.jhat.hat] = 0x80; - } - else - { - devinfo->joystick.hatsR[event.jhat.hat] = 0; - } - } - break; - case SDL_JOYBUTTONDOWN: - case SDL_JOYBUTTONUP: - devinfo = generic_device_find_index(joystick_list, joy_map.logical[event.jbutton.which]); - if (devinfo) - { - devinfo->joystick.buttons[event.jbutton.button] = (event.jbutton.state == SDL_PRESSED) ? 0x80 : 0; - } - break; - case SDL_MOUSEBUTTONDOWN: -#ifdef SDL2_MULTIAPI - devinfo = generic_device_find_index(mouse_list, mouse_map.logical[event.button.which]); -#else - devinfo = generic_device_find_index(mouse_list, mouse_map.logical[0]); -#endif - devinfo->mouse.buttons[event.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 (event.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(&event.button); - if (window != NULL && window->xy_to_render_target(event.button.x,event.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; - } - } - } -#if (!SDLMAME_SDL2) - else if (event.button.button == 4) // SDL_BUTTON_WHEELUP - { - int cx, cy; - sdl_window_info *window = GET_FOCUS_WINDOW(&event.button); - if (window != NULL && window->xy_to_render_target(event.button.x,event.button.y, &cx, &cy) ) - { - machine.ui_input().push_mouse_wheel_event(window->target(), cx, cy, 120, 3); - } - } - - else if (event.button.button == 5) // SDL_BUTTON_WHEELDOWN - { - int cx, cy; - sdl_window_info *window = GET_FOCUS_WINDOW(&event.button); - if (window != NULL && window->xy_to_render_target(event.button.x,event.button.y, &cx, &cy) ) - { - machine.ui_input().push_mouse_wheel_event(window->target(), cx, cy, -120, 3); - } - } -#endif - break; -#if (SDLMAME_SDL2) - case SDL_MOUSEWHEEL: -#ifdef SDL2_MULTIAPI - devinfo = generic_device_find_index(mouse_list, mouse_map.logical[event.wheel.which]); -#else - devinfo = generic_device_find_index(mouse_list, mouse_map.logical[0]); -#endif - if (devinfo) - { - sdl_window_info *window = GET_FOCUS_WINDOW(&event.wheel); - if (window != NULL) - machine.ui_input().push_mouse_wheel_event(window->target(), 0, 0, event.wheel.y, 3); - } - break; -#endif - case SDL_MOUSEBUTTONUP: -#ifdef SDL2_MULTIAPI - devinfo = generic_device_find_index(mouse_list, mouse_map.logical[event.button.which]); -#else - devinfo = generic_device_find_index(mouse_list, mouse_map.logical[0]); -#endif - devinfo->mouse.buttons[event.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 (event.button.button == 1) - { - int cx, cy; - sdl_window_info *window = GET_FOCUS_WINDOW(&event.button); - - if (window != NULL && window->xy_to_render_target(event.button.x,event.button.y, &cx, &cy) ) - { - machine.ui_input().push_mouse_up_event(window->target(), cx, cy); - } - } - break; - case SDL_MOUSEMOTION: -#ifdef SDL2_MULTIAPI - devinfo = generic_device_find_index(mouse_list, mouse_map.logical[event.motion.which]); -#else - devinfo = generic_device_find_index(mouse_list, mouse_map.logical[0]); -#endif -#if (SDLMAME_SDL2) - // FIXME: may apply to 1.2 as well ... - //printf("Motion %d %d %d %s\n", event.motion.which, event.motion.x, event.motion.y, devinfo->name.c_str()); - devinfo->mouse.lX += event.motion.xrel * INPUT_RELATIVE_PER_PIXEL; - devinfo->mouse.lY += event.motion.yrel * INPUT_RELATIVE_PER_PIXEL; -#else - devinfo->mouse.lX = event.motion.xrel * INPUT_RELATIVE_PER_PIXEL; - devinfo->mouse.lY = event.motion.yrel * INPUT_RELATIVE_PER_PIXEL; -#endif - { - int cx=-1, cy=-1; - sdl_window_info *window = GET_FOCUS_WINDOW(&event.motion); - - if (window != NULL && window->xy_to_render_target(event.motion.x, event.motion.y, &cx, &cy) ) - machine.ui_input().push_mouse_move_event(window->target(), cx, cy); - } - break; - case SDL_JOYBALLMOTION: - devinfo = generic_device_find_index(joystick_list, joy_map.logical[event.jball.which]); - //printf("Ball %d %d\n", event.jball.xrel, event.jball.yrel); - devinfo->joystick.balls[event.jball.ball * 2] = event.jball.xrel * INPUT_RELATIVE_PER_PIXEL; - devinfo->joystick.balls[event.jball.ball * 2 + 1] = event.jball.yrel * INPUT_RELATIVE_PER_PIXEL; - break; -#if (!SDLMAME_SDL2) - case SDL_APPMOUSEFOCUS: - app_has_mouse_focus = event.active.gain; - if (!event.active.gain) - { - sdl_window_info *window = GET_FOCUS_WINDOW(&event.motion); - ui_input_push_mouse_leave_event(machine, window->target()); - } - break; - case SDL_QUIT: - machine.schedule_exit(); - break; - case SDL_VIDEORESIZE: - sdl_window_list->resize(event.resize.w, event.resize.h); - break; -#else - case SDL_TEXTINPUT: - if (*event.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, event.text.text, 1); - machine.ui_input().push_char_event(window->target(), result); - } - } - break; - case SDL_WINDOWEVENT: - { - sdl_window_info *window = GET_WINDOW(&event.window); - - if (window == NULL) - break; - - switch (event.window.event) - { - case SDL_WINDOWEVENT_CLOSE: - machine.schedule_exit(); - break; - case SDL_WINDOWEVENT_LEAVE: - machine.ui_input().push_mouse_leave_event(window->target()); - app_has_mouse_focus = 0; - break; - case SDL_WINDOWEVENT_MOVED: - window->notify_changed(); - focus_window = window; - break; - case SDL_WINDOWEVENT_RESIZED: - if (SDL13_COMBINE_RESIZE) - { - window->m_resize_width = event.window.data1; - window->m_resize_height = event.window.data2; - window->m_last_resize = osd_ticks(); - } - else - { -#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(event.window.data1, event.window.data2); - } - } - focus_window = window; - break; - case SDL_WINDOWEVENT_ENTER: - app_has_mouse_focus = 1; - /* fall through */ - case SDL_WINDOWEVENT_FOCUS_GAINED: - case SDL_WINDOWEVENT_EXPOSED: - case SDL_WINDOWEVENT_MAXIMIZED: - case SDL_WINDOWEVENT_RESTORED: - focus_window = window; - break; - } - break; - } -#endif - } - } -#if (SDLMAME_SDL2) - resize_all_windows(); -#endif -} - - -//============================================================ -// sdlinput_release_keys -//============================================================ - - -void sdlinput_release_keys() -{ - // FIXME: SDL >= 1.3 will nuke the window event buffer when - // a window is closed. This will leave keys in a pressed - // state when a window is destroyed and recreated. -#if (SDLMAME_SDL2) - device_info *devinfo; - int index; - - for (index = 0; ;index++) - { - devinfo = generic_device_find_index( keyboard_list, index); - if (devinfo == NULL) - break; - memset(&devinfo->keyboard.state, 0, sizeof(devinfo->keyboard.state)); - } -#endif -} - - -//============================================================ -// sdlinput_should_hide_mouse -//============================================================ - -int sdlinput_should_hide_mouse() -{ - // if we are paused, no - if (input_paused) - return FALSE; - - // if neither mice nor lightguns enabled in the core, then no - if (!mouse_enabled && !lightgun_enabled) - return FALSE; - - if (!app_has_mouse_focus) - return FALSE; - - // otherwise, yes - return TRUE; -} - - -//============================================================ -// customize_input_type_list -//============================================================ - -void sdl_osd_interface::customize_input_type_list(simple_list &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 = lookup_mame_code("ITEM_ID_INSERT"); - #else - mameid_code = lookup_mame_code("ITEM_ID_SCRLOCK"); - #endif - } - else - { - snprintf(fullmode, 63, "ITEM_ID_%s", uimode); - mameid_code = 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; - } - } -} - - -//============================================================ -// device_list_reset_devices -//============================================================ - -static void device_list_reset_devices(device_info *devlist_head) -{ - device_info *curdev; - - for (curdev = devlist_head; curdev != NULL; curdev = curdev->next) - generic_device_reset(curdev); -} - - -//============================================================ -// device_list_free_devices -//============================================================ - -static void device_list_free_devices(device_info **devlist_head) -{ - device_info *curdev, *next; - - for (curdev = *devlist_head; curdev != NULL; ) - { - next = curdev->next; - generic_device_free(curdev); - curdev = next; - } - *devlist_head = NULL; -} - - -//============================================================ -// generic_device_alloc -//============================================================ - -static device_info *generic_device_alloc(device_info **devlist_head_ptr, const char *name) -{ - device_info **curdev_ptr; - device_info *devinfo; - - // allocate memory for the device object - devinfo = global_alloc_clear(); - devinfo->head = devlist_head_ptr; - - // allocate a UTF8 copy of the name - devinfo->name.assign(name); - - // append us to the list - for (curdev_ptr = devinfo->head; *curdev_ptr != NULL; curdev_ptr = &(*curdev_ptr)->next) ; - *curdev_ptr = devinfo; - - return devinfo; -} - - -//============================================================ -// generic_device_free -//============================================================ - -static void generic_device_free(device_info *devinfo) -{ - device_info **curdev_ptr; - - // remove us from the list - for (curdev_ptr = devinfo->head; *curdev_ptr != devinfo && *curdev_ptr != NULL; curdev_ptr = &(*curdev_ptr)->next) ; - if (*curdev_ptr == devinfo) - *curdev_ptr = devinfo->next; - - // and now free the info - global_free(devinfo); -} - - -//============================================================ -// generic_device_index -//============================================================ - -static int generic_device_index(device_info *devlist_head, device_info *devinfo) -{ - int index = 0; - while (devlist_head != NULL) - { - if (devlist_head == devinfo) - return index; - index++; - devlist_head = devlist_head->next; - } - return -1; -} - - -static device_info *generic_device_find_index(device_info *devlist_head, int index) -{ - device_info *orig_head = devlist_head; - - while (devlist_head != NULL) - { - if (generic_device_index(orig_head, devlist_head) == index) - { - return devlist_head; - } - - devlist_head = devlist_head->next; - } - return NULL; -} - - -//============================================================ -// generic_device_reset -//============================================================ - -static void generic_device_reset(device_info *devinfo) -{ - // keyboard case - if (devinfo->head == &keyboard_list) - memset(&devinfo->keyboard, 0, sizeof(devinfo->keyboard)); - - // mouse/lightgun case - else if (devinfo->head == &mouse_list || devinfo->head == &lightgun_list) - memset(&devinfo->mouse, 0, sizeof(devinfo->mouse)); - - // joystick case - else if (devinfo->head == &joystick_list) - { - memset(&devinfo->joystick, 0, sizeof(devinfo->joystick)); - } -} - - -//============================================================ -// generic_button_get_state -//============================================================ - -static INT32 generic_button_get_state(void *device_internal, void *item_internal) -{ - INT32 *itemdata = (INT32 *) item_internal; - - // return the current state - return *itemdata >> 7; -} - - -//============================================================ -// generic_axis_get_state -//============================================================ - -static INT32 generic_axis_get_state(void *device_internal, void *item_internal) -{ - INT32 *axisdata = (INT32 *) item_internal; - - // return the current state - return *axisdata; -} diff --git a/src/osd/sdl/input.h b/src/osd/sdl/input.h deleted file mode 100644 index aa87375a663..00000000000 --- a/src/osd/sdl/input.h +++ /dev/null @@ -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__ */ diff --git a/src/osd/sdl/osdsdl.h b/src/osd/sdl/osdsdl.h index e82c75406cc..1d8cd72c6e9 100644 --- a/src/osd/sdl/osdsdl.h +++ b/src/osd/sdl/osdsdl.h @@ -157,18 +157,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: diff --git a/src/osd/sdl/sdlmain.cpp b/src/osd/sdl/sdlmain.cpp index 2f382605cbb..8fd04339bbf 100644 --- a/src/osd/sdl/sdlmain.cpp +++ b/src/osd/sdl/sdlmain.cpp @@ -48,7 +48,6 @@ // OSD headers #include "video.h" -#include "input.h" #include "osdsdl.h" #include "modules/lib/osdlib.h" @@ -610,3 +609,4 @@ void sdl_osd_interface::init(running_machine &machine) SDL_EnableUNICODE(SDL_TRUE); #endif } + diff --git a/src/osd/sdl/video.cpp b/src/osd/sdl/video.cpp index c5de6be41d9..99e1b2d8360 100644 --- a/src/osd/sdl/video.cpp +++ b/src/osd/sdl/video.cpp @@ -47,7 +47,6 @@ // MAMEOS headers #include "video.h" #include "window.h" -#include "input.h" #include "osdsdl.h" #include "modules/lib/osdlib.h" @@ -316,7 +315,8 @@ void sdl_osd_interface::update(bool skip_redraw) } // poll the joystick values here - sdlinput_poll(machine()); + downcast(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) @@ -506,7 +506,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)) diff --git a/src/osd/sdl/window.cpp b/src/osd/sdl/window.cpp index 47ab3cdd162..08bd3c33988 100644 --- a/src/osd/sdl/window.cpp +++ b/src/osd/sdl/window.cpp @@ -38,7 +38,6 @@ // OSD headers #include "window.h" -#include "input.h" #include "osdsdl.h" //============================================================ @@ -580,8 +579,11 @@ OSDWORK_CALLBACK( sdl_window_info::sdlwindow_toggle_full_screen_wt ) } #endif - +#ifdef USE_OLD_SDL_INPUT sdlinput_release_keys(); +#else + downcast(window->machine().osd()).release_keys(); +#endif window->set_renderer(draw.create(window)); @@ -654,7 +656,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(machine().osd()).should_hide_mouse(); +#endif + if (!fullscreen() && !should_hide_mouse) { SDL_ShowCursor(SDL_ENABLE); if (SDL_GetWindowGrab(sdl_window() )) @@ -676,7 +683,12 @@ void sdl_window_info::update_cursor_state() // the possibility of losing control if (!(machine().debug_flags & DEBUG_FLAG_OSD_ENABLED)) { - 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(machine().osd()).should_hide_mouse(); +#endif + if ( fullscreen() || should_hide_mouse ) { SDL_ShowCursor(SDL_DISABLE); if (!SDL_WM_GrabInput(SDL_GRAB_QUERY)) @@ -810,7 +822,11 @@ OSDWORK_CALLBACK( sdl_window_info::sdlwindow_video_window_destroy_wt ) #endif // release all keys ... +#ifdef USE_OLD_SDL_INPUT sdlinput_release_keys(); +#else + downcast(window->machine().osd()).release_keys(); +#endif osd_free(wp); @@ -1338,7 +1354,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 diff --git a/src/osd/windows/input.cpp b/src/osd/windows/input.cpp deleted file mode 100644 index 6a9d534a2f6..00000000000 --- a/src/osd/windows/input.cpp +++ /dev/null @@ -1,2255 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Aaron Giles -//============================================================ -// -// input.c - Win32 implementation of MAME input routines -// -//============================================================ - -// For testing purposes: force DirectInput -#define FORCE_DIRECTINPUT 0 - -// standard windows headers -#define WIN32_LEAN_AND_MEAN -#include -#include -#include - -// undef WINNT for dinput.h to prevent duplicate definition -#undef WINNT -#include -#undef interface - -// standard C headers -#include -#include -#include - -// MAME headers -#include "emu.h" -#include "osdepend.h" -#include "ui/ui.h" - -// MAMEOS headers -#include "winmain.h" -#include "window.h" -#include "input.h" -#include "video.h" -#include "strconv.h" -#include "config.h" - -#include "winutil.h" -#include - -//============================================================ -// PARAMETERS -//============================================================ - -enum -{ - POVDIR_LEFT = 0, - POVDIR_RIGHT, - POVDIR_UP, - POVDIR_DOWN -}; - -#define MAX_KEYS 256 - - - -//============================================================ -// MACROS -//============================================================ - -#define STRUCTSIZE(x) ((dinput_version == 0x0300) ? sizeof(x##_DX3) : sizeof(x)) - -#ifdef UNICODE -#define UNICODE_SUFFIX "W" -#else -#define UNICODE_SUFFIX "A" -#endif - - - -//============================================================ -// TYPEDEFS -//============================================================ - -// state information for a keyboard; DirectInput state must be first element -struct keyboard_state -{ - UINT8 state[MAX_KEYS]; - INT8 oldkey[MAX_KEYS]; - INT8 currkey[MAX_KEYS]; -}; - - -// state information for a mouse; DirectInput state must be first element -struct mouse_state -{ - DIMOUSESTATE2 state; - LONG raw_x, raw_y, raw_z; -}; - - -// state information for a joystick; DirectInput state must be first element -struct joystick_state -{ - DIJOYSTATE state; - LONG rangemin[8]; - LONG rangemax[8]; -}; - - -// DirectInput-specific information about a device -struct dinput_device_info -{ - LPDIRECTINPUTDEVICE device; - LPDIRECTINPUTDEVICE2 device2; - DIDEVCAPS caps; - LPCDIDATAFORMAT format; -}; - - -// RawInput-specific information about a device -struct rawinput_device_info -{ - HANDLE device; -}; - - -// generic device information -class device_info -{ -public: - device_info(running_machine &machine) - : head(NULL), next(NULL), name(NULL), poll(NULL), device(NULL), m_machine(machine) { } - - running_machine &machine() const { return m_machine; } - - // device information - device_info ** head; - device_info * next; - const char * name; - void (*poll)(device_info *info); - - // MAME information - input_device * device; - - // device state - union - { - keyboard_state keyboard; - mouse_state mouse; - joystick_state joystick; - }; - - // DirectInput/RawInput-specific state - dinput_device_info dinput; - rawinput_device_info rawinput; - -private: - running_machine & m_machine; -}; - - -// 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); - - - -//============================================================ -// LOCAL VARIABLES -//============================================================ - -// global states -static bool input_enabled; -static std::mutex input_lock; -static bool input_paused; -static DWORD last_poll; - -// DirectInput variables -static LPDIRECTINPUT dinput; -static int dinput_version; - -// RawInput variables -static get_rawinput_device_list_ptr get_rawinput_device_list; -static get_rawinput_data_ptr get_rawinput_data; -static get_rawinput_device_info_ptr get_rawinput_device_info; -static register_rawinput_devices_ptr register_rawinput_devices; -static bool global_inputs_enabled; - -// keyboard states -static bool keyboard_win32_reported_key_down; -static device_info * keyboard_list; - -// mouse states -static bool mouse_enabled; -static device_info * mouse_list; - -// lightgun states -static UINT8 lightgun_shared_axis_mode; -static bool lightgun_enabled; -static device_info * lightgun_list; - -// joystick states -static device_info * joystick_list; - -// default axis names -static const TCHAR *const default_axis_name[] = -{ - TEXT("X"), TEXT("Y"), TEXT("Z"), TEXT("RX"), - TEXT("RY"), TEXT("RZ"), TEXT("SL1"), TEXT("SL2") -}; - - - -//============================================================ -// PROTOTYPES -//============================================================ - -// device list management -static void device_list_poll_devices(device_info *devlist_head); -static void device_list_reset_devices(device_info *devlist_head); - -// generic device management -static device_info *generic_device_alloc(running_machine &machine, device_info **devlist_head_ptr, const TCHAR *name); -static void generic_device_free(device_info *devinfo); -static int generic_device_index(device_info *devlist_head, device_info *devinfo); -static void generic_device_reset(device_info *devinfo); -static INT32 generic_button_get_state(void *device_internal, void *item_internal); -static INT32 generic_axis_get_state(void *device_internal, void *item_internal); - -// Win32-specific input code -static void win32_init(running_machine &machine); -static void win32_exit(running_machine &machine); -static void win32_keyboard_poll(device_info *devinfo); -static void win32_lightgun_poll(device_info *devinfo); - -// DirectInput-specific code -static void dinput_init(running_machine &machine); -static void dinput_exit(running_machine &machine); -static HRESULT dinput_set_dword_property(LPDIRECTINPUTDEVICE device, REFGUID property_guid, DWORD object, DWORD how, DWORD value); -static device_info *dinput_device_create(running_machine &machine, device_info **devlist_head_ptr, LPCDIDEVICEINSTANCE instance, LPCDIDATAFORMAT format1, LPCDIDATAFORMAT format2, DWORD cooperative_level); -static void dinput_device_release(device_info *devinfo); -static char *dinput_device_item_name(device_info *devinfo, int offset, const TCHAR *defstring, const TCHAR *suffix); -static HRESULT dinput_device_poll(device_info *devinfo); -static BOOL CALLBACK dinput_keyboard_enum(LPCDIDEVICEINSTANCE instance, LPVOID ref); -static void dinput_keyboard_poll(device_info *devinfo); -static BOOL CALLBACK dinput_mouse_enum(LPCDIDEVICEINSTANCE instance, LPVOID ref); -static void dinput_mouse_poll(device_info *devinfo); -static BOOL CALLBACK dinput_joystick_enum(LPCDIDEVICEINSTANCE instance, LPVOID ref); -static void dinput_joystick_poll(device_info *devinfo); -static INT32 dinput_joystick_pov_get_state(void *device_internal, void *item_internal); - -// RawInput-specific code -static void rawinput_init(running_machine &machine); -static void rawinput_exit(running_machine &machine); -static device_info *rawinput_device_create(running_machine &machine, device_info **devlist_head_ptr, PRAWINPUTDEVICELIST device); -static void rawinput_device_release(device_info *info); -static TCHAR *rawinput_device_improve_name(TCHAR *name); -static void rawinput_keyboard_enum(running_machine &machine, PRAWINPUTDEVICELIST device); -static void rawinput_keyboard_update(HANDLE device, RAWKEYBOARD *data); -static void rawinput_mouse_enum(running_machine &machine, PRAWINPUTDEVICELIST device); -static void rawinput_mouse_update(HANDLE device, RAWMOUSE *data); -static void rawinput_mouse_poll(device_info *devinfo); - -// misc utilities -static TCHAR *reg_query_string(HKEY key, const TCHAR *path); -static const TCHAR *default_button_name(int which); -static const TCHAR *default_pov_name(int which); - - - -//============================================================ -// KEYBOARD/JOYSTICK LIST -//============================================================ - -// master keyboard translation table -struct key_trans_entry { - input_item_id mame_key; - INT32 di_key; - unsigned char virtual_key; - char ascii_key; - char const * mame_key_name; -}; -#define KEY_TRANS_ENTRY(mame, di, virtual, ascii) { ITEM_ID_##mame, DIK_##di, virtual, ascii, "ITEM_ID_"#mame } -static const key_trans_entry win_key_trans_table[] = -{ - // MAME key dinput key virtual key ascii - KEY_TRANS_ENTRY(ESC, ESCAPE, VK_ESCAPE, 27), - KEY_TRANS_ENTRY(1, 1, '1', '1'), - KEY_TRANS_ENTRY(2, 2, '2', '2'), - KEY_TRANS_ENTRY(3, 3, '3', '3'), - KEY_TRANS_ENTRY(4, 4, '4', '4'), - KEY_TRANS_ENTRY(5, 5, '5', '5'), - KEY_TRANS_ENTRY(6, 6, '6', '6'), - KEY_TRANS_ENTRY(7, 7, '7', '7'), - KEY_TRANS_ENTRY(8, 8, '8', '8'), - KEY_TRANS_ENTRY(9, 9, '9', '9'), - KEY_TRANS_ENTRY(0, 0, '0', '0'), - KEY_TRANS_ENTRY(MINUS, MINUS, VK_OEM_MINUS, '-'), - KEY_TRANS_ENTRY(EQUALS, EQUALS, VK_OEM_PLUS, '='), - KEY_TRANS_ENTRY(BACKSPACE, BACK, VK_BACK, 8), - KEY_TRANS_ENTRY(TAB, TAB, VK_TAB, 9), - KEY_TRANS_ENTRY(Q, Q, 'Q', 'Q'), - KEY_TRANS_ENTRY(W, W, 'W', 'W'), - KEY_TRANS_ENTRY(E, E, 'E', 'E'), - KEY_TRANS_ENTRY(R, R, 'R', 'R'), - KEY_TRANS_ENTRY(T, T, 'T', 'T'), - KEY_TRANS_ENTRY(Y, Y, 'Y', 'Y'), - KEY_TRANS_ENTRY(U, U, 'U', 'U'), - KEY_TRANS_ENTRY(I, I, 'I', 'I'), - KEY_TRANS_ENTRY(O, O, 'O', 'O'), - KEY_TRANS_ENTRY(P, P, 'P', 'P'), - KEY_TRANS_ENTRY(OPENBRACE, LBRACKET, VK_OEM_4, '['), - KEY_TRANS_ENTRY(CLOSEBRACE, RBRACKET, VK_OEM_6, ']'), - KEY_TRANS_ENTRY(ENTER, RETURN, VK_RETURN, 13), - KEY_TRANS_ENTRY(LCONTROL, LCONTROL, VK_LCONTROL, 0), - KEY_TRANS_ENTRY(A, A, 'A', 'A'), - KEY_TRANS_ENTRY(S, S, 'S', 'S'), - KEY_TRANS_ENTRY(D, D, 'D', 'D'), - KEY_TRANS_ENTRY(F, F, 'F', 'F'), - KEY_TRANS_ENTRY(G, G, 'G', 'G'), - KEY_TRANS_ENTRY(H, H, 'H', 'H'), - KEY_TRANS_ENTRY(J, J, 'J', 'J'), - KEY_TRANS_ENTRY(K, K, 'K', 'K'), - KEY_TRANS_ENTRY(L, L, 'L', 'L'), - KEY_TRANS_ENTRY(COLON, SEMICOLON, VK_OEM_1, ';'), - KEY_TRANS_ENTRY(QUOTE, APOSTROPHE, VK_OEM_7, '\''), - KEY_TRANS_ENTRY(TILDE, GRAVE, VK_OEM_3, '`'), - KEY_TRANS_ENTRY(LSHIFT, LSHIFT, VK_LSHIFT, 0), - KEY_TRANS_ENTRY(BACKSLASH, BACKSLASH, VK_OEM_5, '\\'), - KEY_TRANS_ENTRY(BACKSLASH2, OEM_102, VK_OEM_102, '<'), - KEY_TRANS_ENTRY(Z, Z, 'Z', 'Z'), - KEY_TRANS_ENTRY(X, X, 'X', 'X'), - KEY_TRANS_ENTRY(C, C, 'C', 'C'), - KEY_TRANS_ENTRY(V, V, 'V', 'V'), - KEY_TRANS_ENTRY(B, B, 'B', 'B'), - KEY_TRANS_ENTRY(N, N, 'N', 'N'), - KEY_TRANS_ENTRY(M, M, 'M', 'M'), - KEY_TRANS_ENTRY(COMMA, COMMA, VK_OEM_COMMA, ','), - KEY_TRANS_ENTRY(STOP, PERIOD, VK_OEM_PERIOD, '.'), - KEY_TRANS_ENTRY(SLASH, SLASH, VK_OEM_2, '/'), - KEY_TRANS_ENTRY(RSHIFT, RSHIFT, VK_RSHIFT, 0), - KEY_TRANS_ENTRY(ASTERISK, MULTIPLY, VK_MULTIPLY, '*'), - KEY_TRANS_ENTRY(LALT, LMENU, VK_LMENU, 0), - KEY_TRANS_ENTRY(SPACE, SPACE, VK_SPACE, ' '), - KEY_TRANS_ENTRY(CAPSLOCK, CAPITAL, VK_CAPITAL, 0), - KEY_TRANS_ENTRY(F1, F1, VK_F1, 0), - KEY_TRANS_ENTRY(F2, F2, VK_F2, 0), - KEY_TRANS_ENTRY(F3, F3, VK_F3, 0), - KEY_TRANS_ENTRY(F4, F4, VK_F4, 0), - KEY_TRANS_ENTRY(F5, F5, VK_F5, 0), - KEY_TRANS_ENTRY(F6, F6, VK_F6, 0), - KEY_TRANS_ENTRY(F7, F7, VK_F7, 0), - KEY_TRANS_ENTRY(F8, F8, VK_F8, 0), - KEY_TRANS_ENTRY(F9, F9, VK_F9, 0), - KEY_TRANS_ENTRY(F10, F10, VK_F10, 0), - KEY_TRANS_ENTRY(NUMLOCK, NUMLOCK, VK_NUMLOCK, 0), - KEY_TRANS_ENTRY(SCRLOCK, SCROLL, VK_SCROLL, 0), - KEY_TRANS_ENTRY(7_PAD, NUMPAD7, VK_NUMPAD7, 0), - KEY_TRANS_ENTRY(8_PAD, NUMPAD8, VK_NUMPAD8, 0), - KEY_TRANS_ENTRY(9_PAD, NUMPAD9, VK_NUMPAD9, 0), - KEY_TRANS_ENTRY(MINUS_PAD, SUBTRACT, VK_SUBTRACT, 0), - KEY_TRANS_ENTRY(4_PAD, NUMPAD4, VK_NUMPAD4, 0), - KEY_TRANS_ENTRY(5_PAD, NUMPAD5, VK_NUMPAD5, 0), - KEY_TRANS_ENTRY(6_PAD, NUMPAD6, VK_NUMPAD6, 0), - KEY_TRANS_ENTRY(PLUS_PAD, ADD, VK_ADD, 0), - KEY_TRANS_ENTRY(1_PAD, NUMPAD1, VK_NUMPAD1, 0), - KEY_TRANS_ENTRY(2_PAD, NUMPAD2, VK_NUMPAD2, 0), - KEY_TRANS_ENTRY(3_PAD, NUMPAD3, VK_NUMPAD3, 0), - KEY_TRANS_ENTRY(0_PAD, NUMPAD0, VK_NUMPAD0, 0), - KEY_TRANS_ENTRY(DEL_PAD, DECIMAL, VK_DECIMAL, 0), - KEY_TRANS_ENTRY(F11, F11, VK_F11, 0), - KEY_TRANS_ENTRY(F12, F12, VK_F12, 0), - KEY_TRANS_ENTRY(F13, F13, VK_F13, 0), - KEY_TRANS_ENTRY(F14, F14, VK_F14, 0), - KEY_TRANS_ENTRY(F15, F15, VK_F15, 0), - KEY_TRANS_ENTRY(ENTER_PAD, NUMPADENTER, VK_RETURN, 0), - KEY_TRANS_ENTRY(RCONTROL, RCONTROL, VK_RCONTROL, 0), - KEY_TRANS_ENTRY(SLASH_PAD, DIVIDE, VK_DIVIDE, 0), - KEY_TRANS_ENTRY(PRTSCR, SYSRQ, 0, 0), - KEY_TRANS_ENTRY(RALT, RMENU, VK_RMENU, 0), - KEY_TRANS_ENTRY(HOME, HOME, VK_HOME, 0), - KEY_TRANS_ENTRY(UP, UP, VK_UP, 0), - KEY_TRANS_ENTRY(PGUP, PRIOR, VK_PRIOR, 0), - KEY_TRANS_ENTRY(LEFT, LEFT, VK_LEFT, 0), - KEY_TRANS_ENTRY(RIGHT, RIGHT, VK_RIGHT, 0), - KEY_TRANS_ENTRY(END, END, VK_END, 0), - KEY_TRANS_ENTRY(DOWN, DOWN, VK_DOWN, 0), - KEY_TRANS_ENTRY(PGDN, NEXT, VK_NEXT, 0), - KEY_TRANS_ENTRY(INSERT, INSERT, VK_INSERT, 0), - KEY_TRANS_ENTRY(DEL, DELETE, VK_DELETE, 0), - KEY_TRANS_ENTRY(LWIN, LWIN, VK_LWIN, 0), - KEY_TRANS_ENTRY(RWIN, RWIN, VK_RWIN, 0), - KEY_TRANS_ENTRY(MENU, APPS, VK_APPS, 0), - KEY_TRANS_ENTRY(PAUSE, PAUSE, VK_PAUSE, 0), - { ITEM_ID_CANCEL, 0, VK_CANCEL, 0, "ITEM_ID_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_ENTRY(OTHER_SWITCH, MUTE, VK_VOLUME_MUTE, 0), - KEY_TRANS_ENTRY(OTHER_SWITCH, VOLUMEDOWN, VK_VOLUME_DOWN, 0), - KEY_TRANS_ENTRY(OTHER_SWITCH, VOLUMEUP, VK_VOLUME_UP, 0), - KEY_TRANS_ENTRY(OTHER_SWITCH, WEBHOME, VK_BROWSER_HOME, 0), - KEY_TRANS_ENTRY(OTHER_SWITCH, WEBSEARCH, VK_BROWSER_SEARCH, 0), - KEY_TRANS_ENTRY(OTHER_SWITCH, WEBFAVORITES, VK_BROWSER_FAVORITES, 0), - KEY_TRANS_ENTRY(OTHER_SWITCH, WEBREFRESH, VK_BROWSER_REFRESH, 0), - KEY_TRANS_ENTRY(OTHER_SWITCH, WEBSTOP, VK_BROWSER_STOP, 0), - KEY_TRANS_ENTRY(OTHER_SWITCH, WEBFORWARD, VK_BROWSER_FORWARD, 0), - KEY_TRANS_ENTRY(OTHER_SWITCH, WEBBACK, VK_BROWSER_BACK, 0), - KEY_TRANS_ENTRY(OTHER_SWITCH, MAIL, VK_LAUNCH_MAIL, 0), - KEY_TRANS_ENTRY(OTHER_SWITCH, MEDIASELECT, VK_LAUNCH_MEDIA_SELECT, 0), -}; - - -//============================================================ -// INLINE FUNCTIONS -//============================================================ - -static inline void poll_if_necessary(running_machine &machine) -{ - // make sure we poll at least once every 1/4 second - if (GetTickCount() > last_poll + 1000 / 4) - wininput_poll(machine); -} - - -static inline input_item_id keyboard_map_scancode_to_itemid(int scancode) -{ - int tablenum; - - // scan the table for a match - for (tablenum = 0; tablenum < ARRAY_LENGTH(win_key_trans_table); tablenum++) - if (win_key_trans_table[tablenum].di_key == scancode) - return (input_item_id)win_key_trans_table[tablenum].mame_key; - - // default to an "other" switch - return ITEM_ID_OTHER_SWITCH; -} - - -static inline 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); - } -} - - - -//============================================================ -// input_init -//============================================================ - -bool windows_osd_interface::input_init() -{ - // decode the options - lightgun_shared_axis_mode = downcast(machine().options()).dual_lightgun(); - - // initialize RawInput and DirectInput (RawInput first so we can fall back) - rawinput_init(machine()); - dinput_init(machine()); - win32_init(machine()); - - // poll once to get the initial states - input_enabled = true; - wininput_poll(machine()); - return true; -} - - -//============================================================ -// wininput_pause -//============================================================ - -void windows_osd_interface::input_pause() -{ - // keep track of the paused state - input_paused = true; -} - -void windows_osd_interface::input_resume() -{ - // keep track of the paused state - input_paused = false; -} - - -//============================================================ -// wininput_exit -//============================================================ - -void windows_osd_interface::input_exit() -{ - // acquire the lock and turn off input (this ensures everyone is done) - std::lock_guard lock(input_lock); - input_enabled = false; -} - - -//============================================================ -// wininput_poll -//============================================================ - -void wininput_poll(running_machine &machine) -{ - // ignore if not enabled - if (input_enabled) - { - // remember when this happened - last_poll = GetTickCount(); - - // 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); - - // track if mouse/lightgun is enabled, for mouse hiding purposes - mouse_enabled = machine.input().device_class(DEVICE_CLASS_MOUSE).enabled(); - lightgun_enabled = machine.input().device_class(DEVICE_CLASS_LIGHTGUN).enabled(); - } - - bool polldevices = input_enabled && (global_inputs_enabled || winwindow_has_focus()); - - // poll all of the devices - if (polldevices) - { - device_list_poll_devices(keyboard_list); - device_list_poll_devices(mouse_list); - device_list_poll_devices(lightgun_list); - device_list_poll_devices(joystick_list); - } - else - { - device_list_reset_devices(keyboard_list); - device_list_reset_devices(mouse_list); - device_list_reset_devices(lightgun_list); - device_list_reset_devices(joystick_list); - } -} - - -//============================================================ -// wininput_should_hide_mouse -//============================================================ - -bool wininput_should_hide_mouse(void) -{ - // if we are paused or disabled, no - if (input_paused || !input_enabled) - return false; - - // if neither mice nor lightguns enabled in the core, then no - if (!mouse_enabled && !lightgun_enabled) - return false; - - // if the window has a menu, no - if (win_window_list != NULL && win_window_list->win_has_menu()) - return false; - - // otherwise, yes - return true; -} - - -//============================================================ -// wininput_handle_mouse_button -//============================================================ - -BOOL wininput_handle_mouse_button(int button, int down, int x, int y) -{ - device_info *devinfo; - - // ignore if not enabled - if (!input_enabled) - return FALSE; - - // only need this for shared axis hack - if (!lightgun_shared_axis_mode || button >= 4) - return FALSE; - - // choose a device based on the button - devinfo = lightgun_list; - if (button >= 2 && devinfo != NULL) - { - button -= 2; - devinfo = devinfo->next; - } - - // take the lock - std::lock_guard lock(input_lock); - - // set the button state - devinfo->mouse.state.rgbButtons[button] = down ? 0x80 : 0x00; - if (down) - { - RECT client_rect; - POINT mousepos; - - // get the position relative to the window - GetClientRect(win_window_list->m_hwnd, &client_rect); - mousepos.x = x; - mousepos.y = y; - ScreenToClient(win_window_list->m_hwnd, &mousepos); - - // convert to absolute coordinates - devinfo->mouse.state.lX = normalize_absolute_axis(mousepos.x, client_rect.left, client_rect.right); - devinfo->mouse.state.lY = normalize_absolute_axis(mousepos.y, client_rect.top, client_rect.bottom); - } - return TRUE; -} - - -//============================================================ -// wininput_handle_raw -//============================================================ - -BOOL wininput_handle_raw(HANDLE device) -{ - BYTE small_buffer[4096]; - LPBYTE data = small_buffer; - BOOL result = FALSE; - int size; - - // ignore if not enabled - if (!input_enabled) - return result; - - // determine the size of databuffer we need - if ((*get_rawinput_data)((HRAWINPUT)device, RID_INPUT, NULL, &size, sizeof(RAWINPUTHEADER)) != 0) - return result; - - // if necessary, allocate a temporary buffer and fetch the data - if (size > sizeof(small_buffer)) - { - data = global_alloc_array_nothrow(BYTE, size); - if (data == NULL) - return result; - } - - // fetch the data and process the appropriate message types - result = (*get_rawinput_data)((HRAWINPUT)device, RID_INPUT, data, &size, sizeof(RAWINPUTHEADER)); - if (result != 0) - { - RAWINPUT *input = (RAWINPUT *)data; - - // handle keyboard input - if (input->header.dwType == RIM_TYPEKEYBOARD) - { - std::lock_guard lock(input_lock); - rawinput_keyboard_update(input->header.hDevice, &input->data.keyboard); - result = TRUE; - } - - // handle mouse input - else if (input->header.dwType == RIM_TYPEMOUSE) - { - std::lock_guard lock(input_lock); - rawinput_mouse_update(input->header.hDevice, &input->data.mouse); - result = TRUE; - } - } - - // free the temporary buffer and return the result - if (data != small_buffer) - global_free_array(data); - return result; -} - - -//============================================================ -// wininput_vkey_for_mame_code -//============================================================ - -int wininput_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 < ARRAY_LENGTH(win_key_trans_table); tablenum++) - if (win_key_trans_table[tablenum].mame_key == id) - return win_key_trans_table[tablenum].virtual_key; - } - return 0; -} - - -//============================================================ -// lookup_mame_code -//============================================================ - -static int lookup_mame_index(const char *scode) -{ - for (int i = 0; i < ARRAY_LENGTH(win_key_trans_table); i++) - { - if (!strcmp(scode, win_key_trans_table[i].mame_key_name)) - return i; - } - return -1; -} - -static input_item_id lookup_mame_code(const char *scode) -{ - int const index = lookup_mame_index(scode); - if (index >= 0) - return win_key_trans_table[index].mame_key; - else - return ITEM_ID_INVALID; -} - - -//============================================================ -// customize_input_type_list -//============================================================ - -void windows_osd_interface::customize_input_type_list(simple_list &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 = 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; - } -} - - -//============================================================ -// device_list_poll_devices -//============================================================ - -static void device_list_poll_devices(device_info *devlist_head) -{ - device_info *curdev; - - for (curdev = devlist_head; curdev != NULL; curdev = curdev->next) - if (curdev->poll != NULL) - (*curdev->poll)(curdev); -} - - -//============================================================ -// device_list_reset_devices -//============================================================ - -static void device_list_reset_devices(device_info *devlist_head) -{ - device_info *curdev; - - for (curdev = devlist_head; curdev != NULL; curdev = curdev->next) - generic_device_reset(curdev); -} - - -//============================================================ -// generic_device_alloc -//============================================================ - -static device_info *generic_device_alloc(running_machine &machine, device_info **devlist_head_ptr, const TCHAR *name) -{ - device_info **curdev_ptr; - device_info *devinfo; - - // allocate memory for the device object - devinfo = global_alloc_clear(machine); - devinfo->head = devlist_head_ptr; - - // allocate a UTF8 copy of the name - devinfo->name = utf8_from_tstring(name); - if (devinfo->name == NULL) - goto error; - - // append us to the list - for (curdev_ptr = devinfo->head; *curdev_ptr != NULL; curdev_ptr = &(*curdev_ptr)->next) ; - *curdev_ptr = devinfo; - - return devinfo; - -error: - global_free(devinfo); - return NULL; -} - - -//============================================================ -// generic_device_free -//============================================================ - -static void generic_device_free(device_info *devinfo) -{ - device_info **curdev_ptr; - - // remove us from the list - for (curdev_ptr = devinfo->head; *curdev_ptr != devinfo && *curdev_ptr != NULL; curdev_ptr = &(*curdev_ptr)->next) ; - if (*curdev_ptr == devinfo) - *curdev_ptr = devinfo->next; - - // free the copy of the name if present - if (devinfo->name != NULL) - osd_free((void *)devinfo->name); - devinfo->name = NULL; - - // and now free the info - global_free(devinfo); -} - - -//============================================================ -// generic_device_index -//============================================================ - -static int generic_device_index(device_info *devlist_head, device_info *devinfo) -{ - int index = 0; - while (devlist_head != NULL) - { - if (devlist_head == devinfo) - return index; - index++; - devlist_head = devlist_head->next; - } - return -1; -} - - -//============================================================ -// generic_device_reset -//============================================================ - -static void generic_device_reset(device_info *devinfo) -{ - // keyboard case - if (devinfo->head == &keyboard_list) - memset(devinfo->keyboard.state, 0, sizeof(devinfo->keyboard.state)); - - // mouse/lightgun case - else if (devinfo->head == &mouse_list || devinfo->head == &lightgun_list) - memset(&devinfo->mouse.state, 0, sizeof(devinfo->mouse.state)); - - // joystick case - else if (devinfo->head == &joystick_list) - { - int povnum; - - memset(&devinfo->joystick.state, 0, sizeof(devinfo->joystick.state)); - for (povnum = 0; povnum < ARRAY_LENGTH(devinfo->joystick.state.rgdwPOV); povnum++) - devinfo->joystick.state.rgdwPOV[povnum] = 0xffff; - } -} - - -//============================================================ -// generic_button_get_state -//============================================================ - -static INT32 generic_button_get_state(void *device_internal, void *item_internal) -{ - device_info *devinfo = (device_info *)device_internal; - BYTE *itemdata = (BYTE *)item_internal; - - // return the current state - poll_if_necessary(devinfo->machine()); - return *itemdata >> 7; -} - - -//============================================================ -// generic_axis_get_state -//============================================================ - -static INT32 generic_axis_get_state(void *device_internal, void *item_internal) -{ - device_info *devinfo = (device_info *)device_internal; - LONG *axisdata = (LONG *)item_internal; - - // return the current state - poll_if_necessary(devinfo->machine()); - return *axisdata; -} - - -//============================================================ -// win32_init -//============================================================ - -static void win32_init(running_machine &machine) -{ - int gunnum; - - // we don't need any initialization unless we are using shared axis mode for lightguns - if (!lightgun_shared_axis_mode) - return; - - // we need an exit callback - machine.add_notifier(MACHINE_NOTIFY_EXIT, machine_notify_delegate(FUNC(win32_exit), &machine)); - - // allocate two lightgun devices - for (gunnum = 0; gunnum < 2; gunnum++) - { - static const TCHAR *const gun_names[] = { TEXT("Shared Axis Gun 1"), TEXT("Shared Axis Gun 2") }; - device_info *devinfo; - int axisnum, butnum; - - // allocate a device - devinfo = generic_device_alloc(machine, &lightgun_list, gun_names[gunnum]); - if (devinfo == NULL) - break; - - // add the device - devinfo->device = machine.input().device_class(DEVICE_CLASS_LIGHTGUN).add_device(devinfo->name, devinfo); - - // populate the axes - for (axisnum = 0; axisnum < 2; axisnum++) - { - char *name = utf8_from_tstring(default_axis_name[axisnum]); - devinfo->device->add_item(name, (input_item_id)(ITEM_ID_XAXIS + axisnum), generic_axis_get_state, &devinfo->mouse.state.lX + axisnum); - osd_free(name); - } - - // populate the buttons - for (butnum = 0; butnum < 2; butnum++) - { - char *name = utf8_from_tstring(default_button_name(butnum)); - devinfo->device->add_item(name, (input_item_id)(ITEM_ID_BUTTON1 + butnum), generic_button_get_state, &devinfo->mouse.state.rgbButtons[butnum]); - osd_free(name); - } - } -} - - -//============================================================ -// win32_exit -//============================================================ - -static void win32_exit(running_machine &machine) -{ - // skip if we're in shared axis mode - if (!lightgun_shared_axis_mode) - return; - - // delete the lightgun devices - while (lightgun_list != NULL) - generic_device_free(lightgun_list); -} - - -//============================================================ -// win32_keyboard_poll -//============================================================ - -static void win32_keyboard_poll(device_info *devinfo) -{ - int keynum; - - // clear the flag that says we detected a key down via win32 - keyboard_win32_reported_key_down = false; - - // reset the keyboard state and then repopulate - memset(devinfo->keyboard.state, 0, sizeof(devinfo->keyboard.state)); - - // iterate over keys - for (keynum = 0; keynum < ARRAY_LENGTH(win_key_trans_table); keynum++) - { - int vk = win_key_trans_table[keynum].virtual_key; - if (vk != 0 && (GetAsyncKeyState(vk) & 0x8000) != 0) - { - int dik = win_key_trans_table[keynum].di_key; - - // conver the VK code to a scancode (DIK code) - if (dik != 0) - devinfo->keyboard.state[dik] = 0x80; - - // set this flag so that we continue to use win32 until all keys are up - keyboard_win32_reported_key_down = true; - } - } -} - - -//============================================================ -// win32_lightgun_poll -//============================================================ - -static void win32_lightgun_poll(device_info *devinfo) -{ - INT32 xpos = 0, ypos = 0; - POINT mousepos; - - // if we are using the shared axis hack, the data is updated via Windows messages only - if (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 - devinfo->mouse.state.lX = xpos; - devinfo->mouse.state.lY = ypos; -} - - -//============================================================ -// dinput_init -//============================================================ - -static void dinput_init(running_machine &machine) -{ - HRESULT result; -#if DIRECTINPUT_VERSION >= 0x800 - int didevtype_keyboard = DI8DEVCLASS_KEYBOARD; - int didevtype_mouse = DI8DEVCLASS_POINTER; - int didevtype_joystick = DI8DEVCLASS_GAMECTRL; - - dinput_version = DIRECTINPUT_VERSION; - result = DirectInput8Create(GetModuleHandleUni(), dinput_version, IID_IDirectInput8, (void **)&dinput, NULL); - if (result != DI_OK) - { - dinput_version = 0; - return; - } -#else - int didevtype_keyboard = DIDEVTYPE_KEYBOARD; - int didevtype_mouse = DIDEVTYPE_MOUSE; - int didevtype_joystick = DIDEVTYPE_JOYSTICK; - - // first attempt to initialize DirectInput at the current version - dinput_version = DIRECTINPUT_VERSION; - result = DirectInputCreate(GetModuleHandleUni(), dinput_version, &dinput, NULL); - if (result != DI_OK) - { - // if that fails, try version 5 - dinput_version = 0x0500; - result = DirectInputCreate(GetModuleHandleUni(), dinput_version, &dinput, NULL); - if (result != DI_OK) - { - // if that fails, try version 3 - dinput_version = 0x0300; - result = DirectInputCreate(GetModuleHandleUni(), dinput_version, &dinput, NULL); - if (result != DI_OK) - { - dinput_version = 0; - return; - } - } - } -#endif - - osd_printf_verbose("DirectInput: Using DirectInput %d\n", dinput_version >> 8); - - // we need an exit callback - machine.add_notifier(MACHINE_NOTIFY_EXIT, machine_notify_delegate(FUNC(dinput_exit), &machine)); - - // initialize keyboard devices, but only if we don't have any yet - if (keyboard_list == NULL) - { - // enumerate the ones we have - result = IDirectInput_EnumDevices(dinput, didevtype_keyboard, dinput_keyboard_enum, &machine, DIEDFL_ATTACHEDONLY); - if (result != DI_OK) - fatalerror("DirectInput: Unable to enumerate keyboards (result=%08X)\n", (UINT32)result); - } - - // initialize mouse & lightgun devices, but only if we don't have any yet - if (mouse_list == NULL) - { - // enumerate the ones we have - result = IDirectInput_EnumDevices(dinput, didevtype_mouse, dinput_mouse_enum, &machine, DIEDFL_ATTACHEDONLY); - if (result != DI_OK) - fatalerror("DirectInput: Unable to enumerate mice (result=%08X)\n", (UINT32)result); - } - - // initialize joystick devices - result = IDirectInput_EnumDevices(dinput, didevtype_joystick, dinput_joystick_enum, &machine, DIEDFL_ATTACHEDONLY); - if (result != DI_OK) - fatalerror("DirectInput: Unable to enumerate joysticks (result=%08X)\n", (UINT32)result); -} - - -//============================================================ -// dinput_exit -//============================================================ - -static void dinput_exit(running_machine &machine) -{ - // release all our devices - while (joystick_list != NULL && joystick_list->dinput.device != NULL) - dinput_device_release(joystick_list); - while (lightgun_list != NULL) - generic_device_free(lightgun_list); - while (mouse_list != NULL && mouse_list->dinput.device != NULL) - dinput_device_release(mouse_list); - while (keyboard_list != NULL && keyboard_list->dinput.device != NULL) - dinput_device_release(keyboard_list); - - // release DirectInput - if (dinput != NULL) - IDirectInput_Release(dinput); - dinput = NULL; -} - - -//============================================================ -// 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_create -//============================================================ - -static device_info *dinput_device_create(running_machine &machine, device_info **devlist_head_ptr, LPCDIDEVICEINSTANCE instance, LPCDIDATAFORMAT format1, LPCDIDATAFORMAT format2, DWORD cooperative_level) -{ - device_info *devinfo; - HRESULT result; - - // allocate memory for the device object - devinfo = generic_device_alloc(machine, devlist_head_ptr, instance->tszInstanceName); - - // attempt to create a device - result = IDirectInput_CreateDevice(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: - dinput_device_release(devinfo); - return NULL; -} - - -//============================================================ -// dinput_device_release -//============================================================ - -static void dinput_device_release(device_info *devinfo) -{ - // release the version 2 device if present - if (devinfo->dinput.device2 != NULL) - IDirectInputDevice_Release(devinfo->dinput.device2); - devinfo->dinput.device2 = NULL; - - // release the regular device if present - if (devinfo->dinput.device != NULL) - IDirectInputDevice_Release(devinfo->dinput.device); - devinfo->dinput.device = NULL; - - // free the item list - generic_device_free(devinfo); -} - - -//============================================================ -// dinput_device_item_name -//============================================================ - -static char *dinput_device_item_name(device_info *devinfo, int offset, const TCHAR *defstring, const TCHAR *suffix) -{ - DIDEVICEOBJECTINSTANCE instance = { 0 }; - const TCHAR *namestring = instance.tszName; - TCHAR *combined; - HRESULT result; - char *utf8; - - // 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 == NULL) - return NULL; - namestring = defstring; - } - - // if no suffix, return as-is - if (suffix == NULL) - return utf8_from_tstring(namestring); - - // otherwise, allocate space to add the suffix - combined = global_alloc_array(TCHAR, _tcslen(namestring) + 1 + _tcslen(suffix) + 1); - _tcscpy(combined, namestring); - _tcscat(combined, TEXT(" ")); - _tcscat(combined, suffix); - - // convert to UTF8, free the temporary string, and return - utf8 = utf8_from_tstring(combined); - global_free_array(combined); - return utf8; -} - - -//============================================================ -// dinput_device_poll -//============================================================ - -static HRESULT dinput_device_poll(device_info *devinfo) -{ - HRESULT result; - - // first poll the device, then get the state - if (devinfo->dinput.device2 != NULL) - IDirectInputDevice2_Poll(devinfo->dinput.device2); - result = IDirectInputDevice_GetDeviceState(devinfo->dinput.device, devinfo->dinput.format->dwDataSize, &devinfo->joystick.state); - - // handle lost inputs here - if (result == DIERR_INPUTLOST || result == DIERR_NOTACQUIRED) - { - result = IDirectInputDevice_Acquire(devinfo->dinput.device); - if (result == DI_OK) - result = IDirectInputDevice_GetDeviceState(devinfo->dinput.device, devinfo->dinput.format->dwDataSize, &devinfo->joystick.state); - } - - return result; -} - - -//============================================================ -// dinput_keyboard_enum -//============================================================ - -static BOOL CALLBACK dinput_keyboard_enum(LPCDIDEVICEINSTANCE instance, LPVOID ref) -{ - running_machine &machine = *(running_machine *)ref; - device_info *devinfo; - int keynum; - - // allocate and link in a new device - devinfo = dinput_device_create(machine, &keyboard_list, instance, &c_dfDIKeyboard, NULL, DISCL_FOREGROUND | DISCL_NONEXCLUSIVE); - if (devinfo == NULL) - goto exit; - - // add the device - devinfo->device = machine.input().device_class(DEVICE_CLASS_KEYBOARD).add_device(devinfo->name, devinfo); - devinfo->poll = dinput_keyboard_poll; - - // populate it - for (keynum = 0; keynum < MAX_KEYS; keynum++) - { - input_item_id itemid = keyboard_map_scancode_to_itemid(keynum); - TCHAR defname[20]; - char *name; - - // generate/fetch the name - _sntprintf(defname, ARRAY_LENGTH(defname), TEXT("Scan%03d"), keynum); - name = dinput_device_item_name(devinfo, keynum, defname, NULL); - - // add the item to the device - devinfo->device->add_item(name, itemid, generic_button_get_state, &devinfo->keyboard.state[keynum]); - osd_free(name); - } - -exit: - return DIENUM_CONTINUE; -} - - -//============================================================ -// dinput_keyboard_poll -//============================================================ - -static void dinput_keyboard_poll(device_info *devinfo) -{ - HRESULT result = dinput_device_poll(devinfo); - - // for the first device, if we errored, or if we previously reported win32 keys, - // then ignore the dinput state and poll using win32 - if (devinfo == keyboard_list && (result != DI_OK || keyboard_win32_reported_key_down)) - win32_keyboard_poll(devinfo); -} - - -//============================================================ -// dinput_mouse_enum -//============================================================ - -static BOOL CALLBACK dinput_mouse_enum(LPCDIDEVICEINSTANCE instance, LPVOID ref) -{ - device_info *devinfo, *guninfo = NULL; - running_machine &machine = *(running_machine *)ref; - int axisnum, butnum; - HRESULT result; - - // allocate and link in a new device - devinfo = dinput_device_create(machine, &mouse_list, instance, &c_dfDIMouse2, &c_dfDIMouse, DISCL_FOREGROUND | DISCL_NONEXCLUSIVE); - if (devinfo == NULL) - goto exit; - - // allocate a second device for the gun (unless we are using the shared axis mode) - // we only support a single gun in dinput mode, so only add one - if (!lightgun_shared_axis_mode && devinfo == mouse_list) - { - guninfo = generic_device_alloc(machine, &lightgun_list, instance->tszInstanceName); - if (guninfo == 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", generic_device_index(mouse_list, devinfo), devinfo->name); - goto error; - } - - // add the device - devinfo->device = machine.input().device_class(DEVICE_CLASS_MOUSE).add_device(devinfo->name, devinfo); - devinfo->poll = dinput_mouse_poll; - if (guninfo != NULL) - { - guninfo->device = machine.input().device_class(DEVICE_CLASS_LIGHTGUN).add_device(guninfo->name, guninfo); - guninfo->poll = win32_lightgun_poll; - } - - // 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++) - { - char *name = dinput_device_item_name(devinfo, offsetof(DIMOUSESTATE, lX) + axisnum * sizeof(LONG), default_axis_name[axisnum], NULL); - - // add to the mouse device and optionally to the gun device as well - devinfo->device->add_item(name, (input_item_id)(ITEM_ID_XAXIS + axisnum), generic_axis_get_state, &devinfo->mouse.state.lX + axisnum); - if (guninfo != NULL && axisnum < 2) - guninfo->device->add_item(name, (input_item_id)(ITEM_ID_XAXIS + axisnum), generic_axis_get_state, &guninfo->mouse.state.lX + axisnum); - - osd_free(name); - } - - // populate the buttons - for (butnum = 0; butnum < devinfo->dinput.caps.dwButtons; butnum++) - { - FPTR offset = (FPTR)(&((DIMOUSESTATE *)NULL)->rgbButtons[butnum]); - char *name = dinput_device_item_name(devinfo, offset, default_button_name(butnum), NULL); - - // add to the mouse device and optionally to the gun device as well - // note that the gun device points to the mouse buttons rather than its own - devinfo->device->add_item(name, (input_item_id)(ITEM_ID_BUTTON1 + butnum), generic_button_get_state, &devinfo->mouse.state.rgbButtons[butnum]); - if (guninfo != NULL) - guninfo->device->add_item(name, (input_item_id)(ITEM_ID_BUTTON1 + butnum), generic_button_get_state, &devinfo->mouse.state.rgbButtons[butnum]); - - osd_free(name); - } - -exit: - return DIENUM_CONTINUE; - -error: - if (guninfo != NULL) - generic_device_free(guninfo); - if (devinfo != NULL) - dinput_device_release(devinfo); - goto exit; -} - - -//============================================================ -// dinput_mouse_poll -//============================================================ - -static void dinput_mouse_poll(device_info *devinfo) -{ - // poll - dinput_device_poll(devinfo); - - // scale the axis data - devinfo->mouse.state.lX *= INPUT_RELATIVE_PER_PIXEL; - devinfo->mouse.state.lY *= INPUT_RELATIVE_PER_PIXEL; - devinfo->mouse.state.lZ *= INPUT_RELATIVE_PER_PIXEL; -} - - -//============================================================ -// dinput_joystick_enum -//============================================================ - -static BOOL CALLBACK dinput_joystick_enum(LPCDIDEVICEINSTANCE instance, LPVOID ref) -{ - DWORD cooperative_level = DISCL_FOREGROUND | DISCL_NONEXCLUSIVE; - int axisnum, axiscount, povnum, butnum; - running_machine &machine = *(running_machine *)ref; - device_info *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 = dinput_device_create(machine, &joystick_list, 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", generic_device_index(joystick_list, devinfo), 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", generic_device_index(joystick_list, devinfo), 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", generic_device_index(joystick_list, devinfo), 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); - - // add the device - devinfo->device = machine.input().device_class(DEVICE_CLASS_JOYSTICK).add_device(devinfo->name, devinfo); - devinfo->poll = dinput_joystick_poll; - - // populate the axes - for (axisnum = axiscount = 0; axiscount < devinfo->dinput.caps.dwAxes && axisnum < 8; axisnum++) - { - DIPROPRANGE dipr; - char *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 = dinput_device_item_name(devinfo, offsetof(DIJOYSTATE2, lX) + axisnum * sizeof(LONG), default_axis_name[axisnum], NULL); - devinfo->device->add_item(name, (input_item_id)(ITEM_ID_XAXIS + axisnum), generic_axis_get_state, &devinfo->joystick.state.lX + axisnum); - osd_free(name); - - axiscount++; - } - - // populate the POVs - for (povnum = 0; povnum < devinfo->dinput.caps.dwPOVs; povnum++) - { - char *name; - - // left - name = dinput_device_item_name(devinfo, offsetof(DIJOYSTATE2, rgdwPOV) + povnum * sizeof(DWORD), default_pov_name(povnum), TEXT("L")); - devinfo->device->add_item(name, ITEM_ID_OTHER_SWITCH, dinput_joystick_pov_get_state, (void *)(FPTR)(povnum * 4 + POVDIR_LEFT)); - osd_free(name); - - // right - name = dinput_device_item_name(devinfo, offsetof(DIJOYSTATE2, rgdwPOV) + povnum * sizeof(DWORD), default_pov_name(povnum), TEXT("R")); - devinfo->device->add_item(name, ITEM_ID_OTHER_SWITCH, dinput_joystick_pov_get_state, (void *)(FPTR)(povnum * 4 + POVDIR_RIGHT)); - osd_free(name); - - // up - name = dinput_device_item_name(devinfo, offsetof(DIJOYSTATE2, rgdwPOV) + povnum * sizeof(DWORD), default_pov_name(povnum), TEXT("U")); - devinfo->device->add_item(name, ITEM_ID_OTHER_SWITCH, dinput_joystick_pov_get_state, (void *)(FPTR)(povnum * 4 + POVDIR_UP)); - osd_free(name); - - // down - name = dinput_device_item_name(devinfo, offsetof(DIJOYSTATE2, rgdwPOV) + povnum * sizeof(DWORD), default_pov_name(povnum), TEXT("D")); - devinfo->device->add_item(name, ITEM_ID_OTHER_SWITCH, dinput_joystick_pov_get_state, (void *)(FPTR)(povnum * 4 + POVDIR_DOWN)); - osd_free(name); - } - - // populate the buttons - for (butnum = 0; butnum < devinfo->dinput.caps.dwButtons; butnum++) - { - FPTR offset = (FPTR)(&((DIJOYSTATE2 *)NULL)->rgbButtons[butnum]); - char *name = dinput_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, itemid, generic_button_get_state, &devinfo->joystick.state.rgbButtons[butnum]); - osd_free(name); - } - -exit: - return DIENUM_CONTINUE; -} - - -//============================================================ -// dinput_joystick_poll -//============================================================ - -static void dinput_joystick_poll(device_info *devinfo) -{ - int axisnum; - - // poll the device first - dinput_device_poll(devinfo); - - // normalize axis values - for (axisnum = 0; axisnum < 8; axisnum++) - { - LONG *axis = (&devinfo->joystick.state.lX) + axisnum; - *axis = normalize_absolute_axis(*axis, devinfo->joystick.rangemin[axisnum], devinfo->joystick.rangemax[axisnum]); - } -} - - -//============================================================ -// dinput_joystick_pov_get_state -//============================================================ - -static INT32 dinput_joystick_pov_get_state(void *device_internal, void *item_internal) -{ - device_info *devinfo = (device_info *)device_internal; - int povnum = (FPTR)item_internal / 4; - int povdir = (FPTR)item_internal % 4; - INT32 result = 0; - DWORD pov; - - // get the current state - 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; -} - - -//============================================================ -// rawinput_init -//============================================================ - -static void rawinput_init(running_machine &machine) -{ - RAWINPUTDEVICELIST *devlist = NULL; - int device_count, devnum, regcount; - RAWINPUTDEVICE reglist[2]; - HMODULE user32; - - // we need pause and exit callbacks - machine.add_notifier(MACHINE_NOTIFY_EXIT, machine_notify_delegate(FUNC(rawinput_exit), &machine)); - - // look in user32 for the raw input APIs - user32 = LoadLibrary(TEXT("user32.dll")); - if (user32 == NULL) - goto error; - - // 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) - goto error; - osd_printf_verbose("RawInput: APIs detected\n"); - - // get the number of devices, allocate a device list, and fetch it - if ((*get_rawinput_device_list)(NULL, &device_count, sizeof(*devlist)) != 0) - goto error; - if (device_count == 0) - goto error; - devlist = global_alloc_array(RAWINPUTDEVICELIST, device_count); - if ((*get_rawinput_device_list)(devlist, &device_count, sizeof(*devlist)) == -1) - goto error; - - // iterate backwards through devices; new devices are added at the head - for (devnum = device_count - 1; devnum >= 0; devnum--) - { - RAWINPUTDEVICELIST *device = &devlist[devnum]; - - // handle keyboards - if (!FORCE_DIRECTINPUT && device->dwType == RIM_TYPEKEYBOARD) - rawinput_keyboard_enum(machine, device); - - // handle mice - else if (!FORCE_DIRECTINPUT && device->dwType == RIM_TYPEMOUSE) - rawinput_mouse_enum(machine, device); - } - - // don't enable global inputs when testing direct input or debugging - if (!FORCE_DIRECTINPUT && !machine.options().debug()) - { - global_inputs_enabled = downcast(machine.options()).global_inputs(); - } - - // finally, register to receive raw input WM_INPUT messages - regcount = 0; - if (keyboard_list != NULL) - { - reglist[regcount].usUsagePage = 0x01; - reglist[regcount].usUsage = 0x06; - - if (global_inputs_enabled) - { - reglist[regcount].dwFlags = 0x00000100; - } - else - { - reglist[regcount].dwFlags = 0; - } - - reglist[regcount].hwndTarget = win_window_list->m_hwnd; - regcount++; - } - if (mouse_list != NULL) - { - reglist[regcount].usUsagePage = 0x01; - reglist[regcount].usUsage = 0x02; - - if (global_inputs_enabled) - { - reglist[regcount].dwFlags = 0x00000100; - } - else - { - reglist[regcount].dwFlags = 0; - } - - reglist[regcount].hwndTarget = win_window_list->m_hwnd; - regcount++; - } - - // if the registration fails, we need to back off - if (regcount > 0) - if (!(*register_rawinput_devices)(reglist, regcount, sizeof(reglist[0]))) - goto error; - - global_free_array(devlist); - return; - -error: - if (devlist != NULL) - global_free_array(devlist); -} - - -//============================================================ -// rawinput_exit -//============================================================ - -static void rawinput_exit(running_machine &machine) -{ - // release all our devices - while (lightgun_list != NULL && lightgun_list->rawinput.device != NULL) - rawinput_device_release(lightgun_list); - while (mouse_list != NULL && mouse_list->rawinput.device != NULL) - rawinput_device_release(mouse_list); - while (keyboard_list != NULL && keyboard_list->rawinput.device != NULL) - rawinput_device_release(keyboard_list); -} - - -//============================================================ -// rawinput_device_create -//============================================================ - -static device_info *rawinput_device_create(running_machine &machine, device_info **devlist_head_ptr, PRAWINPUTDEVICELIST device) -{ - device_info *devinfo = NULL; - TCHAR *tname = NULL; - INT name_length = 0; - - // determine the length of the device name, allocate it, and fetch it if not nameless - if ((*get_rawinput_device_info)(device->hDevice, RIDI_DEVICENAME, NULL, &name_length) != 0) - goto error; - tname = global_alloc_array_clear(name_length+1); - if (name_length > 1 && (*get_rawinput_device_info)(device->hDevice, RIDI_DEVICENAME, tname, &name_length) == -1) - goto error; - - // if this is an RDP name, skip it - if (_tcsstr(tname, TEXT("Root#RDP_")) != NULL) - goto error; - - // improve the name and then allocate a device - tname = rawinput_device_improve_name(tname); - devinfo = generic_device_alloc(machine, devlist_head_ptr, tname); - global_free_array(tname); - - // copy the handle - devinfo->rawinput.device = device->hDevice; - return devinfo; - -error: - if (tname != NULL) - global_free_array(tname); - if (devinfo != NULL) - rawinput_device_release(devinfo); - return NULL; -} - - -//============================================================ -// rawinput_device_release -//============================================================ - -static void rawinput_device_release(device_info *devinfo) -{ - // free the item list - generic_device_free(devinfo); -} - - -//============================================================ -// 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, ®key); - 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, ®key); - 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_keyboard_enum -//============================================================ - -static void rawinput_keyboard_enum(running_machine &machine, PRAWINPUTDEVICELIST device) -{ - device_info *devinfo; - int keynum; - - // allocate and link in a new device - devinfo = rawinput_device_create(machine, &keyboard_list, device); - if (devinfo == NULL) - return; - - // add the device - devinfo->device = machine.input().device_class(DEVICE_CLASS_KEYBOARD).add_device(devinfo->name, devinfo); - - // populate it - for (keynum = 0; keynum < MAX_KEYS; keynum++) - { - input_item_id itemid = keyboard_map_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); - } -} - - -//============================================================ -// rawinput_keyboard_update -//============================================================ - -static void rawinput_keyboard_update(HANDLE device, RAWKEYBOARD *data) -{ - device_info *devinfo; - - // find the keyboard in the list and process - for (devinfo = keyboard_list; devinfo != NULL; devinfo = devinfo->next) - if (devinfo->rawinput.device == device) - { - // determine the full DIK-compatible scancode - UINT8 scancode = (data->MakeCode & 0x7f) | ((data->Flags & RI_KEY_E0) ? 0x80 : 0x00); - - // scancode 0xaa is a special shift code we need to ignore - if (scancode == 0xaa) - break; - - // set or clear the key - if (!(data->Flags & RI_KEY_BREAK)) - devinfo->keyboard.state[scancode] = 0x80; - else - devinfo->keyboard.state[scancode] = 0x00; - break; - } -} - - -//============================================================ -// rawinput_mouse_enum -//============================================================ - -static void rawinput_mouse_enum(running_machine &machine, PRAWINPUTDEVICELIST device) -{ - device_info *devinfo, *guninfo = NULL; - int axisnum, butnum; - - // allocate and link in a new mouse device - devinfo = rawinput_device_create(machine, &mouse_list, device); - if (devinfo == NULL) - return; - devinfo->poll = rawinput_mouse_poll; - - // allocate a second device for the gun (unless we are using the shared axis mode) - if (!lightgun_shared_axis_mode) - { - guninfo = rawinput_device_create(machine, &lightgun_list, device); - assert(guninfo != NULL); - } - - // add the device - devinfo->device = machine.input().device_class(DEVICE_CLASS_MOUSE).add_device(devinfo->name, devinfo); - if (guninfo != NULL) - { - guninfo->device = machine.input().device_class(DEVICE_CLASS_LIGHTGUN).add_device(guninfo->name, guninfo); - guninfo->poll = NULL; - } - - // populate the axes - for (axisnum = 0; axisnum < 3; axisnum++) - { - char *name = utf8_from_tstring(default_axis_name[axisnum]); - - // add to the mouse device and optionally to the gun device as well - devinfo->device->add_item(name, (input_item_id)(ITEM_ID_XAXIS + axisnum), generic_axis_get_state, &devinfo->mouse.state.lX + axisnum); - if (guninfo != NULL && axisnum < 2) - guninfo->device->add_item(name, (input_item_id)(ITEM_ID_XAXIS + axisnum), generic_axis_get_state, &guninfo->mouse.state.lX + axisnum); - - osd_free(name); - } - - // populate the buttons - for (butnum = 0; butnum < 5; butnum++) - { - char *name = utf8_from_tstring(default_button_name(butnum)); - - // add to the mouse device and optionally to the gun device as well - devinfo->device->add_item(name, (input_item_id)(ITEM_ID_BUTTON1 + butnum), generic_button_get_state, &devinfo->mouse.state.rgbButtons[butnum]); - if (guninfo != NULL) - guninfo->device->add_item(name, (input_item_id)(ITEM_ID_BUTTON1 + butnum), generic_button_get_state, &guninfo->mouse.state.rgbButtons[butnum]); - - osd_free(name); - } -} - - -//============================================================ -// rawinput_mouse_update -//============================================================ - -static void rawinput_mouse_update(HANDLE device, RAWMOUSE *data) -{ - device_info *devlist = (data->usFlags & MOUSE_MOVE_ABSOLUTE) ? lightgun_list : mouse_list; - device_info *devinfo; - - // find the mouse in the list and process - for (devinfo = devlist; devinfo != NULL; devinfo = devinfo->next) - if (devinfo->rawinput.device == device) - { - // if we got relative data, update it as a mouse - if (!(data->usFlags & MOUSE_MOVE_ABSOLUTE)) - { - devinfo->mouse.raw_x += data->lLastX * INPUT_RELATIVE_PER_PIXEL; - devinfo->mouse.raw_y += data->lLastY * INPUT_RELATIVE_PER_PIXEL; - - // update zaxis - if (data->usButtonFlags & RI_MOUSE_WHEEL) - devinfo->mouse.raw_z += (INT16)data->usButtonData * INPUT_RELATIVE_PER_PIXEL; - } - - // otherwise, update it as a lightgun - else - { - devinfo->mouse.state.lX = normalize_absolute_axis(data->lLastX, 0, 0xffff); - devinfo->mouse.state.lY = normalize_absolute_axis(data->lLastY, 0, 0xffff); - } - - // update the button states; always update the corresponding mouse buttons - if (data->usButtonFlags & RI_MOUSE_BUTTON_1_DOWN) devinfo->mouse.state.rgbButtons[0] = 0x80; - if (data->usButtonFlags & RI_MOUSE_BUTTON_1_UP) devinfo->mouse.state.rgbButtons[0] = 0x00; - if (data->usButtonFlags & RI_MOUSE_BUTTON_2_DOWN) devinfo->mouse.state.rgbButtons[1] = 0x80; - if (data->usButtonFlags & RI_MOUSE_BUTTON_2_UP) devinfo->mouse.state.rgbButtons[1] = 0x00; - if (data->usButtonFlags & RI_MOUSE_BUTTON_3_DOWN) devinfo->mouse.state.rgbButtons[2] = 0x80; - if (data->usButtonFlags & RI_MOUSE_BUTTON_3_UP) devinfo->mouse.state.rgbButtons[2] = 0x00; - if (data->usButtonFlags & RI_MOUSE_BUTTON_4_DOWN) devinfo->mouse.state.rgbButtons[3] = 0x80; - if (data->usButtonFlags & RI_MOUSE_BUTTON_4_UP) devinfo->mouse.state.rgbButtons[3] = 0x00; - if (data->usButtonFlags & RI_MOUSE_BUTTON_5_DOWN) devinfo->mouse.state.rgbButtons[4] = 0x80; - if (data->usButtonFlags & RI_MOUSE_BUTTON_5_UP) devinfo->mouse.state.rgbButtons[4] = 0x00; - break; - } -} - - -//============================================================ -// rawinput_mouse_poll -//============================================================ - -static void rawinput_mouse_poll(device_info *devinfo) -{ - poll_if_necessary(devinfo->machine()); - - // copy the accumulated raw state to the actual state - std::lock_guard lock(input_lock); - devinfo->mouse.state.lX = devinfo->mouse.raw_x; - devinfo->mouse.state.lY = devinfo->mouse.raw_y; - devinfo->mouse.state.lZ = devinfo->mouse.raw_z; - devinfo->mouse.raw_x = 0; - devinfo->mouse.raw_y = 0; - devinfo->mouse.raw_z = 0; -} - - -//============================================================ -// 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; -} - - -//============================================================ -// default_button_name -//============================================================ - -static const TCHAR *default_button_name(int which) -{ - static TCHAR buffer[20]; - _sntprintf(buffer, ARRAY_LENGTH(buffer), TEXT("B%d"), which); - return buffer; -} - - -//============================================================ -// default_pov_name -//============================================================ - -static const TCHAR *default_pov_name(int which) -{ - static TCHAR buffer[20]; - _sntprintf(buffer, ARRAY_LENGTH(buffer), TEXT("POV%d"), which); - return buffer; -} diff --git a/src/osd/windows/input.h b/src/osd/windows/input.h index 983d1867d6f..39a1d63fa5e 100644 --- a/src/osd/windows/input.h +++ b/src/osd/windows/input.h @@ -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 */ + + diff --git a/src/osd/windows/video.cpp b/src/osd/windows/video.cpp index b4f665a2135..742786202d1 100644 --- a/src/osd/windows/video.cpp +++ b/src/osd/windows/video.cpp @@ -192,7 +192,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) diff --git a/src/osd/windows/window.cpp b/src/osd/windows/window.cpp index dd219949534..d2ecfffcb9b 100644 --- a/src/osd/windows/window.cpp +++ b/src/osd/windows/window.cpp @@ -45,6 +45,12 @@ extern int drawbgfx_init(running_machine &machine, osd_draw_callbacks *callbacks extern int drawogl_init(running_machine &machine, osd_draw_callbacks *callbacks); #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(&machine.osd()) + //============================================================ // PARAMETERS //============================================================ @@ -199,7 +205,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(NULL, 0, win_window_info::thread_entry, NULL, 0, (unsigned *)&window_threadid); + temp = _beginthreadex(NULL, 0, win_window_info::thread_entry, this, 0, (unsigned *)&window_threadid); window_thread = (HANDLE)temp; if (window_thread == NULL) fatalerror("Failed to create window thread\n"); @@ -355,7 +361,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 @@ -396,36 +426,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; } } @@ -606,7 +645,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(machine.osd()).should_hide_mouse()))) { win_window_info *window = win_window_list; RECT bounds; @@ -1060,6 +1099,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(param); // make a bogus user call to make us a message thread PeekMessage(&message, NULL, 0, 0, PM_NOREMOVE); @@ -1087,36 +1127,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 @@ -1272,7 +1312,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(window->machine().osd()).handle_input_event(INPUT_EVENT_RAWINPUT, &lparam); break; // syskeys - ignore @@ -1409,9 +1449,9 @@ LRESULT CALLBACK win_window_info::video_window_proc(HWND wnd, UINT message, WPAR case WM_DESTROY: if (!(window->m_renderer == NULL)) { - window->m_renderer->destroy(); - global_free(window->m_renderer); - window->m_renderer = NULL; + window->m_renderer->destroy(); + global_free(window->m_renderer); + window->m_renderer = NULL; } window->m_hwnd = NULL; return DefWindowProc(wnd, message, wparam, lparam); diff --git a/src/osd/windows/winmain.h b/src/osd/windows/winmain.h index 7656ab4ee31..70fc80e7d2d 100644 --- a/src/osd/windows/winmain.h +++ b/src/osd/windows/winmain.h @@ -240,6 +240,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: @@ -254,25 +277,25 @@ public: // video overridables virtual void *get_slider_list() override; - // input overridables virtual void customize_input_type_list(simple_list &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: