mirror of
https://github.com/holub/mame
synced 2025-04-23 00:39:36 +03:00
Merge input modules work.
This commit is contained in:
commit
f68ad66131
@ -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
|
||||
|
@ -425,8 +425,6 @@ project ("osd_" .. _OPTIONS["osd"])
|
||||
MAME_DIR .. "src/osd/sdl/sdlprefix.h",
|
||||
MAME_DIR .. "src/osd/sdl/sdlmain.cpp",
|
||||
MAME_DIR .. "src/osd/osdepend.h",
|
||||
MAME_DIR .. "src/osd/sdl/input.cpp",
|
||||
MAME_DIR .. "src/osd/sdl/input.h",
|
||||
MAME_DIR .. "src/osd/sdl/video.cpp",
|
||||
MAME_DIR .. "src/osd/sdl/video.h",
|
||||
MAME_DIR .. "src/osd/sdl/window.cpp",
|
||||
|
@ -163,7 +163,6 @@ project ("osd_" .. _OPTIONS["osd"])
|
||||
MAME_DIR .. "src/osd/modules/render/drawgdi.h",
|
||||
MAME_DIR .. "src/osd/modules/render/drawnone.cpp",
|
||||
MAME_DIR .. "src/osd/modules/render/drawnone.h",
|
||||
MAME_DIR .. "src/osd/windows/input.cpp",
|
||||
MAME_DIR .. "src/osd/windows/input.h",
|
||||
MAME_DIR .. "src/osd/windows/output.cpp",
|
||||
MAME_DIR .. "src/osd/windows/output.h",
|
||||
|
@ -25,7 +25,8 @@
|
||||
#include "debugger.h"
|
||||
|
||||
#include "window.h"
|
||||
#include "../../windows/input.h"
|
||||
#include "../input/input_common.h"
|
||||
#include "../input/input_windows.h"
|
||||
|
||||
|
||||
class debugger_windows : public osd_module, public debug_module, protected debugger_windows_interface
|
||||
@ -121,7 +122,7 @@ void debugger_windows::wait_for_debugger(device_t &device, bool firststop)
|
||||
show_all();
|
||||
|
||||
// run input polling to ensure that our status is in sync
|
||||
wininput_poll(*m_machine);
|
||||
downcast<windows_osd_interface&>(machine().osd()).poll_input(*m_machine);
|
||||
|
||||
// get and process messages
|
||||
MSG message;
|
||||
@ -202,7 +203,7 @@ bool debugger_windows::seq_pressed() const
|
||||
else
|
||||
{
|
||||
// handle everything else as a series of ANDs
|
||||
int const vkey = wininput_vkey_for_mame_code(code);
|
||||
int const vkey = keyboard_trans_table::instance().vkey_for_mame_code(code);
|
||||
bool const pressed = (vkey != 0) && ((GetAsyncKeyState(vkey) & 0x8000) != 0);
|
||||
|
||||
if (first) // if this is the first in the sequence, result is set equal
|
||||
|
266
src/osd/modules/input/input_common.cpp
Normal file
266
src/osd/modules/input/input_common.cpp
Normal file
@ -0,0 +1,266 @@
|
||||
// license:BSD-3-Clause
|
||||
// copyright-holders:Olivier Galibert, R. Belmont, Brad Hughes
|
||||
//============================================================
|
||||
//
|
||||
// input_common.cpp - Common code for all MAME input modules
|
||||
//
|
||||
// SDLMAME by Olivier Galibert and R. Belmont
|
||||
//
|
||||
//============================================================
|
||||
|
||||
#include "input_module.h"
|
||||
#include "modules/osdmodule.h"
|
||||
#include "modules/lib/osdobj_common.h"
|
||||
|
||||
#include <mutex>
|
||||
#include <memory>
|
||||
|
||||
// MAME headers
|
||||
#include "emu.h"
|
||||
|
||||
// winnt.h defines this
|
||||
#ifdef DELETE
|
||||
#undef DELETE
|
||||
#endif
|
||||
|
||||
#include "input_common.h"
|
||||
|
||||
//============================================================
|
||||
// Keyboard translation table
|
||||
//============================================================
|
||||
|
||||
#if defined(OSD_WINDOWS)
|
||||
#include <windows.h>
|
||||
#define KEY_TRANS_ENTRY0(mame, sdlsc, sdlkey, disc, virtual, ascii, UI) { ITEM_ID_##mame, KEY_ ## disc, virtual, ascii, "ITEM_ID_"#mame, (char *) UI }
|
||||
#define KEY_TRANS_ENTRY1(mame, sdlsc, sdlkey, disc, virtual, ascii) { ITEM_ID_##mame, KEY_ ## disc, virtual, ascii, "ITEM_ID_"#mame, (char*) #mame }
|
||||
#else
|
||||
// SDL include
|
||||
#include <sdlinc.h>
|
||||
#define KEY_TRANS_ENTRY0(mame, sdlsc, sdlkey, disc, virtual, ascii, UI) { ITEM_ID_##mame, SDL_SCANCODE_ ## sdlsc, SDLK_ ## sdlkey, ascii, "ITEM_ID_"#mame, (char *) UI }
|
||||
#define KEY_TRANS_ENTRY1(mame, sdlsc, sdlkey, disc, virtual, ascii) { ITEM_ID_##mame, SDL_SCANCODE_ ## sdlsc, SDLK_ ## sdlkey, ascii, "ITEM_ID_"#mame, (char*) #mame }
|
||||
#endif
|
||||
|
||||
key_trans_entry keyboard_trans_table::s_default_table[] =
|
||||
{
|
||||
// MAME key sdl scancode sdl key di scancode virtual key ascii ui
|
||||
KEY_TRANS_ENTRY0(ESC, ESCAPE, ESCAPE, ESCAPE, VK_ESCAPE, 27, "ESCAPE"),
|
||||
KEY_TRANS_ENTRY1(1, 1, 1, 1, '1', '1'),
|
||||
KEY_TRANS_ENTRY1(2, 2, 2, 2, '2', '2'),
|
||||
KEY_TRANS_ENTRY1(3, 3, 3, 3, '3', '3'),
|
||||
KEY_TRANS_ENTRY1(4, 4, 4, 4, '4', '4'),
|
||||
KEY_TRANS_ENTRY1(5, 5, 5, 5, '5', '5'),
|
||||
KEY_TRANS_ENTRY1(6, 6, 6, 6, '6', '6'),
|
||||
KEY_TRANS_ENTRY1(7, 7, 7, 7, '7', '7'),
|
||||
KEY_TRANS_ENTRY1(8, 8, 8, 8, '8', '8'),
|
||||
KEY_TRANS_ENTRY1(9, 9, 9, 9, '9', '9'),
|
||||
KEY_TRANS_ENTRY1(0, 0, 0, 0, '0', '0'),
|
||||
KEY_TRANS_ENTRY1(MINUS, MINUS, MINUS, MINUS, VK_OEM_MINUS, '-'),
|
||||
KEY_TRANS_ENTRY1(EQUALS, EQUALS, EQUALS, EQUALS, VK_OEM_PLUS, '='),
|
||||
KEY_TRANS_ENTRY1(BACKSPACE, BACKSPACE, BACKSPACE, BACK, VK_BACK, 8),
|
||||
KEY_TRANS_ENTRY1(TAB, TAB, TAB, TAB, VK_TAB, 9),
|
||||
KEY_TRANS_ENTRY1(Q, Q, q, Q, 'Q', 'Q'),
|
||||
KEY_TRANS_ENTRY1(W, W, w, W, 'W', 'W'),
|
||||
KEY_TRANS_ENTRY1(E, E, e, E, 'E', 'E'),
|
||||
KEY_TRANS_ENTRY1(R, R, r, R, 'R', 'R'),
|
||||
KEY_TRANS_ENTRY1(T, T, t, T, 'T', 'T'),
|
||||
KEY_TRANS_ENTRY1(Y, Y, y, Y, 'Y', 'Y'),
|
||||
KEY_TRANS_ENTRY1(U, U, u, U, 'U', 'U'),
|
||||
KEY_TRANS_ENTRY1(I, I, i, I, 'I', 'I'),
|
||||
KEY_TRANS_ENTRY1(O, O, o, O, 'O', 'O'),
|
||||
KEY_TRANS_ENTRY1(P, P, p, P, 'P', 'P'),
|
||||
KEY_TRANS_ENTRY1(OPENBRACE, LEFTBRACKET, LEFTBRACKET, LBRACKET, VK_OEM_4, '['),
|
||||
KEY_TRANS_ENTRY1(CLOSEBRACE, RIGHTBRACKET, RIGHTBRACKET, RBRACKET, VK_OEM_6, ']'),
|
||||
KEY_TRANS_ENTRY0(ENTER, RETURN, RETURN, RETURN, VK_RETURN, 13, "RETURN"),
|
||||
KEY_TRANS_ENTRY1(LCONTROL, LCTRL, LCTRL, LCONTROL, VK_LCONTROL, 0),
|
||||
KEY_TRANS_ENTRY1(A, A, a, A, 'A', 'A'),
|
||||
KEY_TRANS_ENTRY1(S, S, s, S, 'S', 'S'),
|
||||
KEY_TRANS_ENTRY1(D, D, d, D, 'D', 'D'),
|
||||
KEY_TRANS_ENTRY1(F, F, f, F, 'F', 'F'),
|
||||
KEY_TRANS_ENTRY1(G, G, g, G, 'G', 'G'),
|
||||
KEY_TRANS_ENTRY1(H, H, h, H, 'H', 'H'),
|
||||
KEY_TRANS_ENTRY1(J, J, j, J, 'J', 'J'),
|
||||
KEY_TRANS_ENTRY1(K, K, k, K, 'K', 'K'),
|
||||
KEY_TRANS_ENTRY1(L, L, l, L, 'L', 'L'),
|
||||
KEY_TRANS_ENTRY1(COLON, SEMICOLON, SEMICOLON, SEMICOLON, VK_OEM_1, ';'),
|
||||
KEY_TRANS_ENTRY1(QUOTE, APOSTROPHE, QUOTE, APOSTROPHE, VK_OEM_7, '\''),
|
||||
KEY_TRANS_ENTRY1(TILDE, GRAVE, BACKQUOTE, GRAVE, VK_OEM_3, '`'),
|
||||
KEY_TRANS_ENTRY1(LSHIFT, LSHIFT, LSHIFT, LSHIFT, VK_LSHIFT, 0),
|
||||
KEY_TRANS_ENTRY1(BACKSLASH, BACKSLASH, BACKSLASH, BACKSLASH, VK_OEM_5, '\\'),
|
||||
KEY_TRANS_ENTRY1(BACKSLASH2, 0, 0, OEM_102, VK_OEM_102, '<'),
|
||||
KEY_TRANS_ENTRY1(Z, Z, z, Z, 'Z', 'Z'),
|
||||
KEY_TRANS_ENTRY1(X, X, x, X, 'X', 'X'),
|
||||
KEY_TRANS_ENTRY1(C, C, c, C, 'C', 'C'),
|
||||
KEY_TRANS_ENTRY1(V, V, v, V, 'V', 'V'),
|
||||
KEY_TRANS_ENTRY1(B, B, b, B, 'B', 'B'),
|
||||
KEY_TRANS_ENTRY1(N, N, n, N, 'N', 'N'),
|
||||
KEY_TRANS_ENTRY1(M, M, m, M, 'M', 'M'),
|
||||
KEY_TRANS_ENTRY1(COMMA, COMMA, COMMA, COMMA, VK_OEM_COMMA, ','),
|
||||
KEY_TRANS_ENTRY1(STOP, PERIOD, PERIOD, PERIOD, VK_OEM_PERIOD, '.'),
|
||||
KEY_TRANS_ENTRY1(SLASH, SLASH, SLASH, SLASH, VK_OEM_2, '/'),
|
||||
KEY_TRANS_ENTRY1(RSHIFT, RSHIFT, RSHIFT, RSHIFT, VK_RSHIFT, 0),
|
||||
KEY_TRANS_ENTRY1(ASTERISK, KP_MULTIPLY, KP_MULTIPLY, MULTIPLY, VK_MULTIPLY, '*'),
|
||||
KEY_TRANS_ENTRY1(LALT, LALT, LALT, LMENU, VK_LMENU, 0),
|
||||
KEY_TRANS_ENTRY1(SPACE, SPACE, SPACE, SPACE, VK_SPACE, ' '),
|
||||
KEY_TRANS_ENTRY1(CAPSLOCK, CAPSLOCK, CAPSLOCK, CAPITAL, VK_CAPITAL, 0),
|
||||
KEY_TRANS_ENTRY1(F1, F1, F1, F1, VK_F1, 0),
|
||||
KEY_TRANS_ENTRY1(F2, F2, F2, F2, VK_F2, 0),
|
||||
KEY_TRANS_ENTRY1(F3, F3, F3, F3, VK_F3, 0),
|
||||
KEY_TRANS_ENTRY1(F4, F4, F4, F4, VK_F4, 0),
|
||||
KEY_TRANS_ENTRY1(F5, F5, F5, F5, VK_F5, 0),
|
||||
KEY_TRANS_ENTRY1(F6, F6, F6, F6, VK_F6, 0),
|
||||
KEY_TRANS_ENTRY1(F7, F7, F7, F7, VK_F7, 0),
|
||||
KEY_TRANS_ENTRY1(F8, F8, F8, F8, VK_F8, 0),
|
||||
KEY_TRANS_ENTRY1(F9, F9, F9, F9, VK_F9, 0),
|
||||
KEY_TRANS_ENTRY1(F10, F10, F10, F10, VK_F10, 0),
|
||||
KEY_TRANS_ENTRY1(NUMLOCK, NUMLOCKCLEAR, NUMLOCKCLEAR, NUMLOCK, VK_NUMLOCK, 0),
|
||||
KEY_TRANS_ENTRY1(SCRLOCK, SCROLLLOCK, SCROLLLOCK, SCROLL, VK_SCROLL, 0),
|
||||
KEY_TRANS_ENTRY1(7_PAD, KP_7, KP_7, NUMPAD7, VK_NUMPAD7, 0),
|
||||
KEY_TRANS_ENTRY1(8_PAD, KP_8, KP_8, NUMPAD8, VK_NUMPAD8, 0),
|
||||
KEY_TRANS_ENTRY1(9_PAD, KP_9, KP_9, NUMPAD9, VK_NUMPAD9, 0),
|
||||
KEY_TRANS_ENTRY1(MINUS_PAD, KP_MINUS, KP_MINUS, SUBTRACT, VK_SUBTRACT, 0),
|
||||
KEY_TRANS_ENTRY1(4_PAD, KP_4, KP_4, NUMPAD4, VK_NUMPAD4, 0),
|
||||
KEY_TRANS_ENTRY1(5_PAD, KP_5, KP_5, NUMPAD5, VK_NUMPAD5, 0),
|
||||
KEY_TRANS_ENTRY1(6_PAD, KP_6, KP_6, NUMPAD6, VK_NUMPAD6, 0),
|
||||
KEY_TRANS_ENTRY1(PLUS_PAD, KP_PLUS, KP_PLUS, ADD, VK_ADD, 0),
|
||||
KEY_TRANS_ENTRY1(1_PAD, KP_1, KP_1, NUMPAD1, VK_NUMPAD1, 0),
|
||||
KEY_TRANS_ENTRY1(2_PAD, KP_2, KP_2, NUMPAD2, VK_NUMPAD2, 0),
|
||||
KEY_TRANS_ENTRY1(3_PAD, KP_3, KP_3, NUMPAD3, VK_NUMPAD3, 0),
|
||||
KEY_TRANS_ENTRY1(0_PAD, KP_0, KP_0, NUMPAD0, VK_NUMPAD0, 0),
|
||||
KEY_TRANS_ENTRY1(DEL_PAD, KP_PERIOD, KP_PERIOD, DECIMAL, VK_DECIMAL, 0),
|
||||
KEY_TRANS_ENTRY1(F11, F11, F11, F11, VK_F11, 0),
|
||||
KEY_TRANS_ENTRY1(F12, F12, F12, F12, VK_F12, 0),
|
||||
KEY_TRANS_ENTRY1(F13, F13, F13, F13, VK_F13, 0),
|
||||
KEY_TRANS_ENTRY1(F14, F14, F14, F14, VK_F14, 0),
|
||||
KEY_TRANS_ENTRY1(F15, F15, F15, F15, VK_F15, 0),
|
||||
KEY_TRANS_ENTRY1(ENTER_PAD, KP_ENTER, KP_ENTER, NUMPADENTER, VK_RETURN, 0),
|
||||
KEY_TRANS_ENTRY1(RCONTROL, RCTRL, RCTRL, RCONTROL, VK_RCONTROL, 0),
|
||||
KEY_TRANS_ENTRY1(SLASH_PAD, KP_DIVIDE, KP_DIVIDE, DIVIDE, VK_DIVIDE, 0),
|
||||
KEY_TRANS_ENTRY1(PRTSCR, PRINTSCREEN, PRINTSCREEN, SYSRQ, 0, 0),
|
||||
KEY_TRANS_ENTRY1(RALT, RALT, RALT, RMENU, VK_RMENU, 0),
|
||||
KEY_TRANS_ENTRY1(HOME, HOME, HOME, HOME, VK_HOME, 0),
|
||||
KEY_TRANS_ENTRY1(UP, UP, UP, UP, VK_UP, 0),
|
||||
KEY_TRANS_ENTRY1(PGUP, PAGEUP, PAGEUP, PRIOR, VK_PRIOR, 0),
|
||||
KEY_TRANS_ENTRY1(LEFT, LEFT, LEFT, LEFT, VK_LEFT, 0),
|
||||
KEY_TRANS_ENTRY1(RIGHT, RIGHT, RIGHT, RIGHT, VK_RIGHT, 0),
|
||||
KEY_TRANS_ENTRY1(END, END, END, END, VK_END, 0),
|
||||
KEY_TRANS_ENTRY1(DOWN, DOWN, DOWN, DOWN, VK_DOWN, 0),
|
||||
KEY_TRANS_ENTRY1(PGDN, PAGEDOWN, PAGEDOWN, NEXT, VK_NEXT, 0),
|
||||
KEY_TRANS_ENTRY1(INSERT, INSERT, INSERT, INSERT, VK_INSERT, 0),
|
||||
KEY_TRANS_ENTRY0(DEL, DELETE, DELETE, DELETE, VK_DELETE, 0, "DELETE"),
|
||||
KEY_TRANS_ENTRY1(LWIN, LGUI, LGUI, LWIN, VK_LWIN, 0),
|
||||
KEY_TRANS_ENTRY1(RWIN, RGUI, RGUI, RWIN, VK_RWIN, 0),
|
||||
KEY_TRANS_ENTRY1(MENU, MENU, MENU, APPS, VK_APPS, 0),
|
||||
KEY_TRANS_ENTRY1(PAUSE, PAUSE, PAUSE, PAUSE, VK_PAUSE, 0),
|
||||
KEY_TRANS_ENTRY0(CANCEL, UNKNOWN, UNKNOWN, UNKNOWN, 0, 0, "CANCEL"),
|
||||
|
||||
// New keys introduced in Windows 2000. These have no MAME codes to
|
||||
// preserve compatibility with old config files that may refer to them
|
||||
// as e.g. FORWARD instead of e.g. KEYCODE_WEBFORWARD. They need table
|
||||
// entries anyway because otherwise they aren't recognized when
|
||||
// GetAsyncKeyState polling is used (as happens currently when MAME is
|
||||
// paused). Some codes are missing because the mapping to vkey codes
|
||||
// isn't clear, and MapVirtualKey is no help.
|
||||
KEY_TRANS_ENTRY1(OTHER_SWITCH, MUTE, MUTE, MUTE, VK_VOLUME_MUTE, 0),
|
||||
KEY_TRANS_ENTRY1(OTHER_SWITCH, VOLUMEDOWN, VOLUMEDOWN, VOLUMEDOWN, VK_VOLUME_DOWN, 0),
|
||||
KEY_TRANS_ENTRY1(OTHER_SWITCH, VOLUMEUP, VOLUMEUP, VOLUMEUP, VK_VOLUME_UP, 0),
|
||||
KEY_TRANS_ENTRY1(OTHER_SWITCH, AC_HOME, AC_HOME, WEBHOME, VK_BROWSER_HOME, 0),
|
||||
KEY_TRANS_ENTRY1(OTHER_SWITCH, AC_SEARCH, AC_SEARCH, WEBSEARCH, VK_BROWSER_SEARCH, 0),
|
||||
KEY_TRANS_ENTRY1(OTHER_SWITCH, AC_BOOKMARKS, AC_BOOKMARKS, WEBFAVORITES, VK_BROWSER_FAVORITES, 0),
|
||||
KEY_TRANS_ENTRY1(OTHER_SWITCH, AC_REFRESH, AC_REFRESH, WEBREFRESH, VK_BROWSER_REFRESH, 0),
|
||||
KEY_TRANS_ENTRY1(OTHER_SWITCH, AC_STOP, AC_STOP, WEBSTOP, VK_BROWSER_STOP, 0),
|
||||
KEY_TRANS_ENTRY1(OTHER_SWITCH, AC_FORWARD, AC_FORWARD, WEBFORWARD, VK_BROWSER_FORWARD, 0),
|
||||
KEY_TRANS_ENTRY1(OTHER_SWITCH, AC_BACK, AC_BACK, WEBBACK, VK_BROWSER_BACK, 0),
|
||||
KEY_TRANS_ENTRY1(OTHER_SWITCH, MAIL, MAIL, MAIL, VK_LAUNCH_MAIL, 0),
|
||||
KEY_TRANS_ENTRY1(OTHER_SWITCH, MEDIASELECT, MEDIASELECT, MEDIASELECT, VK_LAUNCH_MEDIA_SELECT, 0),
|
||||
KEY_TRANS_ENTRY0(INVALID, UNKNOWN, UNKNOWN, ESCAPE, 0, 0, "INVALID")
|
||||
};
|
||||
|
||||
// The private constructor to create the default instance
|
||||
keyboard_trans_table::keyboard_trans_table()
|
||||
{
|
||||
m_table = s_default_table;
|
||||
m_table_size = ARRAY_LENGTH(s_default_table);
|
||||
}
|
||||
|
||||
// public constructor to allow creation of non-default instances
|
||||
keyboard_trans_table::keyboard_trans_table(std::unique_ptr<key_trans_entry[]> entries, unsigned int size)
|
||||
{
|
||||
m_custom_table = std::move(entries);
|
||||
m_table = m_custom_table.get();
|
||||
m_table_size = size;
|
||||
}
|
||||
|
||||
int keyboard_trans_table::lookup_mame_index(const char *scode)
|
||||
{
|
||||
for (int i = 0; i < m_table_size; i++)
|
||||
{
|
||||
if (!strcmp(scode, m_table[i].mame_key_name))
|
||||
return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
input_item_id keyboard_trans_table::lookup_mame_code(const char *scode)
|
||||
{
|
||||
int const index = lookup_mame_index(scode);
|
||||
if (index >= 0)
|
||||
return m_table[index].mame_key;
|
||||
else
|
||||
return ITEM_ID_INVALID;
|
||||
}
|
||||
|
||||
// Windows specific lookup methods
|
||||
#if defined(OSD_WINDOWS)
|
||||
|
||||
input_item_id keyboard_trans_table::map_di_scancode_to_itemid(int scancode)
|
||||
{
|
||||
int tablenum;
|
||||
|
||||
// scan the table for a match
|
||||
for (tablenum = 0; tablenum < m_table_size; tablenum++)
|
||||
if (m_table[tablenum].scan_code == scancode)
|
||||
return m_table[tablenum].mame_key;
|
||||
|
||||
// default to an "other" switch
|
||||
return ITEM_ID_OTHER_SWITCH;
|
||||
}
|
||||
|
||||
//============================================================
|
||||
// wininput_vkey_for_mame_code
|
||||
//============================================================
|
||||
|
||||
int keyboard_trans_table::vkey_for_mame_code(input_code code)
|
||||
{
|
||||
// only works for keyboard switches
|
||||
if (code.device_class() == DEVICE_CLASS_KEYBOARD && code.item_class() == ITEM_CLASS_SWITCH)
|
||||
{
|
||||
input_item_id id = code.item_id();
|
||||
int tablenum;
|
||||
|
||||
// scan the table for a match
|
||||
for (tablenum = 0; tablenum < m_table_size; tablenum++)
|
||||
if (m_table[tablenum].mame_key == id)
|
||||
return m_table[tablenum].virtual_key;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
int input_module_base::init(const osd_options &options)
|
||||
{
|
||||
m_options = &options;
|
||||
|
||||
m_mouse_enabled = options.mouse();
|
||||
m_lightgun_enabled = options.lightgun();
|
||||
|
||||
int result = init_internal();
|
||||
if (result != 0)
|
||||
return result;
|
||||
|
||||
m_input_paused = false;
|
||||
m_input_enabled = true;
|
||||
|
||||
return 0;
|
||||
}
|
605
src/osd/modules/input/input_common.h
Normal file
605
src/osd/modules/input/input_common.h
Normal file
@ -0,0 +1,605 @@
|
||||
// license:BSD-3-Clause
|
||||
// copyright-holders:Olivier Galibert, R. Belmont, Brad Hughes
|
||||
//============================================================
|
||||
//
|
||||
// input_common.h - Common code for all MAME input modules
|
||||
//
|
||||
// SDLMAME by Olivier Galibert and R. Belmont
|
||||
//
|
||||
//============================================================
|
||||
|
||||
#ifndef INPUT_COMMON_H_
|
||||
#define INPUT_COMMON_H_
|
||||
|
||||
#include <memory>
|
||||
#include <chrono>
|
||||
#include <string>
|
||||
#include <queue>
|
||||
|
||||
//============================================================
|
||||
// PARAMETERS
|
||||
//============================================================
|
||||
|
||||
enum
|
||||
{
|
||||
POVDIR_LEFT = 0,
|
||||
POVDIR_RIGHT,
|
||||
POVDIR_UP,
|
||||
POVDIR_DOWN
|
||||
};
|
||||
|
||||
#define MAX_KEYS 256
|
||||
#define MAX_AXES 32
|
||||
#define MAX_BUTTONS 32
|
||||
#define MAX_HATS 8
|
||||
#define MAX_POV 4
|
||||
|
||||
/****************************************************************************
|
||||
* DirectInput compatible keyboard scan codes
|
||||
****************************************************************************/
|
||||
#define KEY_UNKNOWN 0x00
|
||||
#define KEY_ESCAPE 0x01
|
||||
#define KEY_1 0x02
|
||||
#define KEY_2 0x03
|
||||
#define KEY_3 0x04
|
||||
#define KEY_4 0x05
|
||||
#define KEY_5 0x06
|
||||
#define KEY_6 0x07
|
||||
#define KEY_7 0x08
|
||||
#define KEY_8 0x09
|
||||
#define KEY_9 0x0A
|
||||
#define KEY_0 0x0B
|
||||
#define KEY_MINUS 0x0C /* - on main keyboard */
|
||||
#define KEY_EQUALS 0x0D
|
||||
#define KEY_BACK 0x0E /* backspace */
|
||||
#define KEY_TAB 0x0F
|
||||
#define KEY_Q 0x10
|
||||
#define KEY_W 0x11
|
||||
#define KEY_E 0x12
|
||||
#define KEY_R 0x13
|
||||
#define KEY_T 0x14
|
||||
#define KEY_Y 0x15
|
||||
#define KEY_U 0x16
|
||||
#define KEY_I 0x17
|
||||
#define KEY_O 0x18
|
||||
#define KEY_P 0x19
|
||||
#define KEY_LBRACKET 0x1A
|
||||
#define KEY_RBRACKET 0x1B
|
||||
#define KEY_RETURN 0x1C /* Enter on main keyboard */
|
||||
#define KEY_LCONTROL 0x1D
|
||||
#define KEY_A 0x1E
|
||||
#define KEY_S 0x1F
|
||||
#define KEY_D 0x20
|
||||
#define KEY_F 0x21
|
||||
#define KEY_G 0x22
|
||||
#define KEY_H 0x23
|
||||
#define KEY_J 0x24
|
||||
#define KEY_K 0x25
|
||||
#define KEY_L 0x26
|
||||
#define KEY_SEMICOLON 0x27
|
||||
#define KEY_APOSTROPHE 0x28
|
||||
#define KEY_GRAVE 0x29 /* accent grave */
|
||||
#define KEY_LSHIFT 0x2A
|
||||
#define KEY_BACKSLASH 0x2B
|
||||
#define KEY_Z 0x2C
|
||||
#define KEY_X 0x2D
|
||||
#define KEY_C 0x2E
|
||||
#define KEY_V 0x2F
|
||||
#define KEY_B 0x30
|
||||
#define KEY_N 0x31
|
||||
#define KEY_M 0x32
|
||||
#define KEY_COMMA 0x33
|
||||
#define KEY_PERIOD 0x34 /* . on main keyboard */
|
||||
#define KEY_SLASH 0x35 /* / on main keyboard */
|
||||
#define KEY_RSHIFT 0x36
|
||||
#define KEY_MULTIPLY 0x37 /* * on numeric keypad */
|
||||
#define KEY_LMENU 0x38 /* left Alt */
|
||||
#define KEY_SPACE 0x39
|
||||
#define KEY_CAPITAL 0x3A
|
||||
#define KEY_F1 0x3B
|
||||
#define KEY_F2 0x3C
|
||||
#define KEY_F3 0x3D
|
||||
#define KEY_F4 0x3E
|
||||
#define KEY_F5 0x3F
|
||||
#define KEY_F6 0x40
|
||||
#define KEY_F7 0x41
|
||||
#define KEY_F8 0x42
|
||||
#define KEY_F9 0x43
|
||||
#define KEY_F10 0x44
|
||||
#define KEY_NUMLOCK 0x45
|
||||
#define KEY_SCROLL 0x46 /* Scroll Lock */
|
||||
#define KEY_NUMPAD7 0x47
|
||||
#define KEY_NUMPAD8 0x48
|
||||
#define KEY_NUMPAD9 0x49
|
||||
#define KEY_SUBTRACT 0x4A /* - on numeric keypad */
|
||||
#define KEY_NUMPAD4 0x4B
|
||||
#define KEY_NUMPAD5 0x4C
|
||||
#define KEY_NUMPAD6 0x4D
|
||||
#define KEY_ADD 0x4E /* + on numeric keypad */
|
||||
#define KEY_NUMPAD1 0x4F
|
||||
#define KEY_NUMPAD2 0x50
|
||||
#define KEY_NUMPAD3 0x51
|
||||
#define KEY_NUMPAD0 0x52
|
||||
#define KEY_DECIMAL 0x53 /* . on numeric keypad */
|
||||
#define KEY_OEM_102 0x56 /* <> or \| on RT 102-key keyboard (Non-U.S.) */
|
||||
#define KEY_F11 0x57
|
||||
#define KEY_F12 0x58
|
||||
#define KEY_F13 0x64 /* (NEC PC98) */
|
||||
#define KEY_F14 0x65 /* (NEC PC98) */
|
||||
#define KEY_F15 0x66 /* (NEC PC98) */
|
||||
#define KEY_KANA 0x70 /* (Japanese keyboard) */
|
||||
#define KEY_ABNT_C1 0x73 /* /? on Brazilian keyboard */
|
||||
#define KEY_CONVERT 0x79 /* (Japanese keyboard) */
|
||||
#define KEY_NOCONVERT 0x7B /* (Japanese keyboard) */
|
||||
#define KEY_YEN 0x7D /* (Japanese keyboard) */
|
||||
#define KEY_ABNT_C2 0x7E /* Numpad . on Brazilian keyboard */
|
||||
#define KEY_NUMPADEQUALS 0x8D /* = on numeric keypad (NEC PC98) */
|
||||
#define KEY_PREVTRACK 0x90 /* Previous Track (DIK_CIRCUMFLEX on Japanese keyboard) */
|
||||
#define KEY_AT 0x91 /* (NEC PC98) */
|
||||
#define KEY_COLON 0x92 /* (NEC PC98) */
|
||||
#define KEY_UNDERLINE 0x93 /* (NEC PC98) */
|
||||
#define KEY_KANJI 0x94 /* (Japanese keyboard) */
|
||||
#define KEY_STOP 0x95 /* (NEC PC98) */
|
||||
#define KEY_AX 0x96 /* (Japan AX) */
|
||||
#define KEY_UNLABELED 0x97 /* (J3100) */
|
||||
#define KEY_NEXTTRACK 0x99 /* Next Track */
|
||||
#define KEY_NUMPADENTER 0x9C /* Enter on numeric keypad */
|
||||
#define KEY_RCONTROL 0x9D
|
||||
#define KEY_MUTE 0xA0 /* Mute */
|
||||
#define KEY_CALCULATOR 0xA1 /* Calculator */
|
||||
#define KEY_PLAYPAUSE 0xA2 /* Play / Pause */
|
||||
#define KEY_MEDIASTOP 0xA4 /* Media Stop */
|
||||
#define KEY_VOLUMEDOWN 0xAE /* Volume - */
|
||||
#define KEY_VOLUMEUP 0xB0 /* Volume + */
|
||||
#define KEY_WEBHOME 0xB2 /* Web home */
|
||||
#define KEY_NUMPADCOMMA 0xB3 /* , on numeric keypad (NEC PC98) */
|
||||
#define KEY_DIVIDE 0xB5 /* / on numeric keypad */
|
||||
#define KEY_SYSRQ 0xB7
|
||||
#define KEY_RMENU 0xB8 /* right Alt */
|
||||
#define KEY_PAUSE 0xC5 /* Pause */
|
||||
#define KEY_HOME 0xC7 /* Home on arrow keypad */
|
||||
#define KEY_UP 0xC8 /* UpArrow on arrow keypad */
|
||||
#define KEY_PRIOR 0xC9 /* PgUp on arrow keypad */
|
||||
#define KEY_LEFT 0xCB /* LeftArrow on arrow keypad */
|
||||
#define KEY_RIGHT 0xCD /* RightArrow on arrow keypad */
|
||||
#define KEY_END 0xCF /* End on arrow keypad */
|
||||
#define KEY_DOWN 0xD0 /* DownArrow on arrow keypad */
|
||||
#define KEY_NEXT 0xD1 /* PgDn on arrow keypad */
|
||||
#define KEY_INSERT 0xD2 /* Insert on arrow keypad */
|
||||
#define KEY_DELETE 0xD3 /* Delete on arrow keypad */
|
||||
#define KEY_LWIN 0xDB /* Left Windows key */
|
||||
#define KEY_RWIN 0xDC /* Right Windows key */
|
||||
#define KEY_APPS 0xDD /* AppMenu key */
|
||||
#define KEY_POWER 0xDE /* System Power */
|
||||
#define KEY_SLEEP 0xDF /* System Sleep */
|
||||
#define KEY_WAKE 0xE3 /* System Wake */
|
||||
#define KEY_WEBSEARCH 0xE5 /* Web Search */
|
||||
#define KEY_WEBFAVORITES 0xE6 /* Web Favorites */
|
||||
#define KEY_WEBREFRESH 0xE7 /* Web Refresh */
|
||||
#define KEY_WEBSTOP 0xE8 /* Web Stop */
|
||||
#define KEY_WEBFORWARD 0xE9 /* Web Forward */
|
||||
#define KEY_WEBBACK 0xEA /* Web Back */
|
||||
#define KEY_MYCOMPUTER 0xEB /* My Computer */
|
||||
#define KEY_MAIL 0xEC /* Mail */
|
||||
#define KEY_MEDIASELECT 0xED /* Media Select */
|
||||
|
||||
//============================================================
|
||||
// device_info
|
||||
//============================================================
|
||||
|
||||
class input_device_list;
|
||||
|
||||
class device_info
|
||||
{
|
||||
friend input_device_list;
|
||||
|
||||
private:
|
||||
std::string m_name;
|
||||
input_device * m_device;
|
||||
running_machine & m_machine;
|
||||
input_module & m_module;
|
||||
input_device_class m_deviceclass;
|
||||
|
||||
public:
|
||||
// Constructor
|
||||
device_info(running_machine &machine, const char *name, input_device_class deviceclass, input_module &module)
|
||||
: m_name(name),
|
||||
m_device(nullptr),
|
||||
m_machine(machine),
|
||||
m_module(module),
|
||||
m_deviceclass(deviceclass)
|
||||
{
|
||||
}
|
||||
|
||||
// Destructor
|
||||
virtual ~device_info() {}
|
||||
|
||||
// Getters
|
||||
running_machine & machine() const { return m_machine; }
|
||||
const char * name() { return m_name.c_str(); }
|
||||
input_device * device() { return m_device; }
|
||||
input_module & module() const { return m_module; }
|
||||
input_device_class deviceclass() { return m_deviceclass; }
|
||||
|
||||
// Poll and reset methods
|
||||
virtual void poll() {};
|
||||
virtual void reset() = 0;
|
||||
};
|
||||
|
||||
//============================================================
|
||||
// event_based_device
|
||||
//============================================================
|
||||
|
||||
#define DEFAULT_EVENT_QUEUE_SIZE 20
|
||||
|
||||
template <class TEvent>
|
||||
class event_based_device : public device_info
|
||||
{
|
||||
private:
|
||||
std::queue<TEvent> m_event_queue;
|
||||
|
||||
protected:
|
||||
std::mutex m_device_lock;
|
||||
|
||||
virtual void process_event(TEvent &ev) = 0;
|
||||
|
||||
public:
|
||||
event_based_device(running_machine &machine, const char *name, input_device_class deviceclass, input_module &module)
|
||||
: device_info(machine, name, deviceclass, module)
|
||||
{
|
||||
}
|
||||
|
||||
void queue_events(const TEvent *events, int count)
|
||||
{
|
||||
std::lock_guard<std::mutex> scope_lock(m_device_lock);
|
||||
for (int i = 0; i < count; i++)
|
||||
m_event_queue.push(events[i]);
|
||||
|
||||
// If we've gone over the size, remove old events from the queue
|
||||
while (m_event_queue.size() > DEFAULT_EVENT_QUEUE_SIZE)
|
||||
m_event_queue.pop();
|
||||
}
|
||||
|
||||
void virtual poll() override
|
||||
{
|
||||
std::lock_guard<std::mutex> scope_lock(m_device_lock);
|
||||
|
||||
// Process each event until the queue is empty
|
||||
while (!m_event_queue.empty())
|
||||
{
|
||||
TEvent &next_event = m_event_queue.front();
|
||||
process_event(next_event);
|
||||
m_event_queue.pop();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
//============================================================
|
||||
// input_device_list class
|
||||
//============================================================
|
||||
|
||||
class input_device_list
|
||||
{
|
||||
protected:
|
||||
std::vector<std::unique_ptr<device_info>> m_list;
|
||||
|
||||
public:
|
||||
input_device_list()
|
||||
{
|
||||
}
|
||||
|
||||
void poll_devices()
|
||||
{
|
||||
for (auto iter = m_list.begin(); iter != m_list.end(); iter++)
|
||||
iter->get()->poll();
|
||||
}
|
||||
|
||||
void reset_devices()
|
||||
{
|
||||
for (auto iter = m_list.begin(); iter != m_list.end(); iter++)
|
||||
iter->get()->reset();
|
||||
}
|
||||
|
||||
void free_device(device_info * devinfo)
|
||||
{
|
||||
// remove us from the list
|
||||
for (auto iter = m_list.begin(); iter != m_list.end(); iter++)
|
||||
{
|
||||
if (iter->get() == devinfo)
|
||||
{
|
||||
m_list.erase(iter);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int find_index(device_info* devinfo)
|
||||
{
|
||||
// remove us from the list
|
||||
int i = 0;
|
||||
for (auto iter = m_list.begin(); iter != m_list.end(); iter++)
|
||||
{
|
||||
if (iter->get() == devinfo)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
// return the index or -1 if we couldn't find it
|
||||
return i == m_list.size() ? -1 : i;
|
||||
}
|
||||
|
||||
void free_all_devices()
|
||||
{
|
||||
while (!m_list.empty())
|
||||
m_list.pop_back();
|
||||
}
|
||||
|
||||
int size()
|
||||
{
|
||||
return m_list.size();
|
||||
}
|
||||
|
||||
device_info* at(int index)
|
||||
{
|
||||
return m_list.at(index).get();
|
||||
}
|
||||
|
||||
template <typename TActual>
|
||||
TActual* create_device(running_machine &machine, const char *name, input_module &module)
|
||||
{
|
||||
// allocate the device object
|
||||
auto devinfo = std::make_unique<TActual>(machine, name, module);
|
||||
|
||||
// Add the device to the machine
|
||||
devinfo->m_device = machine.input().device_class(devinfo->deviceclass()).add_device(devinfo->name(), devinfo.get());
|
||||
|
||||
// append us to the list
|
||||
m_list.push_back(std::move(devinfo));
|
||||
|
||||
return (TActual*)m_list.back().get();
|
||||
}
|
||||
|
||||
template <class TActual>
|
||||
TActual* at(int index)
|
||||
{
|
||||
return (TActual*)m_list.at(index).get();
|
||||
}
|
||||
};
|
||||
|
||||
// keyboard translation table
|
||||
|
||||
struct key_trans_entry {
|
||||
input_item_id mame_key;
|
||||
|
||||
#if !defined(OSD_WINDOWS)
|
||||
int sdl_scancode;
|
||||
int sdl_key;
|
||||
#else
|
||||
int scan_code;
|
||||
unsigned char virtual_key;
|
||||
#endif
|
||||
|
||||
char ascii_key;
|
||||
char const * mame_key_name;
|
||||
char * ui_name;
|
||||
};
|
||||
|
||||
class keyboard_trans_table
|
||||
{
|
||||
private:
|
||||
// default constructor is private
|
||||
keyboard_trans_table();
|
||||
|
||||
static key_trans_entry s_default_table[];
|
||||
std::unique_ptr<key_trans_entry[]> m_custom_table;
|
||||
|
||||
key_trans_entry * m_table;
|
||||
UINT32 m_table_size;
|
||||
|
||||
public:
|
||||
// constructor
|
||||
keyboard_trans_table(std::unique_ptr<key_trans_entry[]> table, unsigned int size);
|
||||
|
||||
// getters/setters
|
||||
UINT32 size() { return m_table_size; }
|
||||
|
||||
// public methods
|
||||
input_item_id lookup_mame_code(const char * scode);
|
||||
int lookup_mame_index(const char * scode);
|
||||
|
||||
#if defined(OSD_WINDOWS)
|
||||
input_item_id map_di_scancode_to_itemid(int di_scancode);
|
||||
int vkey_for_mame_code(input_code code);
|
||||
#endif
|
||||
|
||||
static keyboard_trans_table& instance()
|
||||
{
|
||||
static keyboard_trans_table s_instance;
|
||||
return s_instance;
|
||||
}
|
||||
|
||||
key_trans_entry & operator [](int i) { return m_table[i]; }
|
||||
};
|
||||
|
||||
//============================================================
|
||||
// input_module_base - base class for input modules
|
||||
//============================================================
|
||||
|
||||
class osd_options;
|
||||
|
||||
typedef std::chrono::high_resolution_clock clock_type;
|
||||
typedef std::chrono::time_point<std::chrono::high_resolution_clock> timepoint_type;
|
||||
|
||||
// 10 milliseconds polling interval
|
||||
#define MIN_POLLING_INTERVAL 10
|
||||
|
||||
class input_module_base : public input_module
|
||||
{
|
||||
public:
|
||||
input_module_base(const char *type, const char* name)
|
||||
: input_module(type, name),
|
||||
m_input_enabled(FALSE),
|
||||
m_mouse_enabled(FALSE),
|
||||
m_lightgun_enabled(FALSE),
|
||||
m_input_paused(FALSE)
|
||||
{
|
||||
}
|
||||
|
||||
private:
|
||||
bool m_input_enabled;
|
||||
bool m_mouse_enabled;
|
||||
bool m_lightgun_enabled;
|
||||
bool m_input_paused;
|
||||
const osd_options * m_options;
|
||||
input_device_list m_devicelist;
|
||||
clock_type m_clock;
|
||||
timepoint_type m_last_poll;
|
||||
|
||||
protected:
|
||||
void set_mouse_enabled(bool value) { m_mouse_enabled = value; }
|
||||
|
||||
public:
|
||||
|
||||
const osd_options * options() { return m_options; }
|
||||
input_device_list * devicelist() { return &m_devicelist; }
|
||||
bool input_enabled() { return m_input_enabled; }
|
||||
bool input_paused() { return m_input_paused; }
|
||||
bool mouse_enabled() { return m_mouse_enabled; }
|
||||
bool lightgun_enabled() { return m_lightgun_enabled; }
|
||||
|
||||
int init(const osd_options &options) override;
|
||||
|
||||
void poll_if_necessary(running_machine &machine) override
|
||||
{
|
||||
auto elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(m_clock.now() - m_last_poll);
|
||||
if (elapsed.count() >= MIN_POLLING_INTERVAL)
|
||||
{
|
||||
poll(machine);
|
||||
}
|
||||
}
|
||||
|
||||
virtual void poll(running_machine &machine)
|
||||
{
|
||||
// ignore if not enabled
|
||||
if (m_input_enabled)
|
||||
{
|
||||
// grab the current time
|
||||
m_last_poll = m_clock.now();
|
||||
|
||||
before_poll(machine);
|
||||
|
||||
// track if mouse/lightgun is enabled, for mouse hiding purposes
|
||||
m_mouse_enabled = machine.input().device_class(DEVICE_CLASS_MOUSE).enabled();
|
||||
m_lightgun_enabled = machine.input().device_class(DEVICE_CLASS_LIGHTGUN).enabled();
|
||||
}
|
||||
|
||||
// poll all of the devices
|
||||
if (should_poll_devices(machine))
|
||||
{
|
||||
m_devicelist.poll_devices();
|
||||
}
|
||||
else
|
||||
{
|
||||
m_devicelist.reset_devices();
|
||||
}
|
||||
}
|
||||
|
||||
virtual void pause() override
|
||||
{
|
||||
// keep track of the paused state
|
||||
m_input_paused = true;
|
||||
}
|
||||
|
||||
virtual void resume() override
|
||||
{
|
||||
// keep track of the paused state
|
||||
m_input_paused = false;
|
||||
}
|
||||
|
||||
virtual void exit() override
|
||||
{
|
||||
devicelist()->free_all_devices();
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual int init_internal() { return 0; }
|
||||
virtual bool should_poll_devices(running_machine &machine) = 0;
|
||||
virtual void before_poll(running_machine &machine) {}
|
||||
};
|
||||
|
||||
inline static int generic_button_get_state(void *device_internal, void *item_internal)
|
||||
{
|
||||
device_info *devinfo = (device_info *)device_internal;
|
||||
unsigned char *itemdata = (unsigned char*)item_internal;
|
||||
|
||||
// return the current state
|
||||
devinfo->module().poll_if_necessary(devinfo->machine());
|
||||
return *itemdata >> 7;
|
||||
}
|
||||
|
||||
inline static int generic_axis_get_state(void *device_internal, void *item_internal)
|
||||
{
|
||||
device_info *devinfo = (device_info *)device_internal;
|
||||
int *axisdata = (int*)item_internal;
|
||||
|
||||
// return the current state
|
||||
devinfo->module().poll_if_necessary(devinfo->machine());
|
||||
return *axisdata;
|
||||
}
|
||||
|
||||
//============================================================
|
||||
// default_button_name
|
||||
//============================================================
|
||||
|
||||
inline static const char *default_button_name(int which)
|
||||
{
|
||||
static char buffer[20];
|
||||
snprintf(buffer, ARRAY_LENGTH(buffer), "B%d", which);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
//============================================================
|
||||
// default_pov_name
|
||||
//============================================================
|
||||
|
||||
inline static const char *default_pov_name(int which)
|
||||
{
|
||||
static char buffer[20];
|
||||
snprintf(buffer, ARRAY_LENGTH(buffer), "POV%d", which);
|
||||
return buffer;
|
||||
}
|
||||
|
||||
// default axis names
|
||||
const char *const default_axis_name[] =
|
||||
{
|
||||
"X", "Y", "Z", "RX",
|
||||
"RY", "RZ", "SL1", "SL2"
|
||||
};
|
||||
|
||||
inline static INT32 normalize_absolute_axis(INT32 raw, INT32 rawmin, INT32 rawmax)
|
||||
{
|
||||
INT32 center = (rawmax + rawmin) / 2;
|
||||
|
||||
// make sure we have valid data
|
||||
if (rawmin >= rawmax)
|
||||
return raw;
|
||||
|
||||
// above center
|
||||
if (raw >= center)
|
||||
{
|
||||
INT32 result = (INT64)(raw - center) * (INT64)INPUT_ABSOLUTE_MAX / (INT64)(rawmax - center);
|
||||
return MIN(result, INPUT_ABSOLUTE_MAX);
|
||||
}
|
||||
|
||||
// below center
|
||||
else
|
||||
{
|
||||
INT32 result = -((INT64)(center - raw) * (INT64)-INPUT_ABSOLUTE_MIN / (INT64)(center - rawmin));
|
||||
return MAX(result, INPUT_ABSOLUTE_MIN);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
683
src/osd/modules/input/input_dinput.cpp
Normal file
683
src/osd/modules/input/input_dinput.cpp
Normal file
@ -0,0 +1,683 @@
|
||||
// license:BSD-3-Clause
|
||||
// copyright-holders:Aaron Giles, Brad Hughes
|
||||
//============================================================
|
||||
//
|
||||
// input_dinput.cpp - Windows DirectInput support
|
||||
//
|
||||
//============================================================
|
||||
|
||||
#include "input_module.h"
|
||||
#include "modules/osdmodule.h"
|
||||
|
||||
#if defined(OSD_WINDOWS)
|
||||
|
||||
// standard windows headers
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
#include <winioctl.h>
|
||||
#include <tchar.h>
|
||||
|
||||
// undef WINNT for dinput.h to prevent duplicate definition
|
||||
#undef WINNT
|
||||
#include <dinput.h>
|
||||
#undef interface
|
||||
|
||||
#include <mutex>
|
||||
#include <thread>
|
||||
|
||||
// MAME headers
|
||||
#include "emu.h"
|
||||
#include "osdepend.h"
|
||||
#include "ui/ui.h"
|
||||
#include "strconv.h"
|
||||
|
||||
// MAMEOS headers
|
||||
#include "winmain.h"
|
||||
#include "window.h"
|
||||
#include "winutil.h"
|
||||
#include "../../windows/input.h"
|
||||
|
||||
#include "input_common.h"
|
||||
#include "input_windows.h"
|
||||
|
||||
#define STRUCTSIZE(x) (m_dinput_version == 0x0300) ? sizeof(x##_DX3) : sizeof(x)
|
||||
|
||||
static INT32 dinput_joystick_pov_get_state(void *device_internal, void *item_internal);
|
||||
|
||||
//============================================================
|
||||
// dinput_set_dword_property
|
||||
//============================================================
|
||||
|
||||
static HRESULT dinput_set_dword_property(LPDIRECTINPUTDEVICE device, REFGUID property_guid, DWORD object, DWORD how, DWORD value)
|
||||
{
|
||||
DIPROPDWORD dipdw;
|
||||
|
||||
dipdw.diph.dwSize = sizeof(dipdw);
|
||||
dipdw.diph.dwHeaderSize = sizeof(dipdw.diph);
|
||||
dipdw.diph.dwObj = object;
|
||||
dipdw.diph.dwHow = how;
|
||||
dipdw.dwData = value;
|
||||
|
||||
return IDirectInputDevice_SetProperty(device, property_guid, &dipdw.diph);
|
||||
}
|
||||
|
||||
//============================================================
|
||||
// dinput_device - base directinput device
|
||||
//============================================================
|
||||
|
||||
// DirectInput-specific information about a device
|
||||
struct dinput_api_state
|
||||
{
|
||||
LPDIRECTINPUTDEVICE device;
|
||||
LPDIRECTINPUTDEVICE2 device2;
|
||||
DIDEVCAPS caps;
|
||||
LPCDIDATAFORMAT format;
|
||||
};
|
||||
|
||||
class dinput_device : public device_info
|
||||
{
|
||||
public:
|
||||
dinput_api_state dinput;
|
||||
|
||||
dinput_device(running_machine &machine, const char *name, input_device_class deviceclass, input_module &module)
|
||||
: device_info(machine, name, deviceclass, module),
|
||||
dinput({0})
|
||||
{
|
||||
}
|
||||
|
||||
protected:
|
||||
HRESULT poll_dinput(LPVOID pState)
|
||||
{
|
||||
HRESULT result;
|
||||
|
||||
// first poll the device, then get the state
|
||||
if (dinput.device2 != NULL)
|
||||
IDirectInputDevice2_Poll(dinput.device2);
|
||||
|
||||
// GetDeviceState returns the immediate state
|
||||
result = IDirectInputDevice_GetDeviceState(dinput.device, dinput.format->dwDataSize, pState);
|
||||
|
||||
// handle lost inputs here
|
||||
if (result == DIERR_INPUTLOST || result == DIERR_NOTACQUIRED)
|
||||
{
|
||||
result = IDirectInputDevice_Acquire(dinput.device);
|
||||
if (result == DI_OK)
|
||||
result = IDirectInputDevice_GetDeviceState(dinput.device, dinput.format->dwDataSize, pState);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
//============================================================
|
||||
// dinput_keyboard_device - directinput keyboard device
|
||||
//============================================================
|
||||
|
||||
class dinput_keyboard_device : public dinput_device
|
||||
{
|
||||
private:
|
||||
HANDLE m_dataEvent;
|
||||
HANDLE m_exitEvent;
|
||||
std::mutex m_device_lock;
|
||||
|
||||
public:
|
||||
keyboard_state keyboard;
|
||||
|
||||
dinput_keyboard_device(running_machine &machine, const char *name, input_module &module)
|
||||
: dinput_device(machine, name, DEVICE_CLASS_KEYBOARD, module),
|
||||
keyboard({0})
|
||||
{
|
||||
}
|
||||
|
||||
// Polls the direct input immediate state
|
||||
void poll() override
|
||||
{
|
||||
std::lock_guard<std::mutex> scope_lock(m_device_lock);
|
||||
|
||||
// Poll the state
|
||||
dinput_device::poll_dinput(&keyboard.state);
|
||||
}
|
||||
|
||||
void reset() override
|
||||
{
|
||||
memset(&keyboard, 0, sizeof(keyboard));
|
||||
}
|
||||
};
|
||||
|
||||
//============================================================
|
||||
// dinput_module - base directinput module
|
||||
//============================================================
|
||||
|
||||
class dinput_module : public wininput_module
|
||||
{
|
||||
private:
|
||||
LPDIRECTINPUT m_dinput;
|
||||
int m_dinput_version;
|
||||
int didevtype_keyboard;
|
||||
int didevtype_mouse;
|
||||
|
||||
public:
|
||||
dinput_module(const char* type, const char* name)
|
||||
: wininput_module(type, name)
|
||||
{
|
||||
}
|
||||
|
||||
int init_internal() override
|
||||
{
|
||||
HRESULT result = S_OK;
|
||||
|
||||
#if DIRECTINPUT_VERSION >= 0x800
|
||||
m_dinput_version = DIRECTINPUT_VERSION;
|
||||
result = DirectInput8Create(GetModuleHandleUni(), m_dinput_version, IID_IDirectInput8, (void **)&m_dinput, NULL);
|
||||
if (result != DI_OK)
|
||||
{
|
||||
m_dinput_version = 0;
|
||||
return result;
|
||||
}
|
||||
#else
|
||||
// first attempt to initialize DirectInput at the current version
|
||||
m_dinput_version = DIRECTINPUT_VERSION;
|
||||
result = DirectInputCreate(GetModuleHandleUni(), m_dinput_version, &m_dinput, NULL);
|
||||
if (result != DI_OK)
|
||||
{
|
||||
// if that fails, try version 5
|
||||
m_dinput_version = 0x0500;
|
||||
result = DirectInputCreate(GetModuleHandleUni(), m_dinput_version, &m_dinput, NULL);
|
||||
if (result != DI_OK)
|
||||
{
|
||||
// if that fails, try version 3
|
||||
m_dinput_version = 0x0300;
|
||||
result = DirectInputCreate(GetModuleHandleUni(), m_dinput_version, &m_dinput, NULL);
|
||||
if (result != DI_OK)
|
||||
{
|
||||
m_dinput_version = 0;
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
osd_printf_verbose("DirectInput: Using DirectInput %d\n", m_dinput_version >> 8);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void exit() override
|
||||
{
|
||||
wininput_module::exit();
|
||||
}
|
||||
|
||||
virtual BOOL device_enum_callback(LPCDIDEVICEINSTANCE instance, LPVOID ref) = 0;
|
||||
|
||||
void input_init(running_machine &machine) override
|
||||
{
|
||||
struct dinput_callback_context
|
||||
{
|
||||
dinput_module * self;
|
||||
running_machine * machine;
|
||||
} context = { this, &machine };
|
||||
|
||||
// enumerate the ones we have
|
||||
auto enum_callback = [](LPCDIDEVICEINSTANCE instance, LPVOID ref) {
|
||||
return ((dinput_callback_context*)ref)->self->device_enum_callback(instance, ((dinput_callback_context*)ref)->machine);
|
||||
};
|
||||
|
||||
HRESULT result = IDirectInput_EnumDevices(m_dinput, dinput_devclass(), enum_callback, &context, DIEDFL_ATTACHEDONLY);
|
||||
if (result != DI_OK)
|
||||
fatalerror("DirectInput: Unable to enumerate keyboards (result=%08X)\n", (UINT32)result);
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual int dinput_devclass() = 0;
|
||||
|
||||
template <class TDevice>
|
||||
TDevice* create_dinput_device(
|
||||
running_machine &machine,
|
||||
LPCDIDEVICEINSTANCE instance,
|
||||
LPCDIDATAFORMAT format1,
|
||||
LPCDIDATAFORMAT format2,
|
||||
DWORD cooperative_level)
|
||||
{
|
||||
HRESULT result;
|
||||
|
||||
// convert instance name to utf8
|
||||
auto osd_deleter = [](void *ptr) { osd_free(ptr); };
|
||||
auto utf8_instance_name = std::unique_ptr<char, decltype(osd_deleter)>(utf8_from_tstring(instance->tszInstanceName), osd_deleter);
|
||||
|
||||
// allocate memory for the device object
|
||||
TDevice* devinfo = devicelist()->create_device<TDevice>(machine, utf8_instance_name.get(), *this);
|
||||
|
||||
// attempt to create a device
|
||||
result = IDirectInput_CreateDevice(m_dinput, WRAP_REFIID(instance->guidInstance), &devinfo->dinput.device, NULL);
|
||||
if (result != DI_OK)
|
||||
goto error;
|
||||
|
||||
// try to get a version 2 device for it
|
||||
result = IDirectInputDevice_QueryInterface(devinfo->dinput.device, WRAP_REFIID(IID_IDirectInputDevice2), (void **)&devinfo->dinput.device2);
|
||||
if (result != DI_OK)
|
||||
devinfo->dinput.device2 = NULL;
|
||||
|
||||
// get the caps
|
||||
devinfo->dinput.caps.dwSize = STRUCTSIZE(DIDEVCAPS);
|
||||
result = IDirectInputDevice_GetCapabilities(devinfo->dinput.device, &devinfo->dinput.caps);
|
||||
if (result != DI_OK)
|
||||
goto error;
|
||||
|
||||
// attempt to set the data format
|
||||
devinfo->dinput.format = format1;
|
||||
result = IDirectInputDevice_SetDataFormat(devinfo->dinput.device, devinfo->dinput.format);
|
||||
if (result != DI_OK)
|
||||
{
|
||||
// use the secondary format if available
|
||||
if (format2 != NULL)
|
||||
{
|
||||
devinfo->dinput.format = format2;
|
||||
result = IDirectInputDevice_SetDataFormat(devinfo->dinput.device, devinfo->dinput.format);
|
||||
}
|
||||
if (result != DI_OK)
|
||||
goto error;
|
||||
}
|
||||
|
||||
// set the cooperative level
|
||||
result = IDirectInputDevice_SetCooperativeLevel(devinfo->dinput.device, win_window_list->m_hwnd, cooperative_level);
|
||||
if (result != DI_OK)
|
||||
goto error;
|
||||
return devinfo;
|
||||
|
||||
error:
|
||||
devicelist()->free_device(devinfo);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
std::string device_item_name(dinput_device * devinfo, int offset, const char * defstring, const TCHAR * suffix)
|
||||
{
|
||||
DIDEVICEOBJECTINSTANCE instance = { 0 };
|
||||
HRESULT result;
|
||||
|
||||
// query the key name
|
||||
instance.dwSize = STRUCTSIZE(DIDEVICEOBJECTINSTANCE);
|
||||
result = IDirectInputDevice_GetObjectInfo(devinfo->dinput.device, &instance, offset, DIPH_BYOFFSET);
|
||||
|
||||
// if we got an error and have no default string, just return NULL
|
||||
if (result != DI_OK)
|
||||
{
|
||||
if (defstring == nullptr)
|
||||
return nullptr;
|
||||
|
||||
// Return the default value
|
||||
return std::string(defstring);
|
||||
}
|
||||
|
||||
auto osd_free_deleter = [](char *p) { osd_free(p); };
|
||||
|
||||
// convert the name to utf8
|
||||
auto namestring = std::unique_ptr<char, decltype(osd_free_deleter)>(utf8_from_tstring(instance.tszName), osd_free_deleter);
|
||||
|
||||
// if no suffix, return as-is
|
||||
if (suffix == nullptr)
|
||||
{
|
||||
return std::string(namestring.get());
|
||||
}
|
||||
|
||||
// otherwise, allocate space to add the suffix
|
||||
auto combined = std::make_unique<char[]>(strlen(namestring.get()) + 1 + _tcslen(suffix) + 1);
|
||||
|
||||
// convert the suffix to utf8
|
||||
auto suffix_utf8 = std::unique_ptr<char, decltype(osd_free_deleter)>(utf8_from_tstring(suffix), osd_free_deleter);
|
||||
|
||||
// Concat the name and suffix
|
||||
strcpy(combined.get(), namestring.get());
|
||||
strcat(combined.get(), " ");
|
||||
strcat(combined.get(), suffix_utf8.get());
|
||||
|
||||
return std::string(combined.get());
|
||||
}
|
||||
};
|
||||
|
||||
class keyboard_input_dinput : public dinput_module
|
||||
{
|
||||
public:
|
||||
keyboard_input_dinput() :
|
||||
dinput_module(OSD_KEYBOARDINPUT_PROVIDER, "dinput")
|
||||
{
|
||||
}
|
||||
|
||||
int dinput_devclass() override
|
||||
{
|
||||
#if DIRECTINPUT_VERSION >= 0x800
|
||||
return DI8DEVCLASS_KEYBOARD;
|
||||
#else
|
||||
return DIDEVTYPE_KEYBOARD;
|
||||
#endif
|
||||
}
|
||||
|
||||
BOOL device_enum_callback(LPCDIDEVICEINSTANCE instance, LPVOID ref) override
|
||||
{
|
||||
running_machine &machine = *(running_machine *)ref;
|
||||
dinput_keyboard_device *devinfo;
|
||||
int keynum;
|
||||
|
||||
// allocate and link in a new device
|
||||
devinfo = create_dinput_device<dinput_keyboard_device>(machine, instance, &c_dfDIKeyboard, NULL, DISCL_FOREGROUND | DISCL_NONEXCLUSIVE);
|
||||
if (devinfo == NULL)
|
||||
goto exit;
|
||||
|
||||
// populate it
|
||||
for (keynum = 0; keynum < MAX_KEYS; keynum++)
|
||||
{
|
||||
input_item_id itemid = keyboard_trans_table::instance().map_di_scancode_to_itemid(keynum);
|
||||
char defname[20];
|
||||
std::string name;
|
||||
|
||||
// generate/fetch the name
|
||||
snprintf(defname, ARRAY_LENGTH(defname), "Scan%03d", keynum);
|
||||
name = device_item_name(devinfo, keynum, defname, NULL);
|
||||
|
||||
// add the item to the device
|
||||
devinfo->device()->add_item(name.c_str(), itemid, generic_button_get_state, &devinfo->keyboard.state[keynum]);
|
||||
}
|
||||
|
||||
exit:
|
||||
return DIENUM_CONTINUE;
|
||||
}
|
||||
};
|
||||
|
||||
class dinput_mouse_device : public dinput_device
|
||||
{
|
||||
public:
|
||||
mouse_state mouse;
|
||||
|
||||
dinput_mouse_device(running_machine &machine, const char *name, input_module &module)
|
||||
: dinput_device(machine, name, DEVICE_CLASS_MOUSE, module),
|
||||
mouse({0})
|
||||
{
|
||||
}
|
||||
|
||||
void poll() override
|
||||
{
|
||||
// poll
|
||||
dinput_device::poll_dinput(&mouse);
|
||||
|
||||
// scale the axis data
|
||||
mouse.lX *= INPUT_RELATIVE_PER_PIXEL;
|
||||
mouse.lY *= INPUT_RELATIVE_PER_PIXEL;
|
||||
mouse.lZ *= INPUT_RELATIVE_PER_PIXEL;
|
||||
}
|
||||
|
||||
void reset() override
|
||||
{
|
||||
memset(&mouse, 0, sizeof(mouse));
|
||||
}
|
||||
};
|
||||
|
||||
class mouse_input_dinput : public dinput_module
|
||||
{
|
||||
public:
|
||||
mouse_input_dinput() :
|
||||
dinput_module(OSD_MOUSEINPUT_PROVIDER, "dinput")
|
||||
{
|
||||
}
|
||||
|
||||
int dinput_devclass() override
|
||||
{
|
||||
#if DIRECTINPUT_VERSION >= 0x800
|
||||
return DI8DEVCLASS_POINTER;
|
||||
#else
|
||||
return DI8DEVTYPE_MOUSE;
|
||||
#endif
|
||||
}
|
||||
|
||||
BOOL device_enum_callback(LPCDIDEVICEINSTANCE instance, LPVOID ref) override
|
||||
{
|
||||
dinput_mouse_device *devinfo = NULL;
|
||||
running_machine &machine = *(running_machine *)ref;
|
||||
int axisnum, butnum;
|
||||
HRESULT result;
|
||||
|
||||
// allocate and link in a new device
|
||||
devinfo = create_dinput_device<dinput_mouse_device>(machine, instance, &c_dfDIMouse2, &c_dfDIMouse, DISCL_FOREGROUND | DISCL_NONEXCLUSIVE);
|
||||
if (devinfo == NULL)
|
||||
goto exit;
|
||||
|
||||
// set relative mode on the mouse device
|
||||
result = dinput_set_dword_property(devinfo->dinput.device, DIPROP_AXISMODE, 0, DIPH_DEVICE, DIPROPAXISMODE_REL);
|
||||
if (result != DI_OK && result != DI_PROPNOEFFECT)
|
||||
{
|
||||
osd_printf_error("DirectInput: Unable to set relative mode for mouse %d (%s)\n", devicelist()->size(), devinfo->name());
|
||||
goto error;
|
||||
}
|
||||
|
||||
// cap the number of axes and buttons based on the format
|
||||
devinfo->dinput.caps.dwAxes = MIN(devinfo->dinput.caps.dwAxes, 3);
|
||||
devinfo->dinput.caps.dwButtons = MIN(devinfo->dinput.caps.dwButtons, (devinfo->dinput.format == &c_dfDIMouse) ? 4 : 8);
|
||||
|
||||
// populate the axes
|
||||
for (axisnum = 0; axisnum < devinfo->dinput.caps.dwAxes; axisnum++)
|
||||
{
|
||||
// add to the mouse device and optionally to the gun device as well
|
||||
std::string name = device_item_name(devinfo, offsetof(DIMOUSESTATE, lX) + axisnum * sizeof(LONG), default_axis_name[axisnum], NULL);
|
||||
devinfo->device()->add_item(name.c_str(), (input_item_id)(ITEM_ID_XAXIS + axisnum), generic_axis_get_state, &devinfo->mouse.lX + axisnum);
|
||||
}
|
||||
|
||||
// populate the buttons
|
||||
for (butnum = 0; butnum < devinfo->dinput.caps.dwButtons; butnum++)
|
||||
{
|
||||
FPTR offset = (FPTR)(&((DIMOUSESTATE *)NULL)->rgbButtons[butnum]);
|
||||
|
||||
// add to the mouse device
|
||||
std::string name = device_item_name(devinfo, offset, default_button_name(butnum), NULL);
|
||||
devinfo->device()->add_item(name.c_str(), (input_item_id)(ITEM_ID_BUTTON1 + butnum), generic_button_get_state, &devinfo->mouse.rgbButtons[butnum]);
|
||||
}
|
||||
|
||||
exit:
|
||||
return DIENUM_CONTINUE;
|
||||
|
||||
error:
|
||||
if (devinfo != NULL)
|
||||
devicelist()->free_device(devinfo);
|
||||
goto exit;
|
||||
}
|
||||
};
|
||||
|
||||
// state information for a joystick; DirectInput state must be first element
|
||||
struct dinput_joystick_state
|
||||
{
|
||||
DIJOYSTATE state;
|
||||
LONG rangemin[8];
|
||||
LONG rangemax[8];
|
||||
};
|
||||
|
||||
class dinput_joystick_device : public dinput_device
|
||||
{
|
||||
public:
|
||||
dinput_joystick_state joystick;
|
||||
|
||||
dinput_joystick_device(running_machine &machine, const char *name, input_module &module)
|
||||
: dinput_device(machine, name, DEVICE_CLASS_JOYSTICK, module),
|
||||
joystick({0})
|
||||
{
|
||||
}
|
||||
|
||||
void reset() override
|
||||
{
|
||||
memset(&joystick, 0, sizeof(joystick));
|
||||
}
|
||||
|
||||
void poll() override
|
||||
{
|
||||
int axisnum;
|
||||
|
||||
// poll the device first
|
||||
dinput_device::poll_dinput(&joystick.state);
|
||||
|
||||
// normalize axis values
|
||||
for (axisnum = 0; axisnum < 8; axisnum++)
|
||||
{
|
||||
LONG *axis = (&joystick.state.lX) + axisnum;
|
||||
*axis = normalize_absolute_axis(*axis, joystick.rangemin[axisnum], joystick.rangemax[axisnum]);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class joystick_input_dinput : public dinput_module
|
||||
{
|
||||
public:
|
||||
joystick_input_dinput() :
|
||||
dinput_module(OSD_JOYSTICKINPUT_PROVIDER, "dinput")
|
||||
{
|
||||
}
|
||||
|
||||
int dinput_devclass() override
|
||||
{
|
||||
#if DIRECTINPUT_VERSION >= 0x800
|
||||
return DI8DEVCLASS_GAMECTRL;
|
||||
#else
|
||||
return DI8DEVTYPE_JOYSTICK;
|
||||
#endif
|
||||
}
|
||||
|
||||
BOOL device_enum_callback(LPCDIDEVICEINSTANCE instance, LPVOID ref) override
|
||||
{
|
||||
DWORD cooperative_level = DISCL_FOREGROUND | DISCL_NONEXCLUSIVE;
|
||||
int axisnum, axiscount, povnum, butnum;
|
||||
running_machine &machine = *(running_machine *)ref;
|
||||
dinput_joystick_device *devinfo;
|
||||
HRESULT result;
|
||||
|
||||
if (win_window_list != NULL && win_window_list->win_has_menu()) {
|
||||
cooperative_level = DISCL_BACKGROUND | DISCL_NONEXCLUSIVE;
|
||||
}
|
||||
// allocate and link in a new device
|
||||
devinfo = create_dinput_device<dinput_joystick_device>(machine, instance, &c_dfDIJoystick, NULL, cooperative_level);
|
||||
if (devinfo == NULL)
|
||||
goto exit;
|
||||
|
||||
// set absolute mode
|
||||
result = dinput_set_dword_property(devinfo->dinput.device, DIPROP_AXISMODE, 0, DIPH_DEVICE, DIPROPAXISMODE_ABS);
|
||||
if (result != DI_OK && result != DI_PROPNOEFFECT)
|
||||
osd_printf_warning("DirectInput: Unable to set absolute mode for joystick %d (%s)\n", devicelist()->size(), devinfo->name());
|
||||
|
||||
// turn off deadzone; we do our own calculations
|
||||
result = dinput_set_dword_property(devinfo->dinput.device, DIPROP_DEADZONE, 0, DIPH_DEVICE, 0);
|
||||
if (result != DI_OK && result != DI_PROPNOEFFECT)
|
||||
osd_printf_warning("DirectInput: Unable to reset deadzone for joystick %d (%s)\n", devicelist()->size(), devinfo->name());
|
||||
|
||||
// turn off saturation; we do our own calculations
|
||||
result = dinput_set_dword_property(devinfo->dinput.device, DIPROP_SATURATION, 0, DIPH_DEVICE, 10000);
|
||||
if (result != DI_OK && result != DI_PROPNOEFFECT)
|
||||
osd_printf_warning("DirectInput: Unable to reset saturation for joystick %d (%s)\n", devicelist()->size(), devinfo->name());
|
||||
|
||||
// cap the number of axes, POVs, and buttons based on the format
|
||||
devinfo->dinput.caps.dwAxes = MIN(devinfo->dinput.caps.dwAxes, 8);
|
||||
devinfo->dinput.caps.dwPOVs = MIN(devinfo->dinput.caps.dwPOVs, 4);
|
||||
devinfo->dinput.caps.dwButtons = MIN(devinfo->dinput.caps.dwButtons, 128);
|
||||
|
||||
// populate the axes
|
||||
for (axisnum = axiscount = 0; axiscount < devinfo->dinput.caps.dwAxes && axisnum < 8; axisnum++)
|
||||
{
|
||||
DIPROPRANGE dipr;
|
||||
std::string name;
|
||||
|
||||
// fetch the range of this axis
|
||||
dipr.diph.dwSize = sizeof(dipr);
|
||||
dipr.diph.dwHeaderSize = sizeof(dipr.diph);
|
||||
dipr.diph.dwObj = offsetof(DIJOYSTATE2, lX) + axisnum * sizeof(LONG);
|
||||
dipr.diph.dwHow = DIPH_BYOFFSET;
|
||||
result = IDirectInputDevice_GetProperty(devinfo->dinput.device, DIPROP_RANGE, &dipr.diph);
|
||||
if (result != DI_OK)
|
||||
continue;
|
||||
|
||||
devinfo->joystick.rangemin[axisnum] = dipr.lMin;
|
||||
devinfo->joystick.rangemax[axisnum] = dipr.lMax;
|
||||
|
||||
// populate the item description as well
|
||||
name = device_item_name(devinfo, offsetof(DIJOYSTATE2, lX) + axisnum * sizeof(LONG), default_axis_name[axisnum], NULL);
|
||||
devinfo->device()->add_item(name.c_str(), (input_item_id)(ITEM_ID_XAXIS + axisnum), generic_axis_get_state, &devinfo->joystick.state.lX + axisnum);
|
||||
|
||||
axiscount++;
|
||||
}
|
||||
|
||||
// populate the POVs
|
||||
for (povnum = 0; povnum < devinfo->dinput.caps.dwPOVs; povnum++)
|
||||
{
|
||||
std::string name;
|
||||
|
||||
// left
|
||||
name = device_item_name(devinfo, offsetof(DIJOYSTATE2, rgdwPOV) + povnum * sizeof(DWORD), default_pov_name(povnum), TEXT("L"));
|
||||
devinfo->device()->add_item(name.c_str(), ITEM_ID_OTHER_SWITCH, dinput_joystick_pov_get_state, (void *)(FPTR)(povnum * 4 + POVDIR_LEFT));
|
||||
|
||||
// right
|
||||
name = device_item_name(devinfo, offsetof(DIJOYSTATE2, rgdwPOV) + povnum * sizeof(DWORD), default_pov_name(povnum), TEXT("R"));
|
||||
devinfo->device()->add_item(name.c_str(), ITEM_ID_OTHER_SWITCH, dinput_joystick_pov_get_state, (void *)(FPTR)(povnum * 4 + POVDIR_RIGHT));
|
||||
|
||||
// up
|
||||
name = device_item_name(devinfo, offsetof(DIJOYSTATE2, rgdwPOV) + povnum * sizeof(DWORD), default_pov_name(povnum), TEXT("U"));
|
||||
devinfo->device()->add_item(name.c_str(), ITEM_ID_OTHER_SWITCH, dinput_joystick_pov_get_state, (void *)(FPTR)(povnum * 4 + POVDIR_UP));
|
||||
|
||||
// down
|
||||
name = device_item_name(devinfo, offsetof(DIJOYSTATE2, rgdwPOV) + povnum * sizeof(DWORD), default_pov_name(povnum), TEXT("D"));
|
||||
devinfo->device()->add_item(name.c_str(), ITEM_ID_OTHER_SWITCH, dinput_joystick_pov_get_state, (void *)(FPTR)(povnum * 4 + POVDIR_DOWN));
|
||||
}
|
||||
|
||||
// populate the buttons
|
||||
for (butnum = 0; butnum < devinfo->dinput.caps.dwButtons; butnum++)
|
||||
{
|
||||
FPTR offset = (FPTR)(&((DIJOYSTATE2 *)NULL)->rgbButtons[butnum]);
|
||||
std::string name = device_item_name(devinfo, offset, default_button_name(butnum), NULL);
|
||||
|
||||
input_item_id itemid;
|
||||
|
||||
if (butnum < INPUT_MAX_BUTTONS)
|
||||
itemid = (input_item_id)(ITEM_ID_BUTTON1 + butnum);
|
||||
else if (butnum < INPUT_MAX_BUTTONS + INPUT_MAX_ADD_SWITCH)
|
||||
itemid = (input_item_id)(ITEM_ID_ADD_SWITCH1 - INPUT_MAX_BUTTONS + butnum);
|
||||
else
|
||||
itemid = ITEM_ID_OTHER_SWITCH;
|
||||
|
||||
devinfo->device()->add_item(name.c_str(), itemid, generic_button_get_state, &devinfo->joystick.state.rgbButtons[butnum]);
|
||||
}
|
||||
|
||||
exit:
|
||||
return DIENUM_CONTINUE;
|
||||
}
|
||||
};
|
||||
|
||||
//============================================================
|
||||
// dinput_joystick_pov_get_state
|
||||
//============================================================
|
||||
|
||||
static INT32 dinput_joystick_pov_get_state(void *device_internal, void *item_internal)
|
||||
{
|
||||
dinput_joystick_device *devinfo = (dinput_joystick_device *)device_internal;
|
||||
int povnum = (FPTR)item_internal / 4;
|
||||
int povdir = (FPTR)item_internal % 4;
|
||||
INT32 result = 0;
|
||||
DWORD pov;
|
||||
|
||||
// get the current state
|
||||
devinfo->module().poll_if_necessary(devinfo->machine());
|
||||
pov = devinfo->joystick.state.rgdwPOV[povnum];
|
||||
|
||||
// if invalid, return 0
|
||||
if ((pov & 0xffff) == 0xffff)
|
||||
return result;
|
||||
|
||||
// return the current state
|
||||
switch (povdir)
|
||||
{
|
||||
case POVDIR_LEFT: result = (pov >= 22500 && pov <= 31500); break;
|
||||
case POVDIR_RIGHT: result = (pov >= 4500 && pov <= 13500); break;
|
||||
case POVDIR_UP: result = (pov >= 31500 || pov <= 4500); break;
|
||||
case POVDIR_DOWN: result = (pov >= 13500 && pov <= 22500); break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
#else
|
||||
MODULE_NOT_SUPPORTED(keyboard_input_dinput, OSD_KEYBOARDINPUT_PROVIDER, "dinput")
|
||||
MODULE_NOT_SUPPORTED(mouse_input_dinput, OSD_MOUSEINPUT_PROVIDER, "dinput")
|
||||
MODULE_NOT_SUPPORTED(joystick_input_dinput, OSD_JOYSTICKINPUT_PROVIDER, "dinput")
|
||||
#endif
|
||||
|
||||
MODULE_DEFINITION(KEYBOARDINPUT_DINPUT, keyboard_input_dinput)
|
||||
MODULE_DEFINITION(MOUSEINPUT_DINPUT, mouse_input_dinput)
|
||||
MODULE_DEFINITION(JOYSTICKINPUT_DINPUT, joystick_input_dinput)
|
39
src/osd/modules/input/input_module.h
Normal file
39
src/osd/modules/input/input_module.h
Normal file
@ -0,0 +1,39 @@
|
||||
// license:BSD-3-Clause
|
||||
// copyright-holders:Brad Hughes
|
||||
//============================================================
|
||||
//
|
||||
// input_module.h - OSD input module contracts
|
||||
//
|
||||
//============================================================
|
||||
|
||||
#ifndef INPUT_MODULE_H_
|
||||
#define INPUT_MODULE_H_
|
||||
|
||||
#include "osdepend.h"
|
||||
#include "modules/osdmodule.h"
|
||||
|
||||
class input_module : public osd_module
|
||||
{
|
||||
public:
|
||||
input_module(const char *type, const char *name)
|
||||
: osd_module(type, name)
|
||||
{
|
||||
}
|
||||
|
||||
virtual void input_init(running_machine &machine) = 0;
|
||||
virtual void poll_if_necessary(running_machine &machine) = 0;
|
||||
virtual void pause() = 0;
|
||||
virtual void resume() = 0;
|
||||
virtual void exit() override {};
|
||||
};
|
||||
|
||||
//============================================================
|
||||
// CONSTANTS
|
||||
//============================================================
|
||||
|
||||
#define OSD_KEYBOARDINPUT_PROVIDER "keyboardprovider"
|
||||
#define OSD_MOUSEINPUT_PROVIDER "mouseprovider"
|
||||
#define OSD_LIGHTGUNINPUT_PROVIDER "lightgunprovider"
|
||||
#define OSD_JOYSTICKINPUT_PROVIDER "joystickprovider"
|
||||
|
||||
#endif /* INPUT_MODULE_H_ */
|
66
src/osd/modules/input/input_none.cpp
Normal file
66
src/osd/modules/input/input_none.cpp
Normal file
@ -0,0 +1,66 @@
|
||||
// license:BSD-3-Clause
|
||||
// copyright-holders:Brad Hughes
|
||||
//============================================================
|
||||
//
|
||||
// input_none.cpp - Default unimplemented input modules
|
||||
//
|
||||
//============================================================
|
||||
|
||||
#include "input_module.h"
|
||||
#include "modules/osdmodule.h"
|
||||
|
||||
class keyboard_input_none : public input_module
|
||||
{
|
||||
public:
|
||||
keyboard_input_none()
|
||||
: input_module(OSD_KEYBOARDINPUT_PROVIDER, "none") {}
|
||||
int init(const osd_options &options) override { return 0; }
|
||||
void poll_if_necessary(running_machine &machine) override {};
|
||||
void input_init(running_machine &machine) override {};
|
||||
void pause() override {};
|
||||
void resume() override {};
|
||||
};
|
||||
|
||||
MODULE_DEFINITION(KEYBOARD_NONE, keyboard_input_none)
|
||||
|
||||
class mouse_input_none : public input_module
|
||||
{
|
||||
public:
|
||||
mouse_input_none()
|
||||
: input_module(OSD_MOUSEINPUT_PROVIDER, "none") {}
|
||||
int init(const osd_options &options) override { return 0; }
|
||||
void input_init(running_machine &machine) override {};
|
||||
void poll_if_necessary(running_machine &machine) override {};
|
||||
void pause() override {};
|
||||
void resume() override {};
|
||||
};
|
||||
|
||||
MODULE_DEFINITION(MOUSE_NONE, mouse_input_none)
|
||||
|
||||
class lightgun_input_none : public input_module
|
||||
{
|
||||
public:
|
||||
lightgun_input_none()
|
||||
: input_module(OSD_LIGHTGUNINPUT_PROVIDER, "none") {}
|
||||
int init(const osd_options &options) override { return 0; }
|
||||
void input_init(running_machine &machine) override {};
|
||||
void poll_if_necessary(running_machine &machine) override {};
|
||||
void pause() override {};
|
||||
void resume() override {};
|
||||
};
|
||||
|
||||
MODULE_DEFINITION(LIGHTGUN_NONE, lightgun_input_none)
|
||||
|
||||
class joystick_input_none : public input_module
|
||||
{
|
||||
public:
|
||||
joystick_input_none()
|
||||
: input_module(OSD_JOYSTICKINPUT_PROVIDER, "none") {}
|
||||
int init(const osd_options &options) override { return 0; }
|
||||
void input_init(running_machine &machine) override {};
|
||||
void poll_if_necessary(running_machine &machine) override {};
|
||||
void pause() override {};
|
||||
void resume() override {};
|
||||
};
|
||||
|
||||
MODULE_DEFINITION(JOYSTICK_NONE, joystick_input_none)
|
649
src/osd/modules/input/input_rawinput.cpp
Normal file
649
src/osd/modules/input/input_rawinput.cpp
Normal file
@ -0,0 +1,649 @@
|
||||
// license:BSD-3-Clause
|
||||
// copyright-holders:Aaron Giles, Brad Hughes
|
||||
//============================================================
|
||||
//
|
||||
// input_rawinput.cpp - Windows RawInput input implementation
|
||||
//
|
||||
//============================================================
|
||||
|
||||
#include "input_module.h"
|
||||
#include "modules/osdmodule.h"
|
||||
|
||||
#if defined(OSD_WINDOWS)
|
||||
|
||||
// standard windows headers
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
#include <winioctl.h>
|
||||
#include <tchar.h>
|
||||
#undef interface
|
||||
|
||||
#include <mutex>
|
||||
|
||||
// MAME headers
|
||||
#include "emu.h"
|
||||
#include "osdepend.h"
|
||||
#include "ui/ui.h"
|
||||
#include "strconv.h"
|
||||
|
||||
// MAMEOS headers
|
||||
#include "winmain.h"
|
||||
#include "window.h"
|
||||
#include "../../windows/input.h"
|
||||
|
||||
#include "input_common.h"
|
||||
#include "input_windows.h"
|
||||
|
||||
//============================================================
|
||||
// MACROS
|
||||
//============================================================
|
||||
|
||||
#ifdef UNICODE
|
||||
#define UNICODE_SUFFIX "W"
|
||||
#else
|
||||
#define UNICODE_SUFFIX "A"
|
||||
#endif
|
||||
|
||||
// RawInput APIs
|
||||
typedef /*WINUSERAPI*/ INT(WINAPI *get_rawinput_device_list_ptr)(OUT PRAWINPUTDEVICELIST pRawInputDeviceList, IN OUT PINT puiNumDevices, IN UINT cbSize);
|
||||
typedef /*WINUSERAPI*/ INT(WINAPI *get_rawinput_data_ptr)(IN HRAWINPUT hRawInput, IN UINT uiCommand, OUT LPVOID pData, IN OUT PINT pcbSize, IN UINT cbSizeHeader);
|
||||
typedef /*WINUSERAPI*/ INT(WINAPI *get_rawinput_device_info_ptr)(IN HANDLE hDevice, IN UINT uiCommand, OUT LPVOID pData, IN OUT PINT pcbSize);
|
||||
typedef /*WINUSERAPI*/ BOOL(WINAPI *register_rawinput_devices_ptr)(IN PCRAWINPUTDEVICE pRawInputDevices, IN UINT uiNumDevices, IN UINT cbSize);
|
||||
|
||||
//============================================================
|
||||
// reg_query_string
|
||||
//============================================================
|
||||
|
||||
static TCHAR *reg_query_string(HKEY key, const TCHAR *path)
|
||||
{
|
||||
TCHAR *buffer;
|
||||
DWORD datalen;
|
||||
LONG result;
|
||||
|
||||
// first query to get the length
|
||||
result = RegQueryValueEx(key, path, NULL, NULL, NULL, &datalen);
|
||||
if (result != ERROR_SUCCESS)
|
||||
return NULL;
|
||||
|
||||
// allocate a buffer
|
||||
buffer = global_alloc_array(TCHAR, datalen + sizeof(*buffer));
|
||||
buffer[datalen / sizeof(*buffer)] = 0;
|
||||
|
||||
// now get the actual data
|
||||
result = RegQueryValueEx(key, path, NULL, NULL, (LPBYTE)buffer, &datalen);
|
||||
if (result == ERROR_SUCCESS)
|
||||
return buffer;
|
||||
|
||||
// otherwise return a NULL buffer
|
||||
global_free_array(buffer);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
//============================================================
|
||||
// rawinput_device_improve_name
|
||||
//============================================================
|
||||
|
||||
static TCHAR *rawinput_device_improve_name(TCHAR *name)
|
||||
{
|
||||
static const TCHAR usbbasepath[] = TEXT("SYSTEM\\CurrentControlSet\\Enum\\USB");
|
||||
static const TCHAR basepath[] = TEXT("SYSTEM\\CurrentControlSet\\Enum\\");
|
||||
TCHAR *regstring = NULL;
|
||||
TCHAR *parentid = NULL;
|
||||
TCHAR *regpath = NULL;
|
||||
const TCHAR *chsrc;
|
||||
HKEY regkey = NULL;
|
||||
int usbindex;
|
||||
TCHAR *chdst;
|
||||
LONG result;
|
||||
|
||||
// The RAW name received is formatted as:
|
||||
// \??\type-id#hardware-id#instance-id#{DeviceClasses-id}
|
||||
// XP starts with "\??\"
|
||||
// Vista64 starts with "\\?\"
|
||||
|
||||
// ensure the name is something we can handle
|
||||
if (_tcsncmp(name, TEXT("\\\\?\\"), 4) != 0 && _tcsncmp(name, TEXT("\\??\\"), 4) != 0)
|
||||
return name;
|
||||
|
||||
// allocate a temporary string and concatenate the base path plus the name
|
||||
regpath = global_alloc_array(TCHAR, _tcslen(basepath) + 1 + _tcslen(name));
|
||||
_tcscpy(regpath, basepath);
|
||||
chdst = regpath + _tcslen(regpath);
|
||||
|
||||
// convert all # to \ in the name
|
||||
for (chsrc = name + 4; *chsrc != 0; chsrc++)
|
||||
*chdst++ = (*chsrc == '#') ? '\\' : *chsrc;
|
||||
*chdst = 0;
|
||||
|
||||
// remove the final chunk
|
||||
chdst = _tcsrchr(regpath, '\\');
|
||||
if (chdst == NULL)
|
||||
goto exit;
|
||||
*chdst = 0;
|
||||
|
||||
// now try to open the registry key
|
||||
result = RegOpenKeyEx(HKEY_LOCAL_MACHINE, regpath, 0, KEY_READ, ®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<RAWINPUT>
|
||||
{
|
||||
private:
|
||||
HANDLE m_handle;
|
||||
|
||||
public:
|
||||
rawinput_device(running_machine& machine, const char* name, input_device_class deviceclass, input_module& module)
|
||||
: event_based_device(machine, name, deviceclass, module)
|
||||
{
|
||||
}
|
||||
|
||||
HANDLE device_handle() { return m_handle; }
|
||||
void set_handle(HANDLE handle) { m_handle = handle; }
|
||||
};
|
||||
|
||||
//============================================================
|
||||
// rawinput_keyboard_device
|
||||
//============================================================
|
||||
|
||||
class rawinput_keyboard_device : public rawinput_device
|
||||
{
|
||||
public:
|
||||
keyboard_state keyboard;
|
||||
|
||||
rawinput_keyboard_device(running_machine& machine, const char* name, input_module& module)
|
||||
: rawinput_device(machine, name, DEVICE_CLASS_KEYBOARD, module),
|
||||
keyboard({0})
|
||||
{
|
||||
}
|
||||
|
||||
void reset() override
|
||||
{
|
||||
memset(&keyboard, 0, sizeof(keyboard));
|
||||
}
|
||||
|
||||
void process_event(RAWINPUT &rawinput) override
|
||||
{
|
||||
// determine the full DIK-compatible scancode
|
||||
UINT8 scancode = (rawinput.data.keyboard.MakeCode & 0x7f) | ((rawinput.data.keyboard.Flags & RI_KEY_E0) ? 0x80 : 0x00);
|
||||
|
||||
// scancode 0xaa is a special shift code we need to ignore
|
||||
if (scancode == 0xaa)
|
||||
return;
|
||||
|
||||
// set or clear the key
|
||||
keyboard.state[scancode] = (rawinput.data.keyboard.Flags & RI_KEY_BREAK) ? 0x00 : 0x80;
|
||||
}
|
||||
};
|
||||
|
||||
//============================================================
|
||||
// rawinput_mouse_device
|
||||
//============================================================
|
||||
|
||||
struct rawinput_mouse_state
|
||||
{
|
||||
int raw_x;
|
||||
int raw_y;
|
||||
int raw_z;
|
||||
};
|
||||
|
||||
class rawinput_mouse_device : public rawinput_device
|
||||
{
|
||||
private:
|
||||
std::mutex m_device_lock;
|
||||
public:
|
||||
//rawinput_mouse_state raw_mouse;
|
||||
mouse_state mouse;
|
||||
|
||||
rawinput_mouse_device(running_machine& machine, const char* name, input_module& module)
|
||||
: rawinput_device(machine, name, DEVICE_CLASS_MOUSE, module),
|
||||
mouse({0})
|
||||
{
|
||||
}
|
||||
|
||||
void poll() override
|
||||
{
|
||||
mouse.lX = 0;
|
||||
mouse.lY = 0;
|
||||
mouse.lZ = 0;
|
||||
|
||||
rawinput_device::poll();
|
||||
|
||||
//std::lock_guard<std::mutex> scope_lock(m_device_lock);
|
||||
|
||||
//// copy the accumulated raw state to the actual state
|
||||
//mouse.lX = raw_mouse.raw_x;
|
||||
//mouse.lY = raw_mouse.raw_y;
|
||||
//mouse.lZ = raw_mouse.raw_z;
|
||||
//raw_mouse.raw_x = 0;
|
||||
//raw_mouse.raw_y = 0;
|
||||
//raw_mouse.raw_z = 0;
|
||||
|
||||
//osd_printf_verbose("At poll: lX=%d, lY=%d, lZ=%d\n", (int)mouse.lX, (int)mouse.lY, (int)mouse.lZ);
|
||||
}
|
||||
|
||||
void reset() override
|
||||
{
|
||||
memset(&mouse, 0, sizeof(mouse));
|
||||
}
|
||||
|
||||
void process_event(RAWINPUT &rawinput) override
|
||||
{
|
||||
// If this data was intended for a rawinput lightgun, ignore it.
|
||||
if (rawinput.data.mouse.usFlags & MOUSE_MOVE_ABSOLUTE)
|
||||
return;
|
||||
|
||||
mouse.lX += rawinput.data.mouse.lLastX * INPUT_RELATIVE_PER_PIXEL;
|
||||
mouse.lY += rawinput.data.mouse.lLastY * INPUT_RELATIVE_PER_PIXEL;
|
||||
|
||||
/*osd_printf_verbose(
|
||||
"Mouse Abs : lastX = %d, lastY = %d, rawx = %d, rawy = %d\n",
|
||||
(int)rawinput.data.mouse.lLastX,
|
||||
(int)rawinput.data.mouse.lLastY,
|
||||
(int)raw_mouse.raw_x,
|
||||
(int)raw_mouse.raw_y);*/
|
||||
|
||||
// update zaxis
|
||||
if (rawinput.data.mouse.usButtonFlags & RI_MOUSE_WHEEL)
|
||||
mouse.lZ += (INT16)rawinput.data.mouse.usButtonData * INPUT_RELATIVE_PER_PIXEL;
|
||||
|
||||
// update the button states; always update the corresponding mouse buttons
|
||||
if (rawinput.data.mouse.usButtonFlags & RI_MOUSE_BUTTON_1_DOWN) mouse.rgbButtons[0] = 0x80;
|
||||
if (rawinput.data.mouse.usButtonFlags & RI_MOUSE_BUTTON_1_UP) mouse.rgbButtons[0] = 0x00;
|
||||
if (rawinput.data.mouse.usButtonFlags & RI_MOUSE_BUTTON_2_DOWN) mouse.rgbButtons[1] = 0x80;
|
||||
if (rawinput.data.mouse.usButtonFlags & RI_MOUSE_BUTTON_2_UP) mouse.rgbButtons[1] = 0x00;
|
||||
if (rawinput.data.mouse.usButtonFlags & RI_MOUSE_BUTTON_3_DOWN) mouse.rgbButtons[2] = 0x80;
|
||||
if (rawinput.data.mouse.usButtonFlags & RI_MOUSE_BUTTON_3_UP) mouse.rgbButtons[2] = 0x00;
|
||||
if (rawinput.data.mouse.usButtonFlags & RI_MOUSE_BUTTON_4_DOWN) mouse.rgbButtons[3] = 0x80;
|
||||
if (rawinput.data.mouse.usButtonFlags & RI_MOUSE_BUTTON_4_UP) mouse.rgbButtons[3] = 0x00;
|
||||
if (rawinput.data.mouse.usButtonFlags & RI_MOUSE_BUTTON_5_DOWN) mouse.rgbButtons[4] = 0x80;
|
||||
if (rawinput.data.mouse.usButtonFlags & RI_MOUSE_BUTTON_5_UP) mouse.rgbButtons[4] = 0x00;
|
||||
}
|
||||
};
|
||||
|
||||
//============================================================
|
||||
// rawinput_module - base class for rawinput modules
|
||||
//============================================================
|
||||
|
||||
class rawinput_module : public wininput_module
|
||||
{
|
||||
private:
|
||||
// RawInput variables
|
||||
get_rawinput_device_list_ptr get_rawinput_device_list;
|
||||
get_rawinput_data_ptr get_rawinput_data;
|
||||
get_rawinput_device_info_ptr get_rawinput_device_info;
|
||||
register_rawinput_devices_ptr register_rawinput_devices;
|
||||
std::mutex m_module_lock;
|
||||
|
||||
public:
|
||||
rawinput_module(const char *type, const char* name)
|
||||
: wininput_module(type, name),
|
||||
get_rawinput_device_list(nullptr),
|
||||
get_rawinput_data(nullptr),
|
||||
get_rawinput_device_info(nullptr),
|
||||
register_rawinput_devices(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
void input_init(running_machine &machine) override
|
||||
{
|
||||
// get the number of devices, allocate a device list, and fetch it
|
||||
int device_count = 0;
|
||||
if ((*get_rawinput_device_list)(NULL, &device_count, sizeof(RAWINPUTDEVICELIST)) != 0)
|
||||
return;
|
||||
|
||||
if (device_count == 0)
|
||||
return;
|
||||
|
||||
auto rawinput_devices = std::make_unique<RAWINPUTDEVICELIST[]>(device_count);
|
||||
if ((*get_rawinput_device_list)(rawinput_devices.get(), &device_count, sizeof(RAWINPUTDEVICELIST)) == -1)
|
||||
return;
|
||||
|
||||
// iterate backwards through devices; new devices are added at the head
|
||||
for (int devnum = device_count - 1; devnum >= 0; devnum--)
|
||||
{
|
||||
RAWINPUTDEVICELIST *device = &rawinput_devices[devnum];
|
||||
add_rawinput_device(machine, device);
|
||||
}
|
||||
|
||||
// don't enable global inputs when debugging
|
||||
if (!machine.options().debug())
|
||||
{
|
||||
m_global_inputs_enabled = downcast<windows_options &>(machine.options()).global_inputs();
|
||||
}
|
||||
|
||||
// If we added no devices, no need to register for notifications
|
||||
if (devicelist()->size() == 0)
|
||||
return;
|
||||
|
||||
// finally, register to receive raw input WM_INPUT messages if we found devices
|
||||
RAWINPUTDEVICE registration;
|
||||
registration.usUsagePage = usagepage();
|
||||
registration.usUsage = usage();
|
||||
registration.dwFlags = m_global_inputs_enabled ? 0x00000100 : 0;
|
||||
registration.hwndTarget = win_window_list->m_hwnd;
|
||||
|
||||
// register the device
|
||||
(*register_rawinput_devices)(®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<class TDevice>
|
||||
TDevice* create_rawinput_device(running_machine &machine, PRAWINPUTDEVICELIST rawinputdevice)
|
||||
{
|
||||
TDevice* devinfo = nullptr;
|
||||
INT name_length = 0;
|
||||
// determine the length of the device name, allocate it, and fetch it if not nameless
|
||||
if ((*get_rawinput_device_info)(rawinputdevice->hDevice, RIDI_DEVICENAME, NULL, &name_length) != 0)
|
||||
return nullptr;
|
||||
|
||||
std::unique_ptr<TCHAR[]> tname = std::make_unique<TCHAR[]>(name_length + 1);
|
||||
if (name_length > 1 && (*get_rawinput_device_info)(rawinputdevice->hDevice, RIDI_DEVICENAME, tname.get(), &name_length) == -1)
|
||||
return nullptr;
|
||||
|
||||
// if this is an RDP name, skip it
|
||||
if (_tcsstr(tname.get(), TEXT("Root#RDP_")) != NULL)
|
||||
return nullptr;
|
||||
|
||||
// improve the name and then allocate a device
|
||||
tname = std::unique_ptr<TCHAR[]>(rawinput_device_improve_name(tname.release()));
|
||||
|
||||
// convert name to utf8
|
||||
auto osd_deleter = [](void *ptr) { osd_free(ptr); };
|
||||
auto utf8_name = std::unique_ptr<char, decltype(osd_deleter)>(utf8_from_tstring(tname.get()), osd_deleter);
|
||||
|
||||
devinfo = devicelist()->create_device<TDevice>(machine, utf8_name.get(), *this);
|
||||
|
||||
// Add the handle
|
||||
devinfo->set_handle(rawinputdevice->hDevice);
|
||||
|
||||
return devinfo;
|
||||
}
|
||||
|
||||
bool handle_input_event(input_event eventid, void* eventdata) override
|
||||
{
|
||||
// Only handle raw input data
|
||||
if (!input_enabled() || eventid != INPUT_EVENT_RAWINPUT)
|
||||
return FALSE;
|
||||
|
||||
HRAWINPUT rawinputdevice = *(HRAWINPUT*)eventdata;
|
||||
|
||||
BYTE small_buffer[4096];
|
||||
std::unique_ptr<BYTE[]> larger_buffer;
|
||||
LPBYTE data = small_buffer;
|
||||
BOOL result = FALSE;
|
||||
int size;
|
||||
|
||||
// ignore if not enabled
|
||||
if (!input_enabled())
|
||||
return FALSE;
|
||||
|
||||
// determine the size of databuffer we need
|
||||
if ((*get_rawinput_data)(rawinputdevice, RID_INPUT, NULL, &size, sizeof(RAWINPUTHEADER)) != 0)
|
||||
return FALSE;
|
||||
|
||||
// if necessary, allocate a temporary buffer and fetch the data
|
||||
if (size > sizeof(small_buffer))
|
||||
{
|
||||
larger_buffer = std::make_unique<BYTE[]>(size);
|
||||
data = larger_buffer.get();
|
||||
if (data == NULL)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// fetch the data and process the appropriate message types
|
||||
result = (*get_rawinput_data)((HRAWINPUT)rawinputdevice, RID_INPUT, data, &size, sizeof(RAWINPUTHEADER));
|
||||
if (result)
|
||||
{
|
||||
std::lock_guard<std::mutex> scope_lock(m_module_lock);
|
||||
|
||||
rawinput_device *devinfo;
|
||||
// find the device in the list and update
|
||||
for (int i = 0; i < devicelist()->size(); i++)
|
||||
{
|
||||
devinfo = dynamic_cast<rawinput_device*>(devicelist()->at(i));
|
||||
RAWINPUT *input = reinterpret_cast<RAWINPUT*>(data);
|
||||
if (input->header.hDevice == devinfo->device_handle())
|
||||
{
|
||||
devinfo->queue_events(input, 1);
|
||||
result = TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
//============================================================
|
||||
// keyboard_input_rawinput - rawinput keyboard module
|
||||
//============================================================
|
||||
|
||||
class keyboard_input_rawinput : public rawinput_module
|
||||
{
|
||||
public:
|
||||
keyboard_input_rawinput()
|
||||
: rawinput_module(OSD_KEYBOARDINPUT_PROVIDER, "rawinput")
|
||||
{
|
||||
}
|
||||
|
||||
protected:
|
||||
USHORT usagepage() { return 1; }
|
||||
USHORT usage() { return 6; }
|
||||
void add_rawinput_device(running_machine& machine, RAWINPUTDEVICELIST * device) override
|
||||
{
|
||||
// make sure this is a keyboard
|
||||
if (device->dwType != RIM_TYPEKEYBOARD)
|
||||
return;
|
||||
|
||||
// allocate and link in a new device
|
||||
rawinput_keyboard_device *devinfo = create_rawinput_device<rawinput_keyboard_device>(machine, device);
|
||||
if (devinfo == NULL)
|
||||
return;
|
||||
|
||||
keyboard_trans_table &table = keyboard_trans_table::instance();
|
||||
|
||||
// populate it
|
||||
for (int keynum = 0; keynum < MAX_KEYS; keynum++)
|
||||
{
|
||||
input_item_id itemid = table.map_di_scancode_to_itemid(keynum);
|
||||
TCHAR keyname[100];
|
||||
char *name;
|
||||
|
||||
// generate the name
|
||||
if (GetKeyNameText(((keynum & 0x7f) << 16) | ((keynum & 0x80) << 17), keyname, ARRAY_LENGTH(keyname)) == 0)
|
||||
_sntprintf(keyname, ARRAY_LENGTH(keyname), TEXT("Scan%03d"), keynum);
|
||||
name = utf8_from_tstring(keyname);
|
||||
|
||||
// add the item to the device
|
||||
devinfo->device()->add_item(name, itemid, generic_button_get_state, &devinfo->keyboard.state[keynum]);
|
||||
osd_free(name);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
//============================================================
|
||||
// mouse_input_rawinput - rawinput mouse module
|
||||
//============================================================
|
||||
|
||||
class mouse_input_rawinput : public rawinput_module
|
||||
{
|
||||
public:
|
||||
mouse_input_rawinput()
|
||||
: rawinput_module(OSD_MOUSEINPUT_PROVIDER, "rawinput")
|
||||
{
|
||||
}
|
||||
|
||||
protected:
|
||||
USHORT usagepage() { return 1; }
|
||||
USHORT usage() { return 2; }
|
||||
void add_rawinput_device(running_machine& machine, RAWINPUTDEVICELIST * device) override
|
||||
{
|
||||
// make sure this is a mouse
|
||||
if (device->dwType != RIM_TYPEMOUSE)
|
||||
return;
|
||||
|
||||
// allocate and link in a new device
|
||||
rawinput_mouse_device *devinfo = create_rawinput_device<rawinput_mouse_device>(machine, device);
|
||||
if (devinfo == NULL)
|
||||
return;
|
||||
|
||||
// populate the axes
|
||||
for (int axisnum = 0; axisnum < 3; axisnum++)
|
||||
{
|
||||
devinfo->device()->add_item(default_axis_name[axisnum], (input_item_id)(ITEM_ID_XAXIS + axisnum), generic_axis_get_state, &devinfo->mouse.lX + axisnum);
|
||||
}
|
||||
|
||||
// populate the buttons
|
||||
for (int butnum = 0; butnum < 5; butnum++)
|
||||
{
|
||||
devinfo->device()->add_item(default_button_name(butnum), (input_item_id)(ITEM_ID_BUTTON1 + butnum), generic_button_get_state, &devinfo->mouse.rgbButtons[butnum]);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
#else
|
||||
MODULE_NOT_SUPPORTED(keyboard_input_rawinput, OSD_KEYBOARDINPUT_PROVIDER, "rawinput")
|
||||
MODULE_NOT_SUPPORTED(mouse_input_rawinput, OSD_MOUSEINPUT_PROVIDER, "rawinput")
|
||||
//MODULE_NOT_SUPPORTED(lightgun_input_rawinput, OSD_LIGHTGUNINPUT_PROVIDER, "rawinput")
|
||||
#endif
|
||||
|
||||
MODULE_DEFINITION(KEYBOARDINPUT_RAWINPUT, keyboard_input_rawinput)
|
||||
MODULE_DEFINITION(MOUSEINPUT_RAWINPUT, mouse_input_rawinput)
|
||||
//MODULE_DEFINITION(LIGHTGUNINPUT_RAWINPUT, lightgun_input_rawinput)
|
843
src/osd/modules/input/input_sdl.cpp
Normal file
843
src/osd/modules/input/input_sdl.cpp
Normal file
@ -0,0 +1,843 @@
|
||||
// license:BSD-3-Clause
|
||||
// copyright-holders:Olivier Galibert, R. Belmont, Brad Hughes
|
||||
//============================================================
|
||||
//
|
||||
// input_sdl.cpp - SDL 2.0 implementation of MAME input routines
|
||||
//
|
||||
// SDLMAME by Olivier Galibert and R. Belmont
|
||||
//
|
||||
// SixAxis info: left analog is axes 0 & 1, right analog is axes 2 & 3,
|
||||
// analog L2 is axis 12 and analog L3 is axis 13
|
||||
//
|
||||
//============================================================
|
||||
|
||||
#include "input_module.h"
|
||||
#include "modules/osdmodule.h"
|
||||
|
||||
#if defined(SDLMAME_SDL2)
|
||||
|
||||
// standard sdl header
|
||||
#include "sdlinc.h"
|
||||
#include <ctype.h>
|
||||
#include <stddef.h>
|
||||
#include <mutex>
|
||||
#include <memory>
|
||||
#include <queue>
|
||||
|
||||
// MAME headers
|
||||
#include "emu.h"
|
||||
#include "osdepend.h"
|
||||
#include "ui/ui.h"
|
||||
#include "uiinput.h"
|
||||
#include "strconv.h"
|
||||
|
||||
// MAMEOS headers
|
||||
#include "input_common.h"
|
||||
#include "../lib/osdobj_common.h"
|
||||
#include "input_sdlcommon.h"
|
||||
#include "../../sdl/osdsdl.h"
|
||||
#include "../../sdl/window.h"
|
||||
|
||||
// winnt.h defines this
|
||||
#ifdef DELETE
|
||||
#undef DELETE
|
||||
#endif
|
||||
|
||||
|
||||
// FIXME: sdl does not properly report the window for certain OS.
|
||||
#define GET_FOCUS_WINDOW(ev) focus_window()
|
||||
//#define GET_FOCUS_WINDOW(ev) window_from_id((ev)->windowID)
|
||||
|
||||
struct key_lookup_table
|
||||
{
|
||||
int code;
|
||||
const char *name;
|
||||
};
|
||||
|
||||
#define KE(x) { SDL_SCANCODE_ ## x, "SDL_SCANCODE_" #x },
|
||||
#define KE8(A, B, C, D, E, F, G, H) KE(A) KE(B) KE(C) KE(D) KE(E) KE(F) KE(G) KE(H)
|
||||
#define KE7(A, B, C, D, E, F, G) KE(A) KE(B) KE(C) KE(D) KE(E) KE(F) KE(G)
|
||||
#define KE5(A, B, C, D, E) KE(A) KE(B) KE(C) KE(D) KE(E)
|
||||
#define KE3(A, B, C) KE(A) KE(B) KE(C)
|
||||
|
||||
static key_lookup_table sdl_lookup_table[] =
|
||||
{
|
||||
KE7(UNKNOWN, BACKSPACE, TAB, CLEAR, RETURN, PAUSE, ESCAPE)
|
||||
KE(SPACE)
|
||||
KE5(COMMA, MINUS, PERIOD, SLASH, 0)
|
||||
KE8(1, 2, 3, 4, 5, 6, 7, 8)
|
||||
KE3(9, SEMICOLON, EQUALS)
|
||||
KE5(LEFTBRACKET,BACKSLASH, RIGHTBRACKET, A, B)
|
||||
KE8(C, D, E, F, G, H, I, J)
|
||||
KE8(K, L, M, N, O, P, Q, R)
|
||||
KE8(S, T, U, V, W, X, Y, Z)
|
||||
KE8(DELETE, KP_0, KP_1, KP_2, KP_3, KP_4, KP_5, KP_6)
|
||||
KE8(KP_7, KP_8, KP_9, KP_PERIOD, KP_DIVIDE, KP_MULTIPLY,KP_MINUS, KP_PLUS)
|
||||
KE8(KP_ENTER, KP_EQUALS, UP, DOWN, RIGHT, LEFT, INSERT, HOME)
|
||||
KE8(END, PAGEUP, PAGEDOWN, F1, F2, F3, F4, F5)
|
||||
KE8(F6, F7, F8, F9, F10, F11, F12, F13)
|
||||
KE8(F14, F15, NUMLOCKCLEAR, CAPSLOCK, SCROLLLOCK, RSHIFT, LSHIFT, RCTRL)
|
||||
KE5(LCTRL, RALT, LALT, LGUI, RGUI)
|
||||
KE8(GRAVE, LEFTBRACKET,RIGHTBRACKET, SEMICOLON, APOSTROPHE, BACKSLASH, PRINTSCREEN,MENU)
|
||||
KE(UNDO)
|
||||
{
|
||||
-1, ""
|
||||
}
|
||||
};
|
||||
|
||||
//============================================================
|
||||
// lookup_sdl_code
|
||||
//============================================================
|
||||
|
||||
static int lookup_sdl_code(const char *scode)
|
||||
{
|
||||
int i = 0;
|
||||
|
||||
while (sdl_lookup_table[i].code >= 0)
|
||||
{
|
||||
if (!strcmp(scode, sdl_lookup_table[i].name))
|
||||
return sdl_lookup_table[i].code;
|
||||
i++;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
//============================================================
|
||||
// sdl_device
|
||||
//============================================================
|
||||
|
||||
class sdl_device : public event_based_device<SDL_Event>
|
||||
{
|
||||
public:
|
||||
sdl_device(running_machine &machine, const char* name, input_device_class devclass, input_module &module)
|
||||
: event_based_device(machine, name, devclass, module)
|
||||
{
|
||||
}
|
||||
|
||||
protected:
|
||||
sdl_window_info * focus_window()
|
||||
{
|
||||
return sdl_event_manager::instance().focus_window();
|
||||
}
|
||||
};
|
||||
|
||||
//============================================================
|
||||
// sdl_keyboard_device
|
||||
//============================================================
|
||||
|
||||
#define OSD_SDL_INDEX_KEYSYM(keysym) ((keysym)->scancode)
|
||||
class sdl_keyboard_device : public sdl_device
|
||||
{
|
||||
public:
|
||||
keyboard_state keyboard;
|
||||
|
||||
sdl_keyboard_device(running_machine &machine, const char* name, input_module &module)
|
||||
: sdl_device(machine, name, DEVICE_CLASS_KEYBOARD, module),
|
||||
keyboard({{0}})
|
||||
{
|
||||
}
|
||||
|
||||
void process_event(SDL_Event &sdlevent) override
|
||||
{
|
||||
switch (sdlevent.type)
|
||||
{
|
||||
case SDL_KEYDOWN:
|
||||
keyboard.state[OSD_SDL_INDEX_KEYSYM(&sdlevent.key.keysym)] = 0x80;
|
||||
if (sdlevent.key.keysym.sym < 0x20)
|
||||
machine().ui_input().push_char_event(sdl_window_list->target(), sdlevent.key.keysym.sym);
|
||||
break;
|
||||
|
||||
case SDL_KEYUP:
|
||||
keyboard.state[OSD_SDL_INDEX_KEYSYM(&sdlevent.key.keysym)] = 0x00;
|
||||
break;
|
||||
|
||||
case SDL_TEXTINPUT:
|
||||
if (*sdlevent.text.text)
|
||||
{
|
||||
sdl_window_info *window = GET_FOCUS_WINDOW(&event.text);
|
||||
//printf("Focus window is %p - wl %p\n", window, sdl_window_list);
|
||||
unicode_char result;
|
||||
if (window != NULL)
|
||||
{
|
||||
osd_uchar_from_osdchar(&result, sdlevent.text.text, 1);
|
||||
machine().ui_input().push_char_event(window->target(), result);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void reset() override
|
||||
{
|
||||
memset(&keyboard.state, 0, sizeof(keyboard.state));
|
||||
}
|
||||
};
|
||||
|
||||
//============================================================
|
||||
// sdl_mouse_device
|
||||
//============================================================
|
||||
|
||||
class sdl_mouse_device : public sdl_device
|
||||
{
|
||||
public:
|
||||
mouse_state mouse;
|
||||
|
||||
sdl_mouse_device(running_machine &machine, const char* name, input_module &module)
|
||||
: sdl_device(machine, name, DEVICE_CLASS_MOUSE, module),
|
||||
mouse({0})
|
||||
{
|
||||
}
|
||||
|
||||
void reset() override
|
||||
{
|
||||
memset(&mouse, 0, sizeof(mouse));
|
||||
}
|
||||
|
||||
void poll() override
|
||||
{
|
||||
mouse.lX = 0;
|
||||
mouse.lY = 0;
|
||||
sdl_device::poll();
|
||||
}
|
||||
|
||||
virtual void process_event(SDL_Event &sdlevent) override
|
||||
{
|
||||
switch (sdlevent.type)
|
||||
{
|
||||
case SDL_MOUSEMOTION:
|
||||
mouse.lX += sdlevent.motion.xrel * INPUT_RELATIVE_PER_PIXEL;
|
||||
mouse.lY += sdlevent.motion.yrel * INPUT_RELATIVE_PER_PIXEL;
|
||||
|
||||
{
|
||||
int cx = -1, cy = -1;
|
||||
sdl_window_info *window = GET_FOCUS_WINDOW(&sdlevent.motion);
|
||||
|
||||
if (window != NULL && window->xy_to_render_target(sdlevent.motion.x, sdlevent.motion.y, &cx, &cy))
|
||||
machine().ui_input().push_mouse_move_event(window->target(), cx, cy);
|
||||
}
|
||||
break;
|
||||
|
||||
case SDL_MOUSEBUTTONDOWN:
|
||||
mouse.buttons[sdlevent.button.button - 1] = 0x80;
|
||||
//printf("But down %d %d %d %d %s\n", event.button.which, event.button.button, event.button.x, event.button.y, devinfo->name.c_str());
|
||||
if (sdlevent.button.button == 1)
|
||||
{
|
||||
// FIXME Move static declaration
|
||||
static osd_ticks_t last_click = 0;
|
||||
static int last_x = 0;
|
||||
static int last_y = 0;
|
||||
int cx, cy;
|
||||
osd_ticks_t click = osd_ticks() * 1000 / osd_ticks_per_second();
|
||||
sdl_window_info *window = GET_FOCUS_WINDOW(&sdlevent.button);
|
||||
if (window != NULL && window->xy_to_render_target(sdlevent.button.x, sdlevent.button.y, &cx, &cy))
|
||||
{
|
||||
machine().ui_input().push_mouse_down_event(window->target(), cx, cy);
|
||||
// FIXME Parameter ?
|
||||
if ((click - last_click < 250)
|
||||
&& (cx >= last_x - 4 && cx <= last_x + 4)
|
||||
&& (cy >= last_y - 4 && cy <= last_y + 4))
|
||||
{
|
||||
last_click = 0;
|
||||
machine().ui_input().push_mouse_double_click_event(window->target(), cx, cy);
|
||||
}
|
||||
else
|
||||
{
|
||||
last_click = click;
|
||||
last_x = cx;
|
||||
last_y = cy;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case SDL_MOUSEBUTTONUP:
|
||||
mouse.buttons[sdlevent.button.button - 1] = 0;
|
||||
//printf("But up %d %d %d %d\n", event.button.which, event.button.button, event.button.x, event.button.y);
|
||||
|
||||
if (sdlevent.button.button == 1)
|
||||
{
|
||||
int cx, cy;
|
||||
sdl_window_info *window = GET_FOCUS_WINDOW(&sdlevent.button);
|
||||
|
||||
if (window != NULL && window->xy_to_render_target(sdlevent.button.x, sdlevent.button.y, &cx, &cy))
|
||||
{
|
||||
machine().ui_input().push_mouse_up_event(window->target(), cx, cy);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case SDL_MOUSEWHEEL:
|
||||
sdl_window_info *window = GET_FOCUS_WINDOW(&sdlevent.wheel);
|
||||
if (window != NULL)
|
||||
machine().ui_input().push_mouse_wheel_event(window->target(), 0, 0, sdlevent.wheel.y, 3);
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
//============================================================
|
||||
// sdl_joystick_device
|
||||
//============================================================
|
||||
|
||||
// state information for a joystick
|
||||
struct sdl_joystick_state
|
||||
{
|
||||
INT32 axes[MAX_AXES];
|
||||
INT32 buttons[MAX_BUTTONS];
|
||||
INT32 hatsU[MAX_HATS], hatsD[MAX_HATS], hatsL[MAX_HATS], hatsR[MAX_HATS];
|
||||
INT32 balls[MAX_AXES];
|
||||
};
|
||||
|
||||
struct sdl_api_state
|
||||
{
|
||||
SDL_Joystick *device;
|
||||
SDL_JoystickID joystick_id;
|
||||
};
|
||||
|
||||
class sdl_joystick_device : public sdl_device
|
||||
{
|
||||
public:
|
||||
sdl_joystick_state joystick;
|
||||
sdl_api_state sdl_state;
|
||||
|
||||
sdl_joystick_device(running_machine &machine, const char *name, input_module &module)
|
||||
: sdl_device(machine, name, DEVICE_CLASS_JOYSTICK, module),
|
||||
joystick({{0}}),
|
||||
sdl_state({0})
|
||||
{
|
||||
}
|
||||
|
||||
~sdl_joystick_device()
|
||||
{
|
||||
if (sdl_state.device != nullptr)
|
||||
{
|
||||
SDL_JoystickClose(sdl_state.device);
|
||||
sdl_state.device = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void reset() override
|
||||
{
|
||||
memset(&joystick, 0, sizeof(joystick));
|
||||
}
|
||||
|
||||
void process_event(SDL_Event &sdlevent) override
|
||||
{
|
||||
switch (sdlevent.type)
|
||||
{
|
||||
case SDL_JOYAXISMOTION:
|
||||
joystick.axes[sdlevent.jaxis.axis] = (sdlevent.jaxis.value * 2);
|
||||
break;
|
||||
|
||||
case SDL_JOYBALLMOTION:
|
||||
//printf("Ball %d %d\n", sdlevent.jball.xrel, sdlevent.jball.yrel);
|
||||
joystick.balls[sdlevent.jball.ball * 2] = sdlevent.jball.xrel * INPUT_RELATIVE_PER_PIXEL;
|
||||
joystick.balls[sdlevent.jball.ball * 2 + 1] = sdlevent.jball.yrel * INPUT_RELATIVE_PER_PIXEL;
|
||||
break;
|
||||
|
||||
case SDL_JOYHATMOTION:
|
||||
if (sdlevent.jhat.value & SDL_HAT_UP)
|
||||
{
|
||||
joystick.hatsU[sdlevent.jhat.hat] = 0x80;
|
||||
}
|
||||
else
|
||||
{
|
||||
joystick.hatsU[sdlevent.jhat.hat] = 0;
|
||||
}
|
||||
if (sdlevent.jhat.value & SDL_HAT_DOWN)
|
||||
{
|
||||
joystick.hatsD[sdlevent.jhat.hat] = 0x80;
|
||||
}
|
||||
else
|
||||
{
|
||||
joystick.hatsD[sdlevent.jhat.hat] = 0;
|
||||
}
|
||||
if (sdlevent.jhat.value & SDL_HAT_LEFT)
|
||||
{
|
||||
joystick.hatsL[sdlevent.jhat.hat] = 0x80;
|
||||
}
|
||||
else
|
||||
{
|
||||
joystick.hatsL[sdlevent.jhat.hat] = 0;
|
||||
}
|
||||
if (sdlevent.jhat.value & SDL_HAT_RIGHT)
|
||||
{
|
||||
joystick.hatsR[sdlevent.jhat.hat] = 0x80;
|
||||
}
|
||||
else
|
||||
{
|
||||
joystick.hatsR[sdlevent.jhat.hat] = 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case SDL_JOYBUTTONDOWN:
|
||||
case SDL_JOYBUTTONUP:
|
||||
joystick.buttons[sdlevent.jbutton.button] = (sdlevent.jbutton.state == SDL_PRESSED) ? 0x80 : 0;
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class sdl_sixaxis_joystick_device : public sdl_joystick_device
|
||||
{
|
||||
public:
|
||||
sdl_sixaxis_joystick_device(running_machine &machine, const char *name, input_module &module)
|
||||
: sdl_joystick_device(machine, name, module)
|
||||
{
|
||||
}
|
||||
|
||||
void process_event(SDL_Event &sdlevent) override
|
||||
{
|
||||
switch (sdlevent.type)
|
||||
{
|
||||
case SDL_JOYAXISMOTION:
|
||||
{
|
||||
int axis = sdlevent.jaxis.axis;
|
||||
|
||||
if (axis <= 3)
|
||||
{
|
||||
joystick.axes[sdlevent.jaxis.axis] = (sdlevent.jaxis.value * 2);
|
||||
}
|
||||
else
|
||||
{
|
||||
int magic = (sdlevent.jaxis.value / 2) + 16384;
|
||||
joystick.axes[sdlevent.jaxis.axis] = magic;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
// Call the base for other events
|
||||
sdl_joystick_device::process_event(sdlevent);
|
||||
break;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
//============================================================
|
||||
// sdl_input_module
|
||||
//============================================================
|
||||
|
||||
class sdl_input_module : public input_module_base, public sdl_event_subscriber
|
||||
{
|
||||
public:
|
||||
sdl_input_module(const char *type)
|
||||
: input_module_base(type, "sdl")
|
||||
{
|
||||
}
|
||||
|
||||
void input_init(running_machine &machine) override
|
||||
{
|
||||
if (machine.debug_flags & DEBUG_FLAG_OSD_ENABLED)
|
||||
{
|
||||
osd_printf_warning("Debug Build: Disabling input grab for -debug\n");
|
||||
set_mouse_enabled(false);
|
||||
}
|
||||
}
|
||||
|
||||
void before_poll(running_machine& machine) override
|
||||
{
|
||||
// Tell the event manager to process events and push them to the devices
|
||||
sdl_event_manager::instance().process_events(machine);
|
||||
}
|
||||
|
||||
bool should_poll_devices(running_machine& machine) override
|
||||
{
|
||||
return sdl_event_manager::instance().app_has_mouse_focus() && input_enabled();
|
||||
}
|
||||
|
||||
virtual void handle_event(SDL_Event &sdlevent) override
|
||||
{
|
||||
// By default dispatch event to every device
|
||||
for (int i = 0; i < devicelist()->size(); i++)
|
||||
downcast<sdl_device*>(devicelist()->at(i))->queue_events(&sdlevent, 1);
|
||||
}
|
||||
};
|
||||
|
||||
//============================================================
|
||||
// sdl_keyboard_module
|
||||
//============================================================
|
||||
|
||||
class sdl_keyboard_module : public sdl_input_module
|
||||
{
|
||||
keyboard_trans_table * m_key_trans_table;
|
||||
public:
|
||||
sdl_keyboard_module()
|
||||
: sdl_input_module(OSD_KEYBOARDINPUT_PROVIDER)
|
||||
{
|
||||
}
|
||||
|
||||
void input_init(running_machine &machine) override
|
||||
{
|
||||
sdl_input_module::input_init(machine);
|
||||
|
||||
SDL_EventType event_types[] = { SDL_KEYDOWN, SDL_KEYUP, SDL_TEXTINPUT };
|
||||
sdl_event_manager::instance().subscribe(reinterpret_cast<int*>(event_types), ARRAY_LENGTH(event_types), this);
|
||||
|
||||
sdl_keyboard_device *devinfo;
|
||||
|
||||
// Read our keymap and store a pointer to our table
|
||||
m_key_trans_table = sdlinput_read_keymap(machine);
|
||||
|
||||
keyboard_trans_table& local_table = *m_key_trans_table;
|
||||
|
||||
osd_printf_verbose("Keyboard: Start initialization\n");
|
||||
|
||||
// SDL only has 1 keyboard add it now
|
||||
devinfo = devicelist()->create_device<sdl_keyboard_device>(machine, "System keyboard", *this);
|
||||
|
||||
// populate it
|
||||
for (int keynum = 0; local_table[keynum].mame_key != ITEM_ID_INVALID; keynum++)
|
||||
{
|
||||
input_item_id itemid = local_table[keynum].mame_key;
|
||||
|
||||
// generate the default / modified name
|
||||
char defname[20];
|
||||
snprintf(defname, sizeof(defname) - 1, "%s", local_table[keynum].ui_name);
|
||||
|
||||
devinfo->device()->add_item(defname, itemid, generic_button_get_state, &devinfo->keyboard.state[local_table[keynum].sdl_scancode]);
|
||||
}
|
||||
|
||||
osd_printf_verbose("Keyboard: Registered %s\n", devinfo->name());
|
||||
osd_printf_verbose("Keyboard: End initialization\n");
|
||||
}
|
||||
|
||||
private:
|
||||
static keyboard_trans_table* sdlinput_read_keymap(running_machine &machine)
|
||||
{
|
||||
char *keymap_filename;
|
||||
FILE *keymap_file;
|
||||
int line = 1;
|
||||
int index, i, sk, vk, ak;
|
||||
char buf[256];
|
||||
char mks[41];
|
||||
char sks[41];
|
||||
char kns[41];
|
||||
int sdl2section = 0;
|
||||
|
||||
keyboard_trans_table &default_table = keyboard_trans_table::instance();
|
||||
|
||||
if (!machine.options().bool_value(SDLOPTION_KEYMAP))
|
||||
return &default_table;
|
||||
|
||||
keymap_filename = (char *)downcast<sdl_options &>(machine.options()).keymap_file();
|
||||
osd_printf_verbose("Keymap: Start reading keymap_file %s\n", keymap_filename);
|
||||
|
||||
keymap_file = fopen(keymap_filename, "r");
|
||||
if (keymap_file == NULL)
|
||||
{
|
||||
osd_printf_warning("Keymap: Unable to open keymap %s, using default\n", keymap_filename);
|
||||
return &default_table;
|
||||
}
|
||||
|
||||
// Allocate a block of translation entries big enough to hold what's in the default table
|
||||
auto key_trans_entries = std::make_unique<key_trans_entry[]>(default_table.size());
|
||||
|
||||
// copy the elements from the default table
|
||||
for (int i = 0; i < default_table.size(); i++)
|
||||
key_trans_entries[i] = default_table[i];
|
||||
|
||||
// Allocate the trans table to be associated with the machine so we don't have to free it
|
||||
keyboard_trans_table *custom_table = auto_alloc(machine, keyboard_trans_table(std::move(key_trans_entries), default_table.size()));
|
||||
|
||||
while (!feof(keymap_file))
|
||||
{
|
||||
char *ret = fgets(buf, 255, keymap_file);
|
||||
if (ret && buf[0] != '\n' && buf[0] != '#')
|
||||
{
|
||||
buf[255] = 0;
|
||||
i = strlen(buf);
|
||||
if (i && buf[i - 1] == '\n')
|
||||
buf[i - 1] = 0;
|
||||
if (strncmp(buf, "[SDL2]", 6) == 0)
|
||||
{
|
||||
sdl2section = 1;
|
||||
}
|
||||
else if (((SDLMAME_SDL2) ^ sdl2section) == 0)
|
||||
{
|
||||
mks[0] = 0;
|
||||
sks[0] = 0;
|
||||
memset(kns, 0, ARRAY_LENGTH(kns));
|
||||
sscanf(buf, "%40s %40s %x %x %40c\n",
|
||||
mks, sks, &vk, &ak, kns);
|
||||
|
||||
index = default_table.lookup_mame_index(mks);
|
||||
sk = lookup_sdl_code(sks);
|
||||
|
||||
if (sk >= 0 && index >= 0)
|
||||
{
|
||||
key_trans_entry &entry = (*custom_table)[index];
|
||||
entry.sdl_key = sk;
|
||||
// vk and ak are not really needed
|
||||
//key_trans_table[index][VIRTUAL_KEY] = vk;
|
||||
//key_trans_table[index][ASCII_KEY] = ak;
|
||||
entry.ui_name = auto_alloc_array(machine, char, strlen(kns) + 1);
|
||||
strcpy(entry.ui_name, kns);
|
||||
osd_printf_verbose("Keymap: Mapped <%s> to <%s> with ui-text <%s>\n", sks, mks, kns);
|
||||
}
|
||||
else
|
||||
osd_printf_warning("Keymap: Error on line %d - %s key not found: %s\n", line, (sk<0) ? "sdl" : "mame", buf);
|
||||
}
|
||||
}
|
||||
line++;
|
||||
}
|
||||
fclose(keymap_file);
|
||||
osd_printf_verbose("Keymap: Processed %d lines\n", line);
|
||||
|
||||
return custom_table;
|
||||
}
|
||||
};
|
||||
|
||||
//============================================================
|
||||
// sdl_mouse_module
|
||||
//============================================================
|
||||
|
||||
class sdl_mouse_module : public sdl_input_module
|
||||
{
|
||||
public:
|
||||
sdl_mouse_module()
|
||||
: sdl_input_module(OSD_MOUSEINPUT_PROVIDER)
|
||||
{
|
||||
}
|
||||
|
||||
virtual void input_init(running_machine &machine) override
|
||||
{
|
||||
sdl_input_module::input_init(machine);
|
||||
|
||||
SDL_EventType event_types[] = { SDL_MOUSEMOTION, SDL_MOUSEBUTTONDOWN, SDL_MOUSEBUTTONUP, SDL_MOUSEWHEEL };
|
||||
sdl_event_manager::instance().subscribe(reinterpret_cast<int*>(event_types), ARRAY_LENGTH(event_types), this);
|
||||
|
||||
sdl_mouse_device *devinfo;
|
||||
char defname[20];
|
||||
int button;
|
||||
|
||||
osd_printf_verbose("Mouse: Start initialization\n");
|
||||
|
||||
// SDL currently only supports one mouse
|
||||
devinfo = devicelist()->create_device<sdl_mouse_device>(machine, "System mouse", *this);
|
||||
|
||||
// add the axes
|
||||
devinfo->device()->add_item("X", ITEM_ID_XAXIS, generic_axis_get_state, &devinfo->mouse.lX);
|
||||
devinfo->device()->add_item("Y", ITEM_ID_YAXIS, generic_axis_get_state, &devinfo->mouse.lY);
|
||||
|
||||
for (button = 0; button < 4; button++)
|
||||
{
|
||||
input_item_id itemid = (input_item_id)(ITEM_ID_BUTTON1 + button);
|
||||
snprintf(defname, sizeof(defname), "B%d", button + 1);
|
||||
|
||||
devinfo->device()->add_item(defname, itemid, generic_button_get_state, &devinfo->mouse.buttons[button]);
|
||||
}
|
||||
|
||||
osd_printf_verbose("Mouse: Registered %s\n", devinfo->name());
|
||||
osd_printf_verbose("Mouse: End initialization\n");
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
static void devmap_register(device_map_t *devmap, int physical_idx, const std::string &name)
|
||||
{
|
||||
int found = 0;
|
||||
int stick, i;
|
||||
|
||||
for (i = 0; i < MAX_DEVMAP_ENTRIES; i++)
|
||||
{
|
||||
if (strcmp(name.c_str(), devmap->map[i].name.c_str()) == 0 && devmap->map[i].physical < 0)
|
||||
{
|
||||
devmap->map[i].physical = physical_idx;
|
||||
found = 1;
|
||||
devmap->logical[physical_idx] = i;
|
||||
}
|
||||
}
|
||||
|
||||
if (found == 0)
|
||||
{
|
||||
stick = devmap_leastfree(devmap);
|
||||
devmap->map[stick].physical = physical_idx;
|
||||
devmap->map[stick].name = name;
|
||||
devmap->logical[physical_idx] = stick;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//============================================================
|
||||
// sdl_joystick_module
|
||||
//============================================================
|
||||
|
||||
class sdl_joystick_module : public sdl_input_module
|
||||
{
|
||||
private:
|
||||
device_map_t m_joy_map;
|
||||
bool m_sixaxis_mode;
|
||||
public:
|
||||
sdl_joystick_module()
|
||||
: sdl_input_module(OSD_JOYSTICKINPUT_PROVIDER)
|
||||
{
|
||||
}
|
||||
|
||||
virtual void input_init(running_machine &machine) override
|
||||
{
|
||||
sdl_input_module::input_init(machine);
|
||||
|
||||
char tempname[512];
|
||||
|
||||
m_sixaxis_mode = downcast<const sdl_options*>(options())->sixaxis();
|
||||
|
||||
devmap_init(machine, &m_joy_map, SDLOPTION_JOYINDEX, 8, "Joystick mapping");
|
||||
|
||||
osd_printf_verbose("Joystick: Start initialization\n");
|
||||
int physical_stick;
|
||||
for (physical_stick = 0; physical_stick < SDL_NumJoysticks(); physical_stick++)
|
||||
{
|
||||
SDL_Joystick *joy = SDL_JoystickOpen(physical_stick);
|
||||
std::string joy_name = remove_spaces(SDL_JoystickName(joy));
|
||||
SDL_JoystickClose(joy);
|
||||
|
||||
devmap_register(&m_joy_map, physical_stick, joy_name.c_str());
|
||||
}
|
||||
|
||||
for (int stick = 0; stick < MAX_DEVMAP_ENTRIES; stick++)
|
||||
{
|
||||
sdl_joystick_device *devinfo = create_joystick_device(machine, &m_joy_map, stick, DEVICE_CLASS_JOYSTICK);
|
||||
|
||||
if (devinfo == NULL)
|
||||
continue;
|
||||
|
||||
physical_stick = m_joy_map.map[stick].physical;
|
||||
|
||||
SDL_Joystick *joy = SDL_JoystickOpen(physical_stick);
|
||||
|
||||
devinfo->sdl_state.device = joy;
|
||||
devinfo->sdl_state.joystick_id = SDL_JoystickInstanceID(joy);
|
||||
|
||||
osd_printf_verbose("Joystick: %s\n", devinfo->name());
|
||||
osd_printf_verbose("Joystick: ... %d axes, %d buttons %d hats %d balls\n", SDL_JoystickNumAxes(joy), SDL_JoystickNumButtons(joy), SDL_JoystickNumHats(joy), SDL_JoystickNumBalls(joy));
|
||||
osd_printf_verbose("Joystick: ... Physical id %d mapped to logical id %d\n", physical_stick, stick + 1);
|
||||
|
||||
// loop over all axes
|
||||
for (int axis = 0; axis < SDL_JoystickNumAxes(joy); axis++)
|
||||
{
|
||||
input_item_id itemid;
|
||||
|
||||
if (axis < INPUT_MAX_AXIS)
|
||||
itemid = (input_item_id)(ITEM_ID_XAXIS + axis);
|
||||
else if (axis < INPUT_MAX_AXIS + INPUT_MAX_ADD_ABSOLUTE)
|
||||
itemid = (input_item_id)(ITEM_ID_ADD_ABSOLUTE1 - INPUT_MAX_AXIS + axis);
|
||||
else
|
||||
itemid = ITEM_ID_OTHER_AXIS_ABSOLUTE;
|
||||
|
||||
snprintf(tempname, sizeof(tempname), "A%d %s", axis, devinfo->name());
|
||||
devinfo->device()->add_item(tempname, itemid, generic_axis_get_state, &devinfo->joystick.axes[axis]);
|
||||
}
|
||||
|
||||
// loop over all buttons
|
||||
for (int button = 0; button < SDL_JoystickNumButtons(joy); button++)
|
||||
{
|
||||
input_item_id itemid;
|
||||
|
||||
devinfo->joystick.buttons[button] = 0;
|
||||
|
||||
if (button < INPUT_MAX_BUTTONS)
|
||||
itemid = (input_item_id)(ITEM_ID_BUTTON1 + button);
|
||||
else if (button < INPUT_MAX_BUTTONS + INPUT_MAX_ADD_SWITCH)
|
||||
itemid = (input_item_id)(ITEM_ID_ADD_SWITCH1 - INPUT_MAX_BUTTONS + button);
|
||||
else
|
||||
itemid = ITEM_ID_OTHER_SWITCH;
|
||||
|
||||
snprintf(tempname, sizeof(tempname), "button %d", button);
|
||||
devinfo->device()->add_item(tempname, itemid, generic_button_get_state, &devinfo->joystick.buttons[button]);
|
||||
}
|
||||
|
||||
// loop over all hats
|
||||
for (int hat = 0; hat < SDL_JoystickNumHats(joy); hat++)
|
||||
{
|
||||
input_item_id itemid;
|
||||
|
||||
snprintf(tempname, sizeof(tempname), "hat %d Up", hat);
|
||||
itemid = (input_item_id)((hat < INPUT_MAX_HATS) ? ITEM_ID_HAT1UP + 4 * hat : ITEM_ID_OTHER_SWITCH);
|
||||
devinfo->device()->add_item(tempname, itemid, generic_button_get_state, &devinfo->joystick.hatsU[hat]);
|
||||
snprintf(tempname, sizeof(tempname), "hat %d Down", hat);
|
||||
itemid = (input_item_id)((hat < INPUT_MAX_HATS) ? ITEM_ID_HAT1DOWN + 4 * hat : ITEM_ID_OTHER_SWITCH);
|
||||
devinfo->device()->add_item(tempname, itemid, generic_button_get_state, &devinfo->joystick.hatsD[hat]);
|
||||
snprintf(tempname, sizeof(tempname), "hat %d Left", hat);
|
||||
itemid = (input_item_id)((hat < INPUT_MAX_HATS) ? ITEM_ID_HAT1LEFT + 4 * hat : ITEM_ID_OTHER_SWITCH);
|
||||
devinfo->device()->add_item(tempname, itemid, generic_button_get_state, &devinfo->joystick.hatsL[hat]);
|
||||
snprintf(tempname, sizeof(tempname), "hat %d Right", hat);
|
||||
itemid = (input_item_id)((hat < INPUT_MAX_HATS) ? ITEM_ID_HAT1RIGHT + 4 * hat : ITEM_ID_OTHER_SWITCH);
|
||||
devinfo->device()->add_item(tempname, itemid, generic_button_get_state, &devinfo->joystick.hatsR[hat]);
|
||||
}
|
||||
|
||||
// loop over all (track)balls
|
||||
for (int ball = 0; ball < SDL_JoystickNumBalls(joy); ball++)
|
||||
{
|
||||
int itemid;
|
||||
|
||||
if (ball * 2 < INPUT_MAX_ADD_RELATIVE)
|
||||
itemid = ITEM_ID_ADD_RELATIVE1 + ball * 2;
|
||||
else
|
||||
itemid = ITEM_ID_OTHER_AXIS_RELATIVE;
|
||||
|
||||
snprintf(tempname, sizeof(tempname), "R%d %s", ball * 2, devinfo->name());
|
||||
devinfo->device()->add_item(tempname, (input_item_id)itemid, generic_axis_get_state, &devinfo->joystick.balls[ball * 2]);
|
||||
snprintf(tempname, sizeof(tempname), "R%d %s", ball * 2 + 1, devinfo->name());
|
||||
devinfo->device()->add_item(tempname, (input_item_id)(itemid + 1), generic_axis_get_state, &devinfo->joystick.balls[ball * 2 + 1]);
|
||||
}
|
||||
}
|
||||
|
||||
SDL_EventType event_types[] = { SDL_JOYAXISMOTION, SDL_JOYBALLMOTION, SDL_JOYHATMOTION, SDL_JOYBUTTONDOWN, SDL_JOYBUTTONUP };
|
||||
sdl_event_manager::instance().subscribe(reinterpret_cast<int*>(event_types), ARRAY_LENGTH(event_types), this);
|
||||
|
||||
osd_printf_verbose("Joystick: End initialization\n");
|
||||
}
|
||||
|
||||
virtual void handle_event(SDL_Event &sdlevent) override
|
||||
{
|
||||
// Figure out which joystick this event id destined for
|
||||
for (int i = 0; i < devicelist()->size(); i++)
|
||||
{
|
||||
auto joy = downcast<sdl_joystick_device*>(devicelist()->at(i));
|
||||
|
||||
// If we find a matching joystick, dispatch the event to the joystick
|
||||
if (joy->sdl_state.joystick_id == sdlevent.jdevice.which)
|
||||
joy->queue_events(&sdlevent, 1);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
sdl_joystick_device* create_joystick_device(running_machine &machine, device_map_t *devmap, int index, input_device_class devclass)
|
||||
{
|
||||
sdl_joystick_device *devinfo = NULL;
|
||||
char tempname[20];
|
||||
|
||||
if (devmap->map[index].name.length() == 0)
|
||||
{
|
||||
/* only map place holders if there were mappings specified is enabled */
|
||||
if (devmap->initialized)
|
||||
{
|
||||
snprintf(tempname, ARRAY_LENGTH(tempname), "NC%d", index);
|
||||
devinfo = m_sixaxis_mode
|
||||
? devicelist()->create_device<sdl_sixaxis_joystick_device>(machine, tempname, *this)
|
||||
: devicelist()->create_device<sdl_joystick_device>(machine, tempname, *this);
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
devinfo = m_sixaxis_mode
|
||||
? devicelist()->create_device<sdl_sixaxis_joystick_device>(machine, devmap->map[index].name.c_str(), *this)
|
||||
: devicelist()->create_device<sdl_joystick_device>(machine, devmap->map[index].name.c_str(), *this);
|
||||
}
|
||||
|
||||
return devinfo;
|
||||
}
|
||||
};
|
||||
|
||||
#else
|
||||
MODULE_NOT_SUPPORTED(sdl_keyboard_module, OSD_KEYBOARDINPUT_PROVIDER, "sdl")
|
||||
MODULE_NOT_SUPPORTED(sdl_mouse_module, OSD_MOUSEINPUT_PROVIDER, "sdl")
|
||||
MODULE_NOT_SUPPORTED(sdl_joystick_module, OSD_JOYSTICKINPUT_PROVIDER, "sdl")
|
||||
#endif
|
||||
|
||||
MODULE_DEFINITION(KEYBOARDINPUT_SDL, sdl_keyboard_module)
|
||||
MODULE_DEFINITION(MOUSEINPUT_SDL, sdl_mouse_module)
|
||||
MODULE_DEFINITION(JOYSTICKINPUT_SDL, sdl_joystick_module)
|
283
src/osd/modules/input/input_sdlcommon.cpp
Normal file
283
src/osd/modules/input/input_sdlcommon.cpp
Normal file
@ -0,0 +1,283 @@
|
||||
// license:BSD-3-Clause
|
||||
// copyright-holders:Olivier Galibert, R. Belmont, Brad Hughes
|
||||
//============================================================
|
||||
//
|
||||
// input_sdlcommon.cpp - SDL Common code shared by SDL modules
|
||||
//
|
||||
// Note: this code is also used by the X11 input modules
|
||||
//
|
||||
//============================================================
|
||||
|
||||
#include "input_module.h"
|
||||
#include "modules/osdmodule.h"
|
||||
|
||||
#if defined(OSD_SDL)
|
||||
|
||||
// standard sdl header
|
||||
#include "sdlinc.h"
|
||||
#include <ctype.h>
|
||||
#include <stddef.h>
|
||||
#include <mutex>
|
||||
#include <memory>
|
||||
|
||||
// MAME headers
|
||||
#include "emu.h"
|
||||
#include "osdepend.h"
|
||||
#include "ui/ui.h"
|
||||
#include "uiinput.h"
|
||||
#include "window.h"
|
||||
#include "strconv.h"
|
||||
|
||||
#include "../../sdl/osdsdl.h"
|
||||
#include "input_common.h"
|
||||
#include "input_sdlcommon.h"
|
||||
|
||||
#define GET_WINDOW(ev) window_from_id((ev)->windowID)
|
||||
//#define GET_WINDOW(ev) ((ev)->windowID)
|
||||
|
||||
static inline sdl_window_info * window_from_id(Uint32 windowID)
|
||||
{
|
||||
sdl_window_info *w;
|
||||
SDL_Window *window = SDL_GetWindowFromID(windowID);
|
||||
|
||||
for (w = sdl_window_list; w != NULL; w = w->m_next)
|
||||
{
|
||||
//printf("w->window_id: %d\n", w->window_id);
|
||||
if (w->sdl_window() == window)
|
||||
{
|
||||
return w;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void sdl_event_manager::process_events(running_machine &machine)
|
||||
{
|
||||
std::lock_guard<std::mutex> scope_lock(m_lock);
|
||||
SDL_Event sdlevent;
|
||||
while (SDL_PollEvent(&sdlevent))
|
||||
{
|
||||
// process window events if they come in
|
||||
if (sdlevent.type == SDL_WINDOWEVENT)
|
||||
process_window_event(machine, sdlevent);
|
||||
|
||||
// Find all subscribers for the event type
|
||||
auto subscribers = m_subscription_index.equal_range(sdlevent.type);
|
||||
|
||||
// Dispatch the events
|
||||
for (auto iter = subscribers.first; iter != subscribers.second; iter++)
|
||||
iter->second->handle_event(sdlevent);
|
||||
}
|
||||
}
|
||||
|
||||
void sdl_event_manager::process_window_event(running_machine &machine, SDL_Event &sdlevent)
|
||||
{
|
||||
sdl_window_info *window = GET_WINDOW(&sdlevent.window);
|
||||
|
||||
if (window == NULL)
|
||||
return;
|
||||
|
||||
switch (sdlevent.window.event)
|
||||
{
|
||||
case SDL_WINDOWEVENT_CLOSE:
|
||||
machine.schedule_exit();
|
||||
break;
|
||||
|
||||
case SDL_WINDOWEVENT_LEAVE:
|
||||
machine.ui_input().push_mouse_leave_event(window->target());
|
||||
m_app_has_mouse_focus = 0;
|
||||
break;
|
||||
|
||||
case SDL_WINDOWEVENT_MOVED:
|
||||
window->notify_changed();
|
||||
m_focus_window = window;
|
||||
break;
|
||||
|
||||
case SDL_WINDOWEVENT_RESIZED:
|
||||
#ifndef SDLMAME_WIN32
|
||||
/* FIXME: SDL2 sends some spurious resize events on Ubuntu
|
||||
* while in fullscreen mode. Ignore them for now.
|
||||
*/
|
||||
if (!window->fullscreen())
|
||||
#endif
|
||||
{
|
||||
//printf("event data1,data2 %d x %d %ld\n", event.window.data1, event.window.data2, sizeof(SDL_Event));
|
||||
window->resize(sdlevent.window.data1, sdlevent.window.data2);
|
||||
}
|
||||
m_focus_window = window;
|
||||
break;
|
||||
|
||||
case SDL_WINDOWEVENT_ENTER:
|
||||
m_app_has_mouse_focus = 1;
|
||||
/* fall through */
|
||||
case SDL_WINDOWEVENT_FOCUS_GAINED:
|
||||
case SDL_WINDOWEVENT_EXPOSED:
|
||||
case SDL_WINDOWEVENT_MAXIMIZED:
|
||||
case SDL_WINDOWEVENT_RESTORED:
|
||||
m_focus_window = window;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
//============================================================
|
||||
// customize_input_type_list
|
||||
//============================================================
|
||||
|
||||
void sdl_osd_interface::customize_input_type_list(simple_list<input_type_entry> &typelist)
|
||||
{
|
||||
input_item_id mameid_code;
|
||||
input_code ui_code;
|
||||
input_type_entry *entry;
|
||||
const char* uimode;
|
||||
char fullmode[64];
|
||||
|
||||
// loop over the defaults
|
||||
for (entry = typelist.first(); entry != NULL; entry = entry->next())
|
||||
{
|
||||
switch (entry->type())
|
||||
{
|
||||
// configurable UI mode switch
|
||||
case IPT_UI_TOGGLE_UI:
|
||||
uimode = options().ui_mode_key();
|
||||
if (!strcmp(uimode, "auto"))
|
||||
{
|
||||
#if defined(__APPLE__) && defined(__MACH__)
|
||||
mameid_code = keyboard_trans_table::instance().lookup_mame_code("ITEM_ID_INSERT");
|
||||
#else
|
||||
mameid_code = keyboard_trans_table::instance().lookup_mame_code("ITEM_ID_SCRLOCK");
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
snprintf(fullmode, 63, "ITEM_ID_%s", uimode);
|
||||
mameid_code = keyboard_trans_table::instance().lookup_mame_code(fullmode);
|
||||
}
|
||||
ui_code = input_code(DEVICE_CLASS_KEYBOARD, 0, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, input_item_id(mameid_code));
|
||||
entry->defseq(SEQ_TYPE_STANDARD).set(ui_code);
|
||||
break;
|
||||
// alt-enter for fullscreen
|
||||
case IPT_OSD_1:
|
||||
entry->configure_osd("TOGGLE_FULLSCREEN", "Toggle Fullscreen");
|
||||
entry->defseq(SEQ_TYPE_STANDARD).set(KEYCODE_ENTER, KEYCODE_LALT);
|
||||
break;
|
||||
|
||||
// disable UI_SELECT when LALT is down, this stops selecting
|
||||
// things in the menu when toggling fullscreen with LALT+ENTER
|
||||
/* case IPT_UI_SELECT:
|
||||
entry->defseq(SEQ_TYPE_STANDARD).set(KEYCODE_ENTER, input_seq::not_code, KEYCODE_LALT);
|
||||
break;*/
|
||||
|
||||
// page down for fastforward (must be OSD_3 as per src/emu/ui.c)
|
||||
case IPT_UI_FAST_FORWARD:
|
||||
entry->defseq(SEQ_TYPE_STANDARD).set(KEYCODE_PGDN);
|
||||
break;
|
||||
|
||||
// OSD hotkeys use LCTRL and start at F3, they start at
|
||||
// F3 because F1-F2 are hardcoded into many drivers to
|
||||
// various dipswitches, and pressing them together with
|
||||
// LCTRL will still press/toggle these dipswitches.
|
||||
|
||||
// LCTRL-F3 to toggle fullstretch
|
||||
case IPT_OSD_2:
|
||||
entry->configure_osd("TOGGLE_FULLSTRETCH", "Toggle Uneven stretch");
|
||||
entry->defseq(SEQ_TYPE_STANDARD).set(KEYCODE_F3, KEYCODE_LCONTROL);
|
||||
break;
|
||||
// add a Not lcrtl condition to the reset key
|
||||
case IPT_UI_SOFT_RESET:
|
||||
entry->defseq(SEQ_TYPE_STANDARD).set(KEYCODE_F3, input_seq::not_code, KEYCODE_LCONTROL, input_seq::not_code, KEYCODE_LSHIFT);
|
||||
break;
|
||||
|
||||
// LCTRL-F4 to toggle keep aspect
|
||||
case IPT_OSD_4:
|
||||
entry->configure_osd("TOGGLE_KEEP_ASPECT", "Toggle Keepaspect");
|
||||
entry->defseq(SEQ_TYPE_STANDARD).set(KEYCODE_F4, KEYCODE_LCONTROL);
|
||||
break;
|
||||
// add a Not lcrtl condition to the show gfx key
|
||||
case IPT_UI_SHOW_GFX:
|
||||
entry->defseq(SEQ_TYPE_STANDARD).set(KEYCODE_F4, input_seq::not_code, KEYCODE_LCONTROL);
|
||||
break;
|
||||
|
||||
// LCTRL-F5 to toggle OpenGL filtering
|
||||
case IPT_OSD_5:
|
||||
entry->configure_osd("TOGGLE_FILTER", "Toggle Filter");
|
||||
entry->defseq(SEQ_TYPE_STANDARD).set(KEYCODE_F5, KEYCODE_LCONTROL);
|
||||
break;
|
||||
// add a Not lcrtl condition to the toggle debug key
|
||||
case IPT_UI_TOGGLE_DEBUG:
|
||||
entry->defseq(SEQ_TYPE_STANDARD).set(KEYCODE_F5, input_seq::not_code, KEYCODE_LCONTROL);
|
||||
break;
|
||||
|
||||
// LCTRL-F6 to decrease OpenGL prescaling
|
||||
case IPT_OSD_6:
|
||||
entry->configure_osd("DECREASE_PRESCALE", "Decrease Prescaling");
|
||||
entry->defseq(SEQ_TYPE_STANDARD).set(KEYCODE_F6, KEYCODE_LCONTROL);
|
||||
break;
|
||||
// add a Not lcrtl condition to the toggle cheat key
|
||||
case IPT_UI_TOGGLE_CHEAT:
|
||||
entry->defseq(SEQ_TYPE_STANDARD).set(KEYCODE_F6, input_seq::not_code, KEYCODE_LCONTROL);
|
||||
break;
|
||||
|
||||
// LCTRL-F7 to increase OpenGL prescaling
|
||||
case IPT_OSD_7:
|
||||
entry->configure_osd("INCREASE_PRESCALE", "Increase Prescaling");
|
||||
entry->defseq(SEQ_TYPE_STANDARD).set(KEYCODE_F7, KEYCODE_LCONTROL);
|
||||
break;
|
||||
// add a Not lcrtl condition to the load state key
|
||||
case IPT_UI_LOAD_STATE:
|
||||
entry->defseq(SEQ_TYPE_STANDARD).set(KEYCODE_F7, input_seq::not_code, KEYCODE_LCONTROL, input_seq::not_code, KEYCODE_LSHIFT);
|
||||
break;
|
||||
|
||||
// add a Not lcrtl condition to the throttle key
|
||||
case IPT_UI_THROTTLE:
|
||||
entry->defseq(SEQ_TYPE_STANDARD).set(KEYCODE_F10, input_seq::not_code, KEYCODE_LCONTROL);
|
||||
break;
|
||||
|
||||
// disable the config menu if the ALT key is down
|
||||
// (allows ALT-TAB to switch between apps)
|
||||
case IPT_UI_CONFIGURE:
|
||||
entry->defseq(SEQ_TYPE_STANDARD).set(KEYCODE_TAB, input_seq::not_code, KEYCODE_LALT, input_seq::not_code, KEYCODE_RALT);
|
||||
break;
|
||||
|
||||
// leave everything else alone
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void sdl_osd_interface::poll_inputs(running_machine &machine)
|
||||
{
|
||||
m_keyboard_input->poll_if_necessary(machine);
|
||||
m_mouse_input->poll_if_necessary(machine);
|
||||
m_lightgun_input->poll_if_necessary(machine);
|
||||
m_joystick_input->poll_if_necessary(machine);
|
||||
}
|
||||
|
||||
void sdl_osd_interface::release_keys()
|
||||
{
|
||||
downcast<input_module_base*>(m_keyboard_input)->devicelist()->reset_devices();
|
||||
}
|
||||
|
||||
bool sdl_osd_interface::should_hide_mouse()
|
||||
{
|
||||
// if we are paused, no
|
||||
if (machine().paused())
|
||||
return false;
|
||||
|
||||
// if neither mice nor lightguns enabled in the core, then no
|
||||
if (!options().mouse() && !options().lightgun())
|
||||
return false;
|
||||
|
||||
if (!sdl_event_manager::instance().app_has_mouse_focus())
|
||||
return false;
|
||||
|
||||
// otherwise, yes
|
||||
return true;
|
||||
}
|
||||
|
||||
void sdl_osd_interface::process_events_buf()
|
||||
{
|
||||
SDL_PumpEvents();
|
||||
}
|
||||
|
||||
#endif
|
204
src/osd/modules/input/input_sdlcommon.h
Normal file
204
src/osd/modules/input/input_sdlcommon.h
Normal file
@ -0,0 +1,204 @@
|
||||
// license:BSD-3-Clause
|
||||
// copyright-holders:Olivier Galibert, R. Belmont, Brad Hughes
|
||||
//============================================================
|
||||
//
|
||||
// input_sdlcommon.h - SDL Common code shared by SDL modules
|
||||
//
|
||||
// Note: this code is also used by the X11 input modules
|
||||
//
|
||||
//============================================================
|
||||
|
||||
#ifndef INPUT_SDLCOMMON_H_
|
||||
#define INPUT_SDLCOMMON_H_
|
||||
|
||||
#include <vector>
|
||||
#include <unordered_map>
|
||||
#include <algorithm>
|
||||
#include <queue>
|
||||
|
||||
#define MAX_DEVMAP_ENTRIES 16
|
||||
#define SDL_MODULE_EVENT_BUFFER_SIZE 5
|
||||
|
||||
// state information for a keyboard
|
||||
struct keyboard_state
|
||||
{
|
||||
INT32 state[0x3ff]; // must be INT32!
|
||||
INT8 oldkey[MAX_KEYS];
|
||||
INT8 currkey[MAX_KEYS];
|
||||
};
|
||||
|
||||
// state information for a mouse
|
||||
struct mouse_state
|
||||
{
|
||||
INT32 lX, lY;
|
||||
INT32 buttons[MAX_BUTTONS];
|
||||
};
|
||||
|
||||
|
||||
// state information for a joystick; DirectInput state must be first element
|
||||
struct joystick_state
|
||||
{
|
||||
SDL_Joystick *device;
|
||||
INT32 axes[MAX_AXES];
|
||||
INT32 buttons[MAX_BUTTONS];
|
||||
INT32 hatsU[MAX_HATS], hatsD[MAX_HATS], hatsL[MAX_HATS], hatsR[MAX_HATS];
|
||||
INT32 balls[MAX_AXES];
|
||||
};
|
||||
|
||||
struct device_map_t
|
||||
{
|
||||
struct {
|
||||
std::string name;
|
||||
int physical;
|
||||
} map[MAX_DEVMAP_ENTRIES];
|
||||
int logical[MAX_DEVMAP_ENTRIES];
|
||||
int initialized;
|
||||
};
|
||||
|
||||
//============================================================
|
||||
// event_manager_t
|
||||
//============================================================
|
||||
|
||||
class sdl_event_subscriber
|
||||
{
|
||||
public:
|
||||
virtual void handle_event(SDL_Event &sdlevent) = 0;
|
||||
};
|
||||
|
||||
template <class TSubscriber>
|
||||
class event_manager_t
|
||||
{
|
||||
protected:
|
||||
std::mutex m_lock;
|
||||
std::unordered_multimap<int, TSubscriber*> m_subscription_index;
|
||||
event_manager_t()
|
||||
{
|
||||
}
|
||||
|
||||
public:
|
||||
void subscribe(int* event_types, int num_event_types, TSubscriber *subscriber)
|
||||
{
|
||||
std::lock_guard<std::mutex> scope_lock(m_lock);
|
||||
|
||||
// Add the subscription
|
||||
for (int i = 0; i < num_event_types; i++)
|
||||
{
|
||||
m_subscription_index.emplace(event_types[i], subscriber);
|
||||
}
|
||||
}
|
||||
|
||||
void unsubscribe(TSubscriber *subscriber)
|
||||
{
|
||||
std::lock_guard<std::mutex> scope_lock(m_lock);
|
||||
|
||||
// Loop over the entries and find ones that match our subscriber
|
||||
// remove those that match
|
||||
for (auto iter = m_subscription_index.begin(); iter != m_subscription_index.end(); iter++)
|
||||
{
|
||||
if (iter->second == subscriber)
|
||||
m_subscription_index.erase(iter);
|
||||
}
|
||||
}
|
||||
|
||||
virtual void process_events(running_machine &machine) = 0;
|
||||
};
|
||||
|
||||
class sdl_window_info;
|
||||
|
||||
// REVIEW: Do we need to handle SDLMAME_EVENTS_IN_WORKER_THREAD eventually?
|
||||
class sdl_event_manager : public event_manager_t<sdl_event_subscriber>
|
||||
{
|
||||
private:
|
||||
bool m_app_has_mouse_focus;
|
||||
sdl_window_info * m_focus_window;
|
||||
|
||||
sdl_event_manager()
|
||||
: m_app_has_mouse_focus(true),
|
||||
m_focus_window(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
public:
|
||||
bool app_has_mouse_focus() { return m_app_has_mouse_focus; }
|
||||
sdl_window_info * focus_window() { return m_focus_window; }
|
||||
|
||||
static sdl_event_manager& instance()
|
||||
{
|
||||
static sdl_event_manager s_instance;
|
||||
return s_instance;
|
||||
}
|
||||
|
||||
void process_events(running_machine &machine) override;
|
||||
|
||||
private:
|
||||
void process_window_event(running_machine &machine, SDL_Event &sdlevent);
|
||||
};
|
||||
|
||||
//============================================================
|
||||
// INLINE FUNCTIONS
|
||||
//============================================================
|
||||
|
||||
static inline int devmap_leastfree(device_map_t *devmap)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < MAX_DEVMAP_ENTRIES; i++)
|
||||
{
|
||||
if (devmap->map[i].name.length() == 0)
|
||||
return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static inline std::string remove_spaces(const char *s)
|
||||
{
|
||||
// Remove the spaces
|
||||
auto output = std::string(s);
|
||||
output.erase(std::remove_if(output.begin(), output.end(), isspace), output.end());
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
//============================================================
|
||||
// devmap_init - initializes a device_map based on
|
||||
// an input option prefix and max number of devices
|
||||
//============================================================
|
||||
|
||||
static inline void devmap_init(running_machine &machine, device_map_t *devmap, const char *opt, int max_devices, const char *label)
|
||||
{
|
||||
int dev;
|
||||
char defname[20];
|
||||
|
||||
// The max devices the user specified, better not be bigger than the max the arrays can old
|
||||
assert(max_devices <= MAX_DEVMAP_ENTRIES);
|
||||
|
||||
// Initialize the map to default uninitialized values
|
||||
for (dev = 0; dev < MAX_DEVMAP_ENTRIES; dev++)
|
||||
{
|
||||
devmap->map[dev].physical = -1;
|
||||
devmap->logical[dev] = -1;
|
||||
}
|
||||
devmap->initialized = 0;
|
||||
|
||||
// populate the device map up to the max number of devices
|
||||
for (dev = 0; dev < max_devices; dev++)
|
||||
{
|
||||
const char *dev_name;
|
||||
|
||||
// derive the parameter name from the option name and index. For instance: lightgun_index1 to lightgun_index8
|
||||
sprintf(defname, "%s%d", opt, dev + 1);
|
||||
|
||||
// Get the user-specified name that matches the parameter
|
||||
dev_name = machine.options().value(defname);
|
||||
|
||||
// If they've specified a name and it's not "auto", treat it as a custom mapping
|
||||
if (dev_name && *dev_name && strcmp(dev_name, OSDOPTVAL_AUTO))
|
||||
{
|
||||
// remove the spaces from the name store it in the index
|
||||
devmap->map[dev].name = remove_spaces(dev_name);
|
||||
osd_printf_verbose("%s: Logical id %d: %s\n", label, dev + 1, devmap->map[dev].name.c_str());
|
||||
devmap->initialized = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
427
src/osd/modules/input/input_win32.cpp
Normal file
427
src/osd/modules/input/input_win32.cpp
Normal file
@ -0,0 +1,427 @@
|
||||
// license:BSD-3-Clause
|
||||
// copyright-holders:Aaron Giles, Brad Hughes
|
||||
//============================================================
|
||||
//
|
||||
// input_win32.cpp - Win32 input implementation
|
||||
//
|
||||
//============================================================
|
||||
|
||||
#include "input_module.h"
|
||||
#include "modules/osdmodule.h"
|
||||
|
||||
#if defined(OSD_WINDOWS)
|
||||
|
||||
// standard windows headers
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
#include <winioctl.h>
|
||||
#include <tchar.h>
|
||||
#undef interface
|
||||
|
||||
#include <mutex>
|
||||
|
||||
// MAME headers
|
||||
#include "emu.h"
|
||||
#include "osdepend.h"
|
||||
#include "ui/ui.h"
|
||||
#include "strconv.h"
|
||||
|
||||
// MAMEOS headers
|
||||
#include "winmain.h"
|
||||
#include "window.h"
|
||||
#include "../../windows/input.h"
|
||||
|
||||
#include "input_common.h"
|
||||
#include "input_windows.h"
|
||||
|
||||
//============================================================
|
||||
// win32_keyboard_device
|
||||
//============================================================
|
||||
|
||||
// This device is purely event driven so the implementation is in the module
|
||||
class win32_keyboard_device : public event_based_device<KeyPressEventArgs>
|
||||
{
|
||||
public:
|
||||
keyboard_state keyboard;
|
||||
|
||||
win32_keyboard_device(running_machine& machine, const char *name, input_module &module)
|
||||
: event_based_device(machine, name, DEVICE_CLASS_KEYBOARD, module),
|
||||
keyboard({0})
|
||||
{
|
||||
}
|
||||
|
||||
void reset() override
|
||||
{
|
||||
memset(&keyboard, 0, sizeof(keyboard));
|
||||
}
|
||||
|
||||
protected:
|
||||
void process_event(KeyPressEventArgs &args) override
|
||||
{
|
||||
keyboard.state[args.scancode] = args.event_id == INPUT_EVENT_KEYDOWN ? 0x80 : 0x00;
|
||||
}
|
||||
};
|
||||
|
||||
//============================================================
|
||||
// keyboard_input_win32 - win32 keyboard input module
|
||||
//============================================================
|
||||
|
||||
class keyboard_input_win32 : public wininput_module
|
||||
{
|
||||
private:
|
||||
const osd_options * m_options;
|
||||
|
||||
public:
|
||||
keyboard_input_win32()
|
||||
: wininput_module(OSD_KEYBOARDINPUT_PROVIDER, "win32")
|
||||
{
|
||||
}
|
||||
|
||||
virtual void input_init(running_machine &machine) override
|
||||
{
|
||||
// Add a single win32 keyboard device that we'll monitor using Win32
|
||||
win32_keyboard_device *devinfo = devicelist()->create_device<win32_keyboard_device>(machine, "Win32 Keyboard 1", *this);
|
||||
|
||||
keyboard_trans_table &table = keyboard_trans_table::instance();
|
||||
|
||||
// populate it
|
||||
for (int keynum = 0; keynum < MAX_KEYS; keynum++)
|
||||
{
|
||||
input_item_id itemid = table.map_di_scancode_to_itemid(keynum);
|
||||
char name[20];
|
||||
|
||||
// generate/fetch the name
|
||||
_snprintf(name, ARRAY_LENGTH(name), "Scan%03d", keynum);
|
||||
|
||||
// add the item to the device
|
||||
devinfo->device()->add_item(name, itemid, generic_button_get_state, &devinfo->keyboard.state[keynum]);
|
||||
}
|
||||
}
|
||||
|
||||
bool handle_input_event(input_event eventid, void *eventdata) override
|
||||
{
|
||||
if (!input_enabled())
|
||||
return FALSE;
|
||||
|
||||
KeyPressEventArgs *args = nullptr;
|
||||
|
||||
switch (eventid)
|
||||
{
|
||||
case INPUT_EVENT_KEYDOWN:
|
||||
case INPUT_EVENT_KEYUP:
|
||||
args = (KeyPressEventArgs*)eventdata;
|
||||
for (int i = 0; i < devicelist()->size(); i++)
|
||||
downcast<win32_keyboard_device*>(devicelist()->at(i))->queue_events(args, 1);
|
||||
|
||||
return TRUE;
|
||||
|
||||
default:
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
//============================================================
|
||||
// win32_mouse_device
|
||||
//============================================================
|
||||
|
||||
struct win32_mouse_state
|
||||
{
|
||||
POINT last_point;
|
||||
};
|
||||
|
||||
class win32_mouse_device : public event_based_device<MouseButtonEventArgs>
|
||||
{
|
||||
public:
|
||||
mouse_state mouse;
|
||||
win32_mouse_state win32_mouse;
|
||||
|
||||
win32_mouse_device(running_machine& machine, const char *name, input_module &module)
|
||||
: event_based_device(machine, name, DEVICE_CLASS_MOUSE, module),
|
||||
mouse({0}),
|
||||
win32_mouse({0})
|
||||
{
|
||||
}
|
||||
|
||||
void poll() override
|
||||
{
|
||||
event_based_device::poll();
|
||||
|
||||
CURSORINFO cursor_info = {0};
|
||||
cursor_info.cbSize = sizeof(CURSORINFO);
|
||||
GetCursorInfo(&cursor_info);
|
||||
|
||||
// We only take over the mouse if the cursor isn't showing
|
||||
// This should happen anyway in mouse mode
|
||||
if (!(cursor_info.flags & CURSOR_SHOWING))
|
||||
{
|
||||
// We measure the position change from the previously set center position
|
||||
mouse.lX = (cursor_info.ptScreenPos.x - win32_mouse.last_point.x) * INPUT_RELATIVE_PER_PIXEL;
|
||||
mouse.lY = (cursor_info.ptScreenPos.y - win32_mouse.last_point.y) * INPUT_RELATIVE_PER_PIXEL;
|
||||
|
||||
RECT window_pos = {0};
|
||||
GetWindowRect(win_window_list->m_hwnd, &window_pos);
|
||||
|
||||
// We reset the cursor position to the middle of the window each frame
|
||||
win32_mouse.last_point.x = window_pos.left + (window_pos.right - window_pos.left) / 2;
|
||||
win32_mouse.last_point.y = window_pos.top + (window_pos.bottom - window_pos.top) / 2;
|
||||
|
||||
SetCursorPos(win32_mouse.last_point.x, win32_mouse.last_point.y);
|
||||
}
|
||||
}
|
||||
|
||||
void reset() override
|
||||
{
|
||||
memset(&mouse, 0, sizeof(mouse));
|
||||
}
|
||||
|
||||
protected:
|
||||
void process_event(MouseButtonEventArgs &args)
|
||||
{
|
||||
// set the button state
|
||||
mouse.rgbButtons[args.button] = args.keydown ? 0x80 : 0x00;
|
||||
|
||||
// Make sure we have a fresh mouse position on button down
|
||||
if (args.keydown)
|
||||
module().poll_if_necessary(machine());
|
||||
}
|
||||
};
|
||||
|
||||
//============================================================
|
||||
// mouse_input_win32 - win32 mouse input module
|
||||
//============================================================
|
||||
|
||||
class mouse_input_win32 : public wininput_module
|
||||
{
|
||||
private:
|
||||
const osd_options * m_options;
|
||||
|
||||
public:
|
||||
mouse_input_win32()
|
||||
: wininput_module(OSD_MOUSEINPUT_PROVIDER, "win32")
|
||||
{
|
||||
}
|
||||
|
||||
virtual void input_init(running_machine &machine) override
|
||||
{
|
||||
win32_mouse_device *devinfo;
|
||||
int axisnum, butnum;
|
||||
|
||||
if (!input_enabled() || !mouse_enabled())
|
||||
return;
|
||||
|
||||
// allocate a device
|
||||
devinfo = devicelist()->create_device<win32_mouse_device>(machine, "Win32 Mouse 1", *this);
|
||||
if (devinfo == NULL)
|
||||
return;
|
||||
|
||||
// populate the axes
|
||||
for (axisnum = 0; axisnum < 2; axisnum++)
|
||||
{
|
||||
devinfo->device()->add_item(default_axis_name[axisnum], (input_item_id)(ITEM_ID_XAXIS + axisnum), generic_axis_get_state, &devinfo->mouse.lX + axisnum);
|
||||
}
|
||||
|
||||
// populate the buttons
|
||||
for (butnum = 0; butnum < 2; butnum++)
|
||||
{
|
||||
devinfo->device()->add_item(default_button_name(butnum), (input_item_id)(ITEM_ID_BUTTON1 + butnum), generic_button_get_state, &devinfo->mouse.rgbButtons[butnum]);
|
||||
}
|
||||
}
|
||||
|
||||
bool handle_input_event(input_event eventid, void *eventdata) override
|
||||
{
|
||||
if (!input_enabled() || !mouse_enabled() || eventid != INPUT_EVENT_MOUSE_BUTTON)
|
||||
return FALSE;
|
||||
|
||||
auto args = static_cast<MouseButtonEventArgs*>(eventdata);
|
||||
for (int i = 0; i < devicelist()->size(); i++)
|
||||
downcast<win32_mouse_device*>(devicelist()->at(i))->queue_events(args, 1);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
};
|
||||
|
||||
//============================================================
|
||||
// win32_lightgun_device
|
||||
//============================================================
|
||||
|
||||
class win32_lightgun_device : public event_based_device<MouseButtonEventArgs>
|
||||
{
|
||||
private:
|
||||
BOOL m_lightgun_shared_axis_mode;
|
||||
int m_gun_index;
|
||||
|
||||
public:
|
||||
mouse_state mouse;
|
||||
|
||||
win32_lightgun_device(running_machine& machine, const char *name, input_module &module)
|
||||
: event_based_device(machine, name, DEVICE_CLASS_LIGHTGUN, module),
|
||||
m_lightgun_shared_axis_mode(FALSE),
|
||||
m_gun_index(0)
|
||||
{
|
||||
m_lightgun_shared_axis_mode = downcast<windows_options &>(machine.options()).dual_lightgun();
|
||||
|
||||
// Since we are about to be added to the list, the current size is the zero-based index of where we will be
|
||||
m_gun_index = downcast<wininput_module&>(module).devicelist()->size();
|
||||
}
|
||||
|
||||
void poll() override
|
||||
{
|
||||
event_based_device::poll();
|
||||
|
||||
INT32 xpos = 0, ypos = 0;
|
||||
POINT mousepos;
|
||||
|
||||
// if we are using the shared axis hack, the data is updated via Windows messages only
|
||||
if (m_lightgun_shared_axis_mode)
|
||||
return;
|
||||
|
||||
// get the cursor position and transform into final results
|
||||
GetCursorPos(&mousepos);
|
||||
if (win_window_list != NULL)
|
||||
{
|
||||
RECT client_rect;
|
||||
|
||||
// get the position relative to the window
|
||||
GetClientRect(win_window_list->m_hwnd, &client_rect);
|
||||
ScreenToClient(win_window_list->m_hwnd, &mousepos);
|
||||
|
||||
// convert to absolute coordinates
|
||||
xpos = normalize_absolute_axis(mousepos.x, client_rect.left, client_rect.right);
|
||||
ypos = normalize_absolute_axis(mousepos.y, client_rect.top, client_rect.bottom);
|
||||
}
|
||||
|
||||
// update the X/Y positions
|
||||
mouse.lX = xpos;
|
||||
mouse.lY = ypos;
|
||||
}
|
||||
|
||||
void reset() override
|
||||
{
|
||||
memset(&mouse, 0, sizeof(mouse));
|
||||
}
|
||||
|
||||
protected:
|
||||
void process_event(MouseButtonEventArgs &args)
|
||||
{
|
||||
// Are we in shared axis mode?
|
||||
if (m_lightgun_shared_axis_mode)
|
||||
{
|
||||
handle_shared_axis_mode(args);
|
||||
}
|
||||
else
|
||||
{
|
||||
// In non-shared axis mode, just update the button state
|
||||
mouse.rgbButtons[args.button] = args.keydown ? 0x80 : 0x00;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
void handle_shared_axis_mode(MouseButtonEventArgs &args)
|
||||
{
|
||||
int button = args.button;
|
||||
|
||||
// We only handle the first four buttons in shared axis mode
|
||||
if (button > 3)
|
||||
return;
|
||||
|
||||
// First gun doesn't handle buttons 2 & 3
|
||||
if (button >= 2 && m_gun_index == 0)
|
||||
return;
|
||||
|
||||
// Second gun doesn't handle buttons 0 & 1
|
||||
if (button < 2 && m_gun_index == 1)
|
||||
return;
|
||||
|
||||
// Adjust the button if we're the second lightgun
|
||||
int logical_button = m_gun_index == 1 ? button - 2 : button;
|
||||
|
||||
// set the button state
|
||||
mouse.rgbButtons[logical_button] = args.keydown ? 0x80 : 0x00;
|
||||
if (args.keydown)
|
||||
{
|
||||
RECT client_rect;
|
||||
POINT mousepos;
|
||||
|
||||
// get the position relative to the window
|
||||
GetClientRect(win_window_list->m_hwnd, &client_rect);
|
||||
mousepos.x = args.xpos;
|
||||
mousepos.y = args.ypos;
|
||||
ScreenToClient(win_window_list->m_hwnd, &mousepos);
|
||||
|
||||
// convert to absolute coordinates
|
||||
mouse.lX = normalize_absolute_axis(mousepos.x, client_rect.left, client_rect.right);
|
||||
mouse.lY = normalize_absolute_axis(mousepos.y, client_rect.top, client_rect.bottom);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
//============================================================
|
||||
// lightgun_input_win32 - win32 lightgun input module
|
||||
//============================================================
|
||||
|
||||
class lightgun_input_win32 : public wininput_module
|
||||
{
|
||||
public:
|
||||
lightgun_input_win32()
|
||||
: wininput_module(OSD_LIGHTGUNINPUT_PROVIDER, "win32")
|
||||
{
|
||||
}
|
||||
|
||||
int init_internal() override
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
virtual void input_init(running_machine &machine) override
|
||||
{
|
||||
int max_guns = downcast<windows_options&>(machine.options()).dual_lightgun() ? 2 : 1;
|
||||
|
||||
// allocate the lightgun devices
|
||||
for (int gunnum = 0; gunnum < max_guns; gunnum++)
|
||||
{
|
||||
static const char *const gun_names[] = { "Win32 Gun 1", "Win32 Gun 2" };
|
||||
win32_lightgun_device *devinfo;
|
||||
int axisnum, butnum;
|
||||
|
||||
// allocate a device
|
||||
devinfo = devicelist()->create_device<win32_lightgun_device>(machine, gun_names[gunnum], *this);
|
||||
if (devinfo == NULL)
|
||||
break;
|
||||
|
||||
// populate the axes
|
||||
for (axisnum = 0; axisnum < 2; axisnum++)
|
||||
{
|
||||
devinfo->device()->add_item(default_axis_name[axisnum], (input_item_id)(ITEM_ID_XAXIS + axisnum), generic_axis_get_state, &devinfo->mouse.lX + axisnum);
|
||||
}
|
||||
|
||||
// populate the buttons
|
||||
for (butnum = 0; butnum < 2; butnum++)
|
||||
{
|
||||
devinfo->device()->add_item(default_button_name(butnum), (input_item_id)(ITEM_ID_BUTTON1 + butnum), generic_button_get_state, &devinfo->mouse.rgbButtons[butnum]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool handle_input_event(input_event eventid, void* eventdata) override
|
||||
{
|
||||
if (!input_enabled() || !lightgun_enabled() || eventid != INPUT_EVENT_MOUSE_BUTTON)
|
||||
return false;
|
||||
|
||||
for (int i = 0; i < devicelist()->size(); i++)
|
||||
downcast<win32_lightgun_device*>(devicelist()->at(i))->queue_events(static_cast<MouseButtonEventArgs*>(eventdata), 1);
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
#else
|
||||
MODULE_NOT_SUPPORTED(keyboard_input_win32, OSD_KEYBOARDINPUT_PROVIDER, "win32")
|
||||
MODULE_NOT_SUPPORTED(mouse_input_win32, OSD_MOUSEINPUT_PROVIDER, "win32")
|
||||
MODULE_NOT_SUPPORTED(lightgun_input_win32, OSD_LIGHTGUNINPUT_PROVIDER, "win32")
|
||||
#endif
|
||||
|
||||
MODULE_DEFINITION(KEYBOARDINPUT_WIN32, keyboard_input_win32)
|
||||
MODULE_DEFINITION(MOUSEINPUT_WIN32, mouse_input_win32)
|
||||
MODULE_DEFINITION(LIGHTGUNINPUT_WIN32, lightgun_input_win32)
|
||||
|
144
src/osd/modules/input/input_windows.cpp
Normal file
144
src/osd/modules/input/input_windows.cpp
Normal file
@ -0,0 +1,144 @@
|
||||
// license:BSD-3-Clause
|
||||
// copyright-holders:Aaron Giles, Brad Hughes
|
||||
//============================================================
|
||||
//
|
||||
// input_windows.cpp - Common code used by Windows input modules
|
||||
//
|
||||
//============================================================
|
||||
|
||||
#include "input_module.h"
|
||||
#include "modules/osdmodule.h"
|
||||
|
||||
#if defined(OSD_WINDOWS)
|
||||
|
||||
// standard windows headers
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
#include <winioctl.h>
|
||||
#include <tchar.h>
|
||||
#undef interface
|
||||
|
||||
// MAME headers
|
||||
#include "emu.h"
|
||||
#include "osdepend.h"
|
||||
#include "ui/ui.h"
|
||||
|
||||
// MAMEOS headers
|
||||
#include "winmain.h"
|
||||
#include "window.h"
|
||||
#include "../../windows/input.h"
|
||||
|
||||
#include "input_common.h"
|
||||
#include "input_windows.h"
|
||||
|
||||
bool windows_osd_interface::should_hide_mouse()
|
||||
{
|
||||
bool hidemouse = false;
|
||||
hidemouse |= downcast<wininput_module*>(m_keyboard_input)->should_hide_mouse();
|
||||
hidemouse |= downcast<wininput_module*>(m_mouse_input)->should_hide_mouse();
|
||||
hidemouse |= downcast<wininput_module*>(m_lightgun_input)->should_hide_mouse();
|
||||
hidemouse |= downcast<wininput_module*>(m_joystick_input)->should_hide_mouse();
|
||||
return hidemouse;
|
||||
}
|
||||
|
||||
bool windows_osd_interface::handle_input_event(input_event eventid, void* eventdata)
|
||||
{
|
||||
bool handled = false;
|
||||
handled |= downcast<wininput_module*>(m_keyboard_input)->handle_input_event(eventid, eventdata);
|
||||
handled |= downcast<wininput_module*>(m_mouse_input)->handle_input_event(eventid, eventdata);
|
||||
handled |= downcast<wininput_module*>(m_lightgun_input)->handle_input_event(eventid, eventdata);
|
||||
handled |= downcast<wininput_module*>(m_joystick_input)->handle_input_event(eventid, eventdata);
|
||||
return handled;
|
||||
}
|
||||
|
||||
void windows_osd_interface::poll_input(running_machine &machine)
|
||||
{
|
||||
m_keyboard_input->poll_if_necessary(machine);
|
||||
m_mouse_input->poll_if_necessary(machine);
|
||||
m_lightgun_input->poll_if_necessary(machine);
|
||||
m_joystick_input->poll_if_necessary(machine);
|
||||
}
|
||||
|
||||
//============================================================
|
||||
// customize_input_type_list
|
||||
//============================================================
|
||||
|
||||
void windows_osd_interface::customize_input_type_list(simple_list<input_type_entry> &typelist)
|
||||
{
|
||||
input_type_entry *entry;
|
||||
const char* uimode;
|
||||
|
||||
// loop over the defaults
|
||||
for (entry = typelist.first(); entry != NULL; entry = entry->next())
|
||||
switch (entry->type())
|
||||
{
|
||||
// disable the config menu if the ALT key is down
|
||||
// (allows ALT-TAB to switch between windows apps)
|
||||
case IPT_UI_CONFIGURE:
|
||||
entry->defseq(SEQ_TYPE_STANDARD).set(KEYCODE_TAB, input_seq::not_code, KEYCODE_LALT, input_seq::not_code, KEYCODE_RALT);
|
||||
break;
|
||||
|
||||
// configurable UI mode switch
|
||||
case IPT_UI_TOGGLE_UI:
|
||||
uimode = options().ui_mode_key();
|
||||
if (strcmp(uimode, "auto"))
|
||||
{
|
||||
std::string fullmode = "ITEM_ID_";
|
||||
fullmode += uimode;
|
||||
input_item_id const mameid_code = keyboard_trans_table::instance().lookup_mame_code(fullmode.c_str());
|
||||
if (ITEM_ID_INVALID != mameid_code)
|
||||
{
|
||||
input_code const ui_code = input_code(DEVICE_CLASS_KEYBOARD, 0, ITEM_CLASS_SWITCH, ITEM_MODIFIER_NONE, input_item_id(mameid_code));
|
||||
entry->defseq(SEQ_TYPE_STANDARD).set(ui_code);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
// alt-enter for fullscreen
|
||||
case IPT_OSD_1:
|
||||
entry->configure_osd("TOGGLE_FULLSCREEN", "Toggle Fullscreen");
|
||||
entry->defseq(SEQ_TYPE_STANDARD).set(KEYCODE_ENTER, KEYCODE_LALT, input_seq::or_code, KEYCODE_ENTER, KEYCODE_RALT);
|
||||
break;
|
||||
|
||||
// lalt-F12 for fullscreen snap (HLSL)
|
||||
case IPT_OSD_2:
|
||||
entry->configure_osd("RENDER_SNAP", "Take Rendered Snapshot");
|
||||
entry->defseq(SEQ_TYPE_STANDARD).set(KEYCODE_F12, KEYCODE_LALT, input_seq::not_code, KEYCODE_LSHIFT);
|
||||
break;
|
||||
// add a NOT-lalt to our default F12
|
||||
case IPT_UI_SNAPSHOT: // emu/input.c: input_seq(KEYCODE_F12, input_seq::not_code, KEYCODE_LSHIFT)
|
||||
entry->defseq(SEQ_TYPE_STANDARD).set(KEYCODE_F12, input_seq::not_code, KEYCODE_LSHIFT, input_seq::not_code, KEYCODE_LALT);
|
||||
break;
|
||||
|
||||
// lshift-lalt-F12 for fullscreen video (HLSL)
|
||||
case IPT_OSD_3:
|
||||
entry->configure_osd("RENDER_AVI", "Record Rendered Video");
|
||||
entry->defseq(SEQ_TYPE_STANDARD).set(KEYCODE_F12, KEYCODE_LSHIFT, KEYCODE_LALT);
|
||||
break;
|
||||
// add a NOT-lalt to our default shift-F12
|
||||
case IPT_UI_RECORD_MOVIE: // emu/input.c: input_seq(KEYCODE_F12, KEYCODE_LSHIFT)
|
||||
entry->defseq(SEQ_TYPE_STANDARD).set(KEYCODE_F12, KEYCODE_LSHIFT, input_seq::not_code, KEYCODE_LALT);
|
||||
break;
|
||||
|
||||
// add a NOT-lalt to write timecode file
|
||||
case IPT_UI_TIMECODE: // emu/input.c: input_seq(KEYCODE_F12, input_seq::not_code, KEYCODE_LSHIFT)
|
||||
entry->defseq(SEQ_TYPE_STANDARD).set(KEYCODE_F12, input_seq::not_code, KEYCODE_LSHIFT, input_seq::not_code, KEYCODE_LALT);
|
||||
break;
|
||||
|
||||
// lctrl-lalt-F5 to toggle post-processing
|
||||
case IPT_OSD_4:
|
||||
entry->configure_osd("POST_PROCESS", "Toggle Post-Processing");
|
||||
entry->defseq(SEQ_TYPE_STANDARD).set(KEYCODE_F5, KEYCODE_LALT, KEYCODE_LCONTROL);
|
||||
break;
|
||||
// add a NOT-lctrl-lalt to our default F5
|
||||
case IPT_UI_TOGGLE_DEBUG: // emu/input.c: input_seq(KEYCODE_F5)
|
||||
entry->defseq(SEQ_TYPE_STANDARD).set(KEYCODE_F5, input_seq::not_code, KEYCODE_LCONTROL, input_seq::not_code, KEYCODE_LALT);
|
||||
break;
|
||||
|
||||
// leave everything else alone
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
83
src/osd/modules/input/input_windows.h
Normal file
83
src/osd/modules/input/input_windows.h
Normal file
@ -0,0 +1,83 @@
|
||||
// license:BSD-3-Clause
|
||||
// copyright-holders:Aaron Giles, Brad Hughes
|
||||
//============================================================
|
||||
//
|
||||
// input_windows.h - Common code used by Windows input modules
|
||||
//
|
||||
//============================================================
|
||||
|
||||
#ifndef INPUT_WIN_H_
|
||||
#define INPUT_WIN_H_
|
||||
|
||||
//============================================================
|
||||
// TYPEDEFS
|
||||
//============================================================
|
||||
|
||||
// state information for a keyboard
|
||||
struct keyboard_state
|
||||
{
|
||||
UINT8 state[MAX_KEYS];
|
||||
INT8 oldkey[MAX_KEYS];
|
||||
INT8 currkey[MAX_KEYS];
|
||||
};
|
||||
|
||||
// state information for a mouse (matches DIMOUSESTATE exactly)
|
||||
struct mouse_state
|
||||
{
|
||||
LONG lX;
|
||||
LONG lY;
|
||||
LONG lZ;
|
||||
BYTE rgbButtons[8];
|
||||
};
|
||||
|
||||
class wininput_module : public input_module_base
|
||||
{
|
||||
protected:
|
||||
bool m_global_inputs_enabled;
|
||||
|
||||
public:
|
||||
wininput_module(const char * type, const char * name)
|
||||
: input_module_base(type, name)
|
||||
{
|
||||
}
|
||||
|
||||
virtual bool should_hide_mouse()
|
||||
{
|
||||
if (winwindow_has_focus() // has focus
|
||||
&& (!video_config.windowed || !win_window_list->win_has_menu()) // not windowed or doesn't have a menu
|
||||
&& (input_enabled() && !input_paused()) // input enabled and not paused
|
||||
&& (mouse_enabled() || lightgun_enabled())) // either mouse or lightgun enabled in the core
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
virtual bool handle_input_event(input_event eventid, void* data)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
protected:
|
||||
|
||||
void before_poll(running_machine& machine) override
|
||||
{
|
||||
// periodically process events, in case they're not coming through
|
||||
// this also will make sure the mouse state is up-to-date
|
||||
winwindow_process_events_periodic(machine);
|
||||
}
|
||||
|
||||
bool should_poll_devices(running_machine &machine) override
|
||||
{
|
||||
return input_enabled() && (m_global_inputs_enabled || winwindow_has_focus());
|
||||
}
|
||||
};
|
||||
|
||||
//============================================================
|
||||
// INLINE FUNCTIONS
|
||||
//============================================================
|
||||
|
||||
INT32 generic_button_get_state(void *device_internal, void *item_internal);
|
||||
INT32 generic_axis_get_state(void *device_internal, void *item_internal);
|
||||
#endif
|
605
src/osd/modules/input/input_x11.cpp
Normal file
605
src/osd/modules/input/input_x11.cpp
Normal file
@ -0,0 +1,605 @@
|
||||
// license:BSD-3-Clause
|
||||
// copyright-holders:Olivier Galibert, R. Belmont, Brad Hughes
|
||||
//============================================================
|
||||
//
|
||||
// input_x11.cpp - X11 XLib/XInput routines
|
||||
//
|
||||
// SDLMAME by Olivier Galibert and R. Belmont
|
||||
//
|
||||
//============================================================
|
||||
|
||||
#include "input_module.h"
|
||||
#include "modules/osdmodule.h"
|
||||
|
||||
#if defined(SDLMAME_SDL2) && !defined(SDLMAME_WIN32) && defined(USE_XINPUT) && USE_XINPUT
|
||||
|
||||
// for X11 xinput
|
||||
#include <X11/Xlib.h>
|
||||
#include <X11/extensions/XInput.h>
|
||||
#include <X11/Xutil.h>
|
||||
|
||||
// standard sdl header
|
||||
#include "sdlinc.h"
|
||||
#include <ctype.h>
|
||||
#include <stddef.h>
|
||||
#include <mutex>
|
||||
#include <memory>
|
||||
#include <queue>
|
||||
#include <string>
|
||||
|
||||
// MAME headers
|
||||
#include "emu.h"
|
||||
#include "osdepend.h"
|
||||
|
||||
// MAMEOS headers
|
||||
#include "../lib/osdobj_common.h"
|
||||
#include "input_common.h"
|
||||
#include "../../sdl/osdsdl.h"
|
||||
#include "input_sdlcommon.h"
|
||||
|
||||
#define MAX_DEVMAP_ENTRIES 16
|
||||
|
||||
#define INVALID_EVENT_TYPE -1
|
||||
static int motion_type = INVALID_EVENT_TYPE;
|
||||
static int button_press_type = INVALID_EVENT_TYPE;
|
||||
static int button_release_type = INVALID_EVENT_TYPE;
|
||||
static int key_press_type = INVALID_EVENT_TYPE;
|
||||
static int key_release_type = INVALID_EVENT_TYPE;
|
||||
static int proximity_in_type = INVALID_EVENT_TYPE;
|
||||
static int proximity_out_type = INVALID_EVENT_TYPE;
|
||||
|
||||
// state information for a lightgun
|
||||
struct lightgun_state
|
||||
{
|
||||
INT32 lX, lY;
|
||||
INT32 buttons[MAX_BUTTONS];
|
||||
};
|
||||
|
||||
struct x11_api_state
|
||||
{
|
||||
XID deviceid; // X11 device id
|
||||
INT32 maxx, maxy;
|
||||
INT32 minx, miny;
|
||||
};
|
||||
|
||||
//============================================================
|
||||
// DEBUG MACROS
|
||||
//============================================================
|
||||
|
||||
#if defined(XINPUT_DEBUG) && XINPUT_DEBUG
|
||||
#define XI_DBG(format, ...) osd_printf_verbose(format, __VA_ARGS__)
|
||||
|
||||
#define print_motion_event(motion) print_motion_event_impl(motion)
|
||||
static inline void print_motion_event_impl(XDeviceMotionEvent *motion)
|
||||
{
|
||||
/*
|
||||
* print a lot of debug informations of the motion event(s).
|
||||
*/
|
||||
osd_printf_verbose(
|
||||
"XDeviceMotionEvent:\n"
|
||||
" type: %d\n"
|
||||
" serial: %lu\n"
|
||||
" send_event: %d\n"
|
||||
" display: %p\n"
|
||||
" window: --\n"
|
||||
" deviceid: %lu\n"
|
||||
" root: --\n"
|
||||
" subwindow: --\n"
|
||||
" time: --\n"
|
||||
" x: %d, y: %d\n"
|
||||
" x_root: %d, y_root: %d\n"
|
||||
" state: %u\n"
|
||||
" is_hint: %2.2X\n"
|
||||
" same_screen: %d\n"
|
||||
" device_state: %u\n"
|
||||
" axes_count: %2.2X\n"
|
||||
" first_axis: %2.2X\n"
|
||||
" axis_data[6]: {%d,%d,%d,%d,%d,%d}\n",
|
||||
motion->type,
|
||||
motion->serial,
|
||||
motion->send_event,
|
||||
motion->display,
|
||||
/* motion->window, */
|
||||
motion->deviceid,
|
||||
/* motion->root */
|
||||
/* motion->subwindow */
|
||||
/* motion->time, */
|
||||
motion->x, motion->y,
|
||||
motion->x_root, motion->y_root,
|
||||
motion->state,
|
||||
motion->is_hint,
|
||||
motion->same_screen,
|
||||
motion->device_state,
|
||||
motion->axes_count,
|
||||
motion->first_axis,
|
||||
motion->axis_data[0], motion->axis_data[1], motion->axis_data[2], motion->axis_data[3], motion->axis_data[4], motion->axis_data[5]
|
||||
);
|
||||
}
|
||||
#else
|
||||
#define XI_DBG(format, ...) while(0) {}
|
||||
#define print_motion_event(motion) while(0) {}
|
||||
#endif
|
||||
|
||||
//============================================================
|
||||
// lightgun helpers: copy-past from xinfo
|
||||
//============================================================
|
||||
|
||||
XDeviceInfo*
|
||||
find_device_info(Display *display,
|
||||
const char *name,
|
||||
bool only_extended)
|
||||
{
|
||||
XDeviceInfo *devices;
|
||||
XDeviceInfo *found = NULL;
|
||||
int loop;
|
||||
int num_devices;
|
||||
int len = strlen(name);
|
||||
bool is_id = true;
|
||||
XID id = (XID)-1;
|
||||
|
||||
for(loop = 0; loop < len; loop++)
|
||||
{
|
||||
if (!isdigit(name[loop]))
|
||||
{
|
||||
is_id = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (is_id)
|
||||
{
|
||||
id = atoi(name);
|
||||
}
|
||||
|
||||
devices = XListInputDevices(display, &num_devices);
|
||||
|
||||
for(loop = 0; loop < num_devices; loop++)
|
||||
{
|
||||
osd_printf_verbose("Evaluating device with name: %s\n", devices[loop].name);
|
||||
|
||||
// if only extended devices and our device isn't extended, skip
|
||||
if (only_extended && devices[loop].use < IsXExtensionDevice)
|
||||
continue;
|
||||
|
||||
// Adjust name to remove spaces for accurate comparison
|
||||
std::string name_no_space = remove_spaces(devices[loop].name);
|
||||
if ((!is_id && strcmp(name_no_space.c_str(), name) == 0)
|
||||
|| (is_id && devices[loop].id == id))
|
||||
{
|
||||
if (found)
|
||||
{
|
||||
osd_printf_verbose(
|
||||
"Warning: There are multiple devices named \"%s\".\n"
|
||||
"To ensure the correct one is selected, please use "
|
||||
"the device ID instead.\n\n", name);
|
||||
}
|
||||
else
|
||||
{
|
||||
found = &devices[loop];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return found;
|
||||
}
|
||||
|
||||
//Copypasted from xinfo
|
||||
static int
|
||||
register_events(
|
||||
Display *dpy,
|
||||
XDeviceInfo *info,
|
||||
const char *dev_name,
|
||||
bool handle_proximity)
|
||||
{
|
||||
int number = 0; /* number of events registered */
|
||||
XEventClass event_list[7];
|
||||
int i;
|
||||
XDevice * device;
|
||||
Window root_win;
|
||||
unsigned long screen;
|
||||
XInputClassInfo * ip;
|
||||
|
||||
screen = DefaultScreen(dpy);
|
||||
root_win = RootWindow(dpy, screen);
|
||||
|
||||
device = XOpenDevice(dpy, info->id);
|
||||
if (device == nullptr)
|
||||
{
|
||||
osd_printf_verbose("unable to open device %s\n", dev_name);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (device->num_classes > 0)
|
||||
{
|
||||
for (ip = device->classes, i = 0; i < info->num_classes; ip++, i++)
|
||||
{
|
||||
switch (ip->input_class)
|
||||
{
|
||||
case KeyClass:
|
||||
DeviceKeyPress(device, key_press_type, event_list[number]); number++;
|
||||
DeviceKeyRelease(device, key_release_type, event_list[number]); number++;
|
||||
break;
|
||||
|
||||
case ButtonClass:
|
||||
DeviceButtonPress(device, button_press_type, event_list[number]); number++;
|
||||
DeviceButtonRelease(device, button_release_type, event_list[number]); number++;
|
||||
break;
|
||||
|
||||
case ValuatorClass:
|
||||
DeviceMotionNotify(device, motion_type, event_list[number]); number++;
|
||||
osd_printf_verbose("Motion = %i\n",motion_type);
|
||||
if (handle_proximity)
|
||||
{
|
||||
ProximityIn(device, proximity_in_type, event_list[number]); number++;
|
||||
ProximityOut(device, proximity_out_type, event_list[number]); number++;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
osd_printf_verbose("unknown class\n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (XSelectExtensionEvent(dpy, root_win, event_list, number))
|
||||
{
|
||||
osd_printf_verbose("error selecting extended events\n");
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return number;
|
||||
}
|
||||
|
||||
//============================================================
|
||||
// x11_event_manager
|
||||
//============================================================
|
||||
|
||||
class x11_event_handler
|
||||
{
|
||||
public:
|
||||
virtual void handle_event(XEvent &xevent) = 0;
|
||||
};
|
||||
|
||||
class x11_event_manager : public event_manager_t<x11_event_handler>
|
||||
{
|
||||
private:
|
||||
Display * m_display;
|
||||
|
||||
x11_event_manager()
|
||||
: event_manager_t(),
|
||||
m_display(nullptr)
|
||||
{
|
||||
}
|
||||
public:
|
||||
Display * display() { return m_display; }
|
||||
|
||||
static x11_event_manager& instance()
|
||||
{
|
||||
static x11_event_manager s_instance;
|
||||
return s_instance;
|
||||
}
|
||||
|
||||
int initialize()
|
||||
{
|
||||
std::lock_guard<std::mutex> scope_lock(m_lock);
|
||||
|
||||
if (m_display != nullptr)
|
||||
return 0;
|
||||
|
||||
m_display = XOpenDisplay(NULL);
|
||||
if (m_display == nullptr)
|
||||
{
|
||||
osd_printf_verbose("Unable to connect to X server\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
XExtensionVersion *version = XGetExtensionVersion(m_display, INAME);
|
||||
if (!version || (version == (XExtensionVersion*)NoSuchExtension))
|
||||
{
|
||||
osd_printf_verbose("xinput extension not available!\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void process_events(running_machine &machine) override
|
||||
{
|
||||
std::lock_guard<std::mutex> scope_lock(m_lock);
|
||||
XEvent xevent;
|
||||
|
||||
//Get XInput events
|
||||
while (XPending(m_display) != 0)
|
||||
{
|
||||
XNextEvent(m_display, &xevent);
|
||||
|
||||
// Find all subscribers for the event type
|
||||
auto subscribers = m_subscription_index.equal_range(xevent.type);
|
||||
|
||||
// Dispatch the events
|
||||
for (auto iter = subscribers.first; iter != subscribers.second; iter++)
|
||||
iter->second->handle_event(xevent);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
//============================================================
|
||||
// x11_input_device
|
||||
//============================================================
|
||||
|
||||
class x11_input_device : public event_based_device<XEvent>
|
||||
{
|
||||
public:
|
||||
x11_api_state x11_state;
|
||||
|
||||
x11_input_device(running_machine &machine, const char* name, input_device_class devclass, input_module &module)
|
||||
: event_based_device(machine, name, devclass, module),
|
||||
x11_state({0})
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
//============================================================
|
||||
// x11_lightgun_device
|
||||
//============================================================
|
||||
|
||||
class x11_lightgun_device : public x11_input_device
|
||||
{
|
||||
public:
|
||||
lightgun_state lightgun;
|
||||
|
||||
x11_lightgun_device(running_machine &machine, const char* name, input_module &module)
|
||||
: x11_input_device(machine, name, DEVICE_CLASS_LIGHTGUN, module),
|
||||
lightgun({0})
|
||||
{
|
||||
}
|
||||
|
||||
void process_event(XEvent &xevent) override
|
||||
{
|
||||
if (xevent.type == motion_type)
|
||||
{
|
||||
XDeviceMotionEvent *motion = (XDeviceMotionEvent *)&xevent;
|
||||
print_motion_event(motion);
|
||||
|
||||
/*
|
||||
* We have to check with axis will start on array index 0.
|
||||
* We have also to check the number of axes that are stored in the array.
|
||||
*/
|
||||
switch (motion->first_axis)
|
||||
{
|
||||
/*
|
||||
* Starting with x, check number of axis, if there is also the y axis stored.
|
||||
*/
|
||||
case 0:
|
||||
if (motion->axes_count >= 1)
|
||||
{
|
||||
lightgun.lX = normalize_absolute_axis(motion->axis_data[0], x11_state.minx, x11_state.maxx);
|
||||
if (motion->axes_count >= 2)
|
||||
{
|
||||
lightgun.lY = normalize_absolute_axis(motion->axis_data[1], x11_state.miny, x11_state.maxy);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
/*
|
||||
* Starting with y, ...
|
||||
*/
|
||||
case 1:
|
||||
if (motion->axes_count >= 1)
|
||||
{
|
||||
lightgun.lY = normalize_absolute_axis(motion->axis_data[0], x11_state.miny, x11_state.maxy);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (xevent.type == button_press_type || xevent.type == button_release_type)
|
||||
{
|
||||
XDeviceButtonEvent *button = (XDeviceButtonEvent *)&xevent;
|
||||
lightgun.buttons[button->button] = (xevent.type == button_press_type) ? 0x80 : 0;
|
||||
}
|
||||
}
|
||||
|
||||
void reset() override
|
||||
{
|
||||
memset(&lightgun, 0, sizeof(lightgun));
|
||||
}
|
||||
};
|
||||
|
||||
//============================================================
|
||||
// x11_lightgun_module
|
||||
//============================================================
|
||||
|
||||
class x11_lightgun_module : public input_module_base, public x11_event_handler
|
||||
{
|
||||
private:
|
||||
device_map_t m_lightgun_map;
|
||||
Display * m_display;
|
||||
public:
|
||||
x11_lightgun_module()
|
||||
: input_module_base(OSD_LIGHTGUNINPUT_PROVIDER, "x11")
|
||||
{
|
||||
}
|
||||
|
||||
void input_init(running_machine &machine) override
|
||||
{
|
||||
int index;
|
||||
|
||||
osd_printf_verbose("Lightgun: Begin initialization\n");
|
||||
|
||||
devmap_init(machine, &m_lightgun_map, SDLOPTION_LIGHTGUNINDEX, 8, "Lightgun mapping");
|
||||
|
||||
x11_event_manager::instance().initialize();
|
||||
m_display = x11_event_manager::instance().display();
|
||||
|
||||
// Loop through all 8 possible devices
|
||||
for (index = 0; index < 8; index++)
|
||||
{
|
||||
XDeviceInfo *info;
|
||||
|
||||
// Skip if the name is empty
|
||||
if (m_lightgun_map.map[index].name.length() == 0)
|
||||
continue;
|
||||
|
||||
x11_lightgun_device *devinfo;
|
||||
std::string const &name = m_lightgun_map.map[index].name;
|
||||
char defname[512];
|
||||
|
||||
// Register and add the device
|
||||
devinfo = create_lightgun_device(machine, index);
|
||||
osd_printf_verbose("%i: %s\n", index, name.c_str());
|
||||
|
||||
// Find the device info associated with the name
|
||||
info = find_device_info(m_display, name.c_str(), 0);
|
||||
|
||||
// If we couldn't find the device, skip
|
||||
if (info == nullptr)
|
||||
{
|
||||
osd_printf_verbose("Can't find device %s!\n", name.c_str());
|
||||
continue;
|
||||
}
|
||||
|
||||
//Grab device info and translate to stuff mame can use
|
||||
if (info->num_classes > 0)
|
||||
{
|
||||
// Add the lightgun buttons based on what we read
|
||||
add_lightgun_buttons((XAnyClassPtr)info->inputclassinfo, info->num_classes, devinfo);
|
||||
|
||||
// Also, set the axix min/max ranges if we got them
|
||||
set_lightgun_axis_props((XAnyClassPtr)info->inputclassinfo, info->num_classes, devinfo);
|
||||
}
|
||||
|
||||
// Add X and Y axis
|
||||
sprintf(defname, "X %s", devinfo->name());
|
||||
devinfo->device()->add_item(defname, ITEM_ID_XAXIS, generic_axis_get_state, &devinfo->lightgun.lX);
|
||||
|
||||
sprintf(defname, "Y %s", devinfo->name());
|
||||
devinfo->device()->add_item(defname, ITEM_ID_YAXIS, generic_axis_get_state, &devinfo->lightgun.lY);
|
||||
|
||||
// Save the device id
|
||||
devinfo->x11_state.deviceid = info->id;
|
||||
|
||||
// Register this device to receive event notifications
|
||||
int events_registered = register_events(m_display, info, m_lightgun_map.map[index].name.c_str(), 0);
|
||||
osd_printf_verbose("Device %i: Registered %i events.\n", (int)info->id, events_registered);
|
||||
|
||||
// register ourself to handle events from event manager
|
||||
int event_types[] = { motion_type, button_press_type, button_release_type };
|
||||
osd_printf_verbose("Events types to register: motion:%d, press:%d, release:%d\n", motion_type, button_press_type, button_release_type);
|
||||
x11_event_manager::instance().subscribe(event_types, ARRAY_LENGTH(event_types), this);
|
||||
}
|
||||
|
||||
osd_printf_verbose("Lightgun: End initialization\n");
|
||||
}
|
||||
|
||||
bool should_poll_devices(running_machine &machine) override
|
||||
{
|
||||
return sdl_event_manager::instance().app_has_mouse_focus();
|
||||
}
|
||||
|
||||
void before_poll(running_machine &machine) override
|
||||
{
|
||||
if (!should_poll_devices(machine))
|
||||
return;
|
||||
|
||||
// Tell the event manager to process events and push them to the devices
|
||||
x11_event_manager::instance().process_events(machine);
|
||||
|
||||
// Also trigger the SDL event manager so it can process window events
|
||||
sdl_event_manager::instance().process_events(machine);
|
||||
}
|
||||
|
||||
void handle_event(XEvent &xevent) override
|
||||
{
|
||||
for (int i = 0; i < devicelist()->size(); i++)
|
||||
{
|
||||
downcast<x11_input_device*>(devicelist()->at(i))->queue_events(&xevent, 1);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
x11_lightgun_device* create_lightgun_device(running_machine &machine, int index)
|
||||
{
|
||||
x11_lightgun_device *devinfo = nullptr;
|
||||
char tempname[20];
|
||||
|
||||
if (m_lightgun_map.map[index].name.length() == 0)
|
||||
{
|
||||
if (m_lightgun_map.initialized)
|
||||
{
|
||||
snprintf(tempname, ARRAY_LENGTH(tempname), "NC%d", index);
|
||||
devinfo = devicelist()->create_device<x11_lightgun_device>(machine, tempname, *this);
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
else
|
||||
{
|
||||
devinfo = devicelist()->create_device<x11_lightgun_device>(machine, m_lightgun_map.map[index].name.c_str(), *this);
|
||||
}
|
||||
|
||||
return devinfo;
|
||||
}
|
||||
|
||||
void add_lightgun_buttons(XAnyClassPtr first_info_class, int num_classes, x11_lightgun_device *devinfo)
|
||||
{
|
||||
XAnyClassPtr any = first_info_class;
|
||||
|
||||
for (int i = 0; i < num_classes; i++)
|
||||
{
|
||||
switch (any->c_class)
|
||||
{
|
||||
case ButtonClass:
|
||||
XButtonInfoPtr b = (XButtonInfoPtr)any;
|
||||
for (int button = 0; button < b->num_buttons; button++)
|
||||
{
|
||||
input_item_id itemid = (input_item_id)(ITEM_ID_BUTTON1 + button);
|
||||
devinfo->device()->add_item(default_button_name(button), itemid, generic_button_get_state, &devinfo->lightgun.buttons[button]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
any = (XAnyClassPtr)((char *)any + any->length);
|
||||
}
|
||||
}
|
||||
|
||||
void set_lightgun_axis_props(XAnyClassPtr first_info_class, int num_classes, x11_lightgun_device *devinfo)
|
||||
{
|
||||
XAnyClassPtr any = first_info_class;
|
||||
|
||||
for (int i = 0; i < num_classes; i++)
|
||||
{
|
||||
switch (any->c_class)
|
||||
{
|
||||
case ValuatorClass:
|
||||
XValuatorInfoPtr valuator_info = (XValuatorInfoPtr)any;
|
||||
XAxisInfoPtr axis_info = (XAxisInfoPtr)((char *)valuator_info + sizeof(XValuatorInfo));
|
||||
for (int j = 0; j < valuator_info->num_axes; j++, axis_info++)
|
||||
{
|
||||
if (j == 0)
|
||||
{
|
||||
XI_DBG("Set minx=%d, maxx=%d\n", axis_info->min_value, axis_info->max_value);
|
||||
devinfo->x11_state.maxx = axis_info->max_value;
|
||||
devinfo->x11_state.minx = axis_info->min_value;
|
||||
}
|
||||
|
||||
if (j == 1)
|
||||
{
|
||||
XI_DBG("Set miny=%d, maxy=%d\n", axis_info->min_value, axis_info->max_value);
|
||||
devinfo->x11_state.maxy = axis_info->max_value;
|
||||
devinfo->x11_state.miny = axis_info->min_value;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
any = (XAnyClassPtr)((char *)any + any->length);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
#else
|
||||
MODULE_NOT_SUPPORTED(x11_lightgun_module, OSD_LIGHTGUNINPUT_PROVIDER, "x11")
|
||||
#endif
|
||||
|
||||
MODULE_DEFINITION(LIGHTGUN_X11, x11_lightgun_module)
|
@ -25,6 +25,12 @@ const options_entry osd_options::s_option_entries[] =
|
||||
{ nullptr, nullptr, OPTION_HEADER, "OSD FONT OPTIONS" },
|
||||
{ OSD_FONT_PROVIDER, OSDOPTVAL_AUTO, OPTION_STRING, "provider for ui font: " },
|
||||
|
||||
{ nullptr, nullptr, OPTION_HEADER, "OSD INPUT OPTIONS" },
|
||||
{ OSD_KEYBOARDINPUT_PROVIDER, OSDOPTVAL_AUTO, OPTION_STRING, "provider for keyboard input: " },
|
||||
{ OSD_MOUSEINPUT_PROVIDER, OSDOPTVAL_AUTO, OPTION_STRING, "provider for mouse input: " },
|
||||
{ OSD_LIGHTGUNINPUT_PROVIDER, OSDOPTVAL_AUTO, OPTION_STRING, "provider for lightgun input: " },
|
||||
{ OSD_JOYSTICKINPUT_PROVIDER, OSDOPTVAL_AUTO, OPTION_STRING, "provider for joystick input: " },
|
||||
|
||||
{ nullptr, nullptr, OPTION_HEADER, "OSD CLI OPTIONS" },
|
||||
{ OSDCOMMAND_LIST_MIDI_DEVICES ";mlist", "0", OPTION_COMMAND, "list available MIDI I/O devices" },
|
||||
{ OSDCOMMAND_LIST_NETWORK_ADAPTERS ";nlist", "0", OPTION_COMMAND, "list available network adapters" },
|
||||
@ -155,7 +161,11 @@ osd_common_t::osd_common_t(osd_options &options)
|
||||
m_options(options),
|
||||
m_print_verbose(false),
|
||||
m_sound(nullptr),
|
||||
m_debugger(nullptr)
|
||||
m_debugger(nullptr),
|
||||
m_keyboard_input(nullptr),
|
||||
m_mouse_input(nullptr),
|
||||
m_lightgun_input(nullptr),
|
||||
m_joystick_input(nullptr)
|
||||
{
|
||||
osd_output::push(this);
|
||||
}
|
||||
@ -207,6 +217,26 @@ void osd_common_t::register_options()
|
||||
#endif
|
||||
REGISTER_MODULE(m_mod_man, MIDI_NONE);
|
||||
|
||||
REGISTER_MODULE(m_mod_man, KEYBOARDINPUT_SDL);
|
||||
REGISTER_MODULE(m_mod_man, KEYBOARDINPUT_RAWINPUT);
|
||||
REGISTER_MODULE(m_mod_man, KEYBOARDINPUT_DINPUT);
|
||||
REGISTER_MODULE(m_mod_man, KEYBOARDINPUT_WIN32);
|
||||
REGISTER_MODULE(m_mod_man, KEYBOARD_NONE);
|
||||
|
||||
REGISTER_MODULE(m_mod_man, MOUSEINPUT_SDL);
|
||||
REGISTER_MODULE(m_mod_man, MOUSEINPUT_RAWINPUT);
|
||||
REGISTER_MODULE(m_mod_man, MOUSEINPUT_DINPUT);
|
||||
REGISTER_MODULE(m_mod_man, MOUSEINPUT_WIN32);
|
||||
REGISTER_MODULE(m_mod_man, MOUSE_NONE);
|
||||
|
||||
REGISTER_MODULE(m_mod_man, LIGHTGUN_X11);
|
||||
REGISTER_MODULE(m_mod_man, LIGHTGUNINPUT_WIN32);
|
||||
REGISTER_MODULE(m_mod_man, LIGHTGUN_NONE);
|
||||
|
||||
REGISTER_MODULE(m_mod_man, JOYSTICKINPUT_SDL);
|
||||
REGISTER_MODULE(m_mod_man, JOYSTICKINPUT_DINPUT);
|
||||
REGISTER_MODULE(m_mod_man, JOYSTICK_NONE);
|
||||
|
||||
// after initialization we know which modules are supported
|
||||
|
||||
const char *names[20];
|
||||
@ -217,6 +247,30 @@ void osd_common_t::register_options()
|
||||
dnames.push_back(names[i]);
|
||||
update_option(OSD_FONT_PROVIDER, dnames);
|
||||
|
||||
m_mod_man.get_module_names(OSD_KEYBOARDINPUT_PROVIDER, 20, &num, names);
|
||||
dnames.clear();
|
||||
for (int i = 0; i < num; i++)
|
||||
dnames.push_back(names[i]);
|
||||
update_option(OSD_KEYBOARDINPUT_PROVIDER, dnames);
|
||||
|
||||
m_mod_man.get_module_names(OSD_MOUSEINPUT_PROVIDER, 20, &num, names);
|
||||
dnames.clear();
|
||||
for (int i = 0; i < num; i++)
|
||||
dnames.push_back(names[i]);
|
||||
update_option(OSD_MOUSEINPUT_PROVIDER, dnames);
|
||||
|
||||
m_mod_man.get_module_names(OSD_LIGHTGUNINPUT_PROVIDER, 20, &num, names);
|
||||
dnames.clear();
|
||||
for (int i = 0; i < num; i++)
|
||||
dnames.push_back(names[i]);
|
||||
update_option(OSD_LIGHTGUNINPUT_PROVIDER, dnames);
|
||||
|
||||
m_mod_man.get_module_names(OSD_JOYSTICKINPUT_PROVIDER, 20, &num, names);
|
||||
dnames.clear();
|
||||
for (int i = 0; i < num; i++)
|
||||
dnames.push_back(names[i]);
|
||||
update_option(OSD_JOYSTICKINPUT_PROVIDER, dnames);
|
||||
|
||||
m_mod_man.get_module_names(OSD_SOUND_PROVIDER, 20, &num, names);
|
||||
dnames.clear();
|
||||
for (int i = 0; i < num; i++)
|
||||
@ -545,15 +599,14 @@ void osd_common_t::init_subsystems()
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
input_init();
|
||||
// we need pause callbacks
|
||||
machine().add_notifier(MACHINE_NOTIFY_PAUSE, machine_notify_delegate(FUNC(osd_common_t::input_pause), this));
|
||||
machine().add_notifier(MACHINE_NOTIFY_RESUME, machine_notify_delegate(FUNC(osd_common_t::input_resume), this));
|
||||
|
||||
output_init();
|
||||
|
||||
m_font_module = select_module_options<font_module *>(options(), OSD_FONT_PROVIDER);
|
||||
m_keyboard_input = select_module_options<input_module *>(options(), OSD_KEYBOARDINPUT_PROVIDER);
|
||||
m_mouse_input = select_module_options<input_module *>(options(), OSD_MOUSEINPUT_PROVIDER);
|
||||
m_lightgun_input = select_module_options<input_module *>(options(), OSD_LIGHTGUNINPUT_PROVIDER);
|
||||
m_joystick_input = select_module_options<input_module *>(options(), OSD_JOYSTICKINPUT_PROVIDER);
|
||||
|
||||
m_font_module = select_module_options<font_module *>(options(), OSD_FONT_PROVIDER);
|
||||
m_sound = select_module_options<sound_module *>(options(), OSD_SOUND_PROVIDER);
|
||||
m_sound->m_sample_rate = options().sample_rate();
|
||||
m_sound->m_audio_latency = options().audio_latency();
|
||||
@ -566,6 +619,10 @@ void osd_common_t::init_subsystems()
|
||||
|
||||
m_mod_man.init(options());
|
||||
|
||||
input_init();
|
||||
// we need pause callbacks
|
||||
machine().add_notifier(MACHINE_NOTIFY_PAUSE, machine_notify_delegate(FUNC(osd_common_t::input_pause), this));
|
||||
machine().add_notifier(MACHINE_NOTIFY_RESUME, machine_notify_delegate(FUNC(osd_common_t::input_resume), this));
|
||||
}
|
||||
|
||||
bool osd_common_t::video_init()
|
||||
@ -589,15 +646,27 @@ void osd_common_t::video_register()
|
||||
|
||||
bool osd_common_t::input_init()
|
||||
{
|
||||
m_keyboard_input->input_init(machine());
|
||||
m_mouse_input->input_init(machine());
|
||||
m_lightgun_input->input_init(machine());
|
||||
m_joystick_input->input_init(machine());
|
||||
return true;
|
||||
}
|
||||
|
||||
void osd_common_t::input_pause()
|
||||
{
|
||||
m_keyboard_input->pause();
|
||||
m_mouse_input->pause();
|
||||
m_lightgun_input->pause();
|
||||
m_joystick_input->pause();
|
||||
}
|
||||
|
||||
void osd_common_t::input_resume()
|
||||
{
|
||||
m_keyboard_input->resume();
|
||||
m_mouse_input->resume();
|
||||
m_lightgun_input->resume();
|
||||
m_joystick_input->resume();
|
||||
}
|
||||
|
||||
bool osd_common_t::output_init()
|
||||
@ -622,6 +691,10 @@ void osd_common_t::window_exit()
|
||||
|
||||
void osd_common_t::input_exit()
|
||||
{
|
||||
m_keyboard_input->exit();
|
||||
m_mouse_input->exit();
|
||||
m_lightgun_input->exit();
|
||||
m_joystick_input->exit();
|
||||
}
|
||||
|
||||
void osd_common_t::output_exit()
|
||||
|
@ -16,6 +16,7 @@
|
||||
#include "osdepend.h"
|
||||
#include "modules/osdmodule.h"
|
||||
#include "modules/font/font_module.h"
|
||||
#include "modules/input/input_module.h"
|
||||
#include "modules/sound/sound_module.h"
|
||||
#include "modules/debugger/debug_module.h"
|
||||
#include "modules/netdev/netdev_module.h"
|
||||
@ -269,6 +270,10 @@ protected:
|
||||
sound_module* m_sound;
|
||||
debug_module* m_debugger;
|
||||
midi_module* m_midi;
|
||||
input_module* m_keyboard_input;
|
||||
input_module* m_mouse_input;
|
||||
input_module* m_lightgun_input;
|
||||
input_module* m_joystick_input;
|
||||
private:
|
||||
std::vector<const char *> m_video_names;
|
||||
};
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -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__ */
|
@ -149,18 +149,28 @@ public:
|
||||
|
||||
virtual bool video_init() override;
|
||||
virtual bool window_init() override;
|
||||
#ifdef USE_OLD_SDL_INPUT
|
||||
virtual bool input_init() override;
|
||||
virtual void input_pause() override;
|
||||
virtual void input_resume() override;
|
||||
#endif
|
||||
virtual bool output_init() override;
|
||||
//virtual bool midi_init();
|
||||
|
||||
virtual void video_exit() override;
|
||||
virtual void window_exit() override;
|
||||
#ifdef USE_OLD_SDL_INPUT
|
||||
virtual void input_exit() override;
|
||||
#endif
|
||||
virtual void output_exit() override;
|
||||
//virtual void midi_exit();
|
||||
|
||||
// sdl specific
|
||||
void poll_inputs(running_machine &machine);
|
||||
void release_keys();
|
||||
bool should_hide_mouse();
|
||||
void process_events_buf();
|
||||
|
||||
sdl_options &options() { return m_options; }
|
||||
|
||||
private:
|
||||
|
@ -42,7 +42,6 @@
|
||||
|
||||
// OSD headers
|
||||
#include "video.h"
|
||||
#include "input.h"
|
||||
#include "osdsdl.h"
|
||||
#include "modules/lib/osdlib.h"
|
||||
|
||||
@ -524,3 +523,4 @@ void sdl_osd_interface::init(running_machine &machine)
|
||||
SDL_EventState(SDL_TEXTINPUT, SDL_TRUE);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
@ -20,7 +20,6 @@
|
||||
// MAMEOS headers
|
||||
#include "video.h"
|
||||
#include "window.h"
|
||||
#include "input.h"
|
||||
#include "osdsdl.h"
|
||||
#include "modules/lib/osdlib.h"
|
||||
|
||||
@ -163,7 +162,8 @@ void sdl_osd_interface::update(bool skip_redraw)
|
||||
}
|
||||
|
||||
// poll the joystick values here
|
||||
sdlinput_poll(machine());
|
||||
downcast<sdl_osd_interface&>(machine().osd()).poll_inputs(machine());
|
||||
|
||||
check_osd_inputs(machine());
|
||||
// if we're running, disable some parts of the debugger
|
||||
if ((machine().debug_flags & DEBUG_FLAG_OSD_ENABLED) != 0)
|
||||
@ -286,7 +286,12 @@ finishit:
|
||||
|
||||
static void check_osd_inputs(running_machine &machine)
|
||||
{
|
||||
#ifdef USE_OLD_SDL_INPUT
|
||||
sdl_window_info *window = sdlinput_get_focus_window();
|
||||
#else
|
||||
// BUG: TODO: Fix focus window support
|
||||
sdl_window_info *window = sdl_window_list;
|
||||
#endif
|
||||
|
||||
// check for toggling fullscreen mode
|
||||
if (machine.ui_input().pressed(IPT_OSD_1))
|
||||
|
@ -34,7 +34,6 @@
|
||||
// OSD headers
|
||||
|
||||
#include "window.h"
|
||||
#include "input.h"
|
||||
#include "osdsdl.h"
|
||||
#include "modules/render/drawbgfx.h"
|
||||
#include "modules/render/drawsdl.h"
|
||||
@ -250,14 +249,14 @@ bool sdl_osd_interface::window_init()
|
||||
if (renderer_sdl2::init(machine()))
|
||||
{
|
||||
video_config.mode = VIDEO_MODE_SOFT;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (video_config.mode == VIDEO_MODE_SOFT)
|
||||
{
|
||||
if (renderer_sdl1::init(machine()))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* We may want to set a number of the hints SDL2 provides.
|
||||
@ -579,7 +578,8 @@ OSDWORK_CALLBACK( sdl_window_info::sdlwindow_toggle_full_screen_wt )
|
||||
SDL_SetWindowFullscreen(window->sdl_window(), SDL_WINDOW_FULLSCREEN); // Try to set mode
|
||||
}
|
||||
SDL_DestroyWindow(window->sdl_window());
|
||||
sdlinput_release_keys();
|
||||
|
||||
downcast<sdl_osd_interface &>(window->machine().osd()).release_keys();
|
||||
|
||||
window->set_renderer(osd_renderer::make_for_type(video_config.mode, reinterpret_cast<osd_window *>(window)));
|
||||
|
||||
@ -651,7 +651,12 @@ void sdl_window_info::update_cursor_state()
|
||||
{
|
||||
//FIXME: SDL1.3: really broken: the whole SDL code
|
||||
// will only work correct with relative mouse movements ...
|
||||
if (!fullscreen() && !sdlinput_should_hide_mouse())
|
||||
#ifdef USE_OLD_SDL_INPUT
|
||||
bool should_hide_mouse = sdlinput_should_hide_mouse();
|
||||
#else
|
||||
bool should_hide_mouse = downcast<sdl_osd_interface&>(machine().osd()).should_hide_mouse();
|
||||
#endif
|
||||
if (!fullscreen() && !should_hide_mouse)
|
||||
{
|
||||
SDL_ShowCursor(SDL_ENABLE);
|
||||
if (SDL_GetWindowGrab(sdl_window() ))
|
||||
@ -666,7 +671,7 @@ void sdl_window_info::update_cursor_state()
|
||||
SDL_SetRelativeMouseMode(SDL_TRUE);
|
||||
}
|
||||
SDL_SetCursor(nullptr); // Force an update in case the underlying driver has changed visibility
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -775,7 +780,11 @@ OSDWORK_CALLBACK( sdl_window_info::sdlwindow_video_window_destroy_wt )
|
||||
}
|
||||
SDL_DestroyWindow(window->sdl_window());
|
||||
// release all keys ...
|
||||
#ifdef USE_OLD_SDL_INPUT
|
||||
sdlinput_release_keys();
|
||||
#else
|
||||
downcast<sdl_osd_interface &>(window->machine().osd()).release_keys();
|
||||
#endif
|
||||
|
||||
|
||||
osd_free(wp);
|
||||
@ -1119,11 +1128,11 @@ OSDWORK_CALLBACK( sdl_window_info::complete_create_wt )
|
||||
for (auto w = sdl_window_list; w != nullptr; w = w->m_next)
|
||||
{
|
||||
if (w->m_index == 0)
|
||||
{
|
||||
{
|
||||
window->m_main = w;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
window->monitor()->refresh();
|
||||
// initialize the drawing backend
|
||||
@ -1194,7 +1203,11 @@ OSDWORK_CALLBACK( sdl_window_info::draw_video_contents_wt )
|
||||
ASSERT_REDRAW_THREAD();
|
||||
|
||||
// Some configurations require events to be polled in the worker thread
|
||||
#ifdef USE_OLD_SDL_INPUT
|
||||
sdlinput_process_events_buf();
|
||||
#else
|
||||
downcast< sdl_osd_interface& >(window->machine().osd()).process_events_buf();
|
||||
#endif
|
||||
|
||||
// Check whether window has vector screens
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -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 */
|
||||
|
||||
|
||||
|
@ -206,7 +206,7 @@ void windows_osd_interface::update(bool skip_redraw)
|
||||
|
||||
// poll the joystick values here
|
||||
winwindow_process_events(machine(), TRUE, FALSE);
|
||||
wininput_poll(machine());
|
||||
poll_input(machine());
|
||||
check_osd_inputs(machine());
|
||||
// if we're running, disable some parts of the debugger
|
||||
if ((machine().debug_flags & DEBUG_FLAG_OSD_ENABLED) != 0)
|
||||
|
@ -36,6 +36,12 @@
|
||||
#include "modules/render/drawogl.h"
|
||||
#endif
|
||||
|
||||
#define NOT_ALREADY_DOWN(x) (x & 0x40000000) == 0
|
||||
#define SCAN_CODE(x) ((x >> 16) & 0xff)
|
||||
#define IS_EXTENDED(x) (0x01000000 & x)
|
||||
#define MAKE_DI_SCAN(scan, isextended) (scan & 0x7f) | (isextended ? 0x80 : 0x00)
|
||||
#define WINOSD(machine) downcast<windows_osd_interface*>(&machine.osd())
|
||||
|
||||
//============================================================
|
||||
// PARAMETERS
|
||||
//============================================================
|
||||
@ -188,7 +194,7 @@ bool windows_osd_interface::window_init()
|
||||
fatalerror("Failed to create window thread ready event\n");
|
||||
|
||||
// create a thread to run the windows from
|
||||
temp = _beginthreadex(nullptr, 0, win_window_info::thread_entry, nullptr, 0, (unsigned *)&window_threadid);
|
||||
temp = _beginthreadex(nullptr, 0, win_window_info::thread_entry, this, 0, (unsigned *)&window_threadid);
|
||||
window_thread = (HANDLE)temp;
|
||||
if (window_thread == nullptr)
|
||||
fatalerror("Failed to create window thread\n");
|
||||
@ -225,7 +231,7 @@ bool windows_osd_interface::window_init()
|
||||
{
|
||||
bool error = false;
|
||||
switch(current_mode)
|
||||
{
|
||||
{
|
||||
case VIDEO_MODE_NONE:
|
||||
error = renderer_none::init(machine());
|
||||
break;
|
||||
@ -401,7 +407,7 @@ win_window_info::~win_window_info()
|
||||
if (m_renderer != nullptr)
|
||||
{
|
||||
delete m_renderer;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -437,7 +443,31 @@ static BOOL is_mame_window(HWND hwnd)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
inline static BOOL handle_mouse_button(windows_osd_interface *osd, int button, int down, int x, int y)
|
||||
{
|
||||
MouseButtonEventArgs args;
|
||||
args.button = button;
|
||||
args.keydown = down;
|
||||
args.xpos = x;
|
||||
args.ypos = y;
|
||||
|
||||
bool handled = osd->handle_input_event(INPUT_EVENT_MOUSE_BUTTON, &args);
|
||||
|
||||
// When in lightgun mode or mouse mode, the mouse click may be routed to the input system
|
||||
// because the mouse interactions in the UI are routed from the video_window_proc below
|
||||
// we need to make sure they aren't suppressed in these cases.
|
||||
return handled && !osd->options().lightgun() && !osd->options().mouse();
|
||||
}
|
||||
|
||||
inline static BOOL handle_keypress(windows_osd_interface *osd, int vkey, int down, int scancode, BOOL extended_key)
|
||||
{
|
||||
KeyPressEventArgs args;
|
||||
args.event_id = down ? INPUT_EVENT_KEYDOWN : INPUT_EVENT_KEYUP;
|
||||
args.scancode = MAKE_DI_SCAN(scancode, extended_key);
|
||||
args.vkey = vkey;
|
||||
|
||||
return osd->handle_input_event(args.event_id, &args);
|
||||
}
|
||||
|
||||
//============================================================
|
||||
// winwindow_process_events
|
||||
@ -478,36 +508,45 @@ void winwindow_process_events(running_machine &machine, int ingame, bool nodispa
|
||||
|
||||
// forward mouse button downs to the input system
|
||||
case WM_LBUTTONDOWN:
|
||||
dispatch = !wininput_handle_mouse_button(0, TRUE, GET_X_LPARAM(message.lParam), GET_Y_LPARAM(message.lParam));
|
||||
dispatch = !handle_mouse_button(WINOSD(machine), 0, TRUE, GET_X_LPARAM(message.lParam), GET_Y_LPARAM(message.lParam));
|
||||
break;
|
||||
|
||||
case WM_RBUTTONDOWN:
|
||||
dispatch = !wininput_handle_mouse_button(1, TRUE, GET_X_LPARAM(message.lParam), GET_Y_LPARAM(message.lParam));
|
||||
dispatch = !handle_mouse_button(WINOSD(machine), 1, TRUE, GET_X_LPARAM(message.lParam), GET_Y_LPARAM(message.lParam));
|
||||
break;
|
||||
|
||||
case WM_MBUTTONDOWN:
|
||||
dispatch = !wininput_handle_mouse_button(2, TRUE, GET_X_LPARAM(message.lParam), GET_Y_LPARAM(message.lParam));
|
||||
dispatch = !handle_mouse_button(WINOSD(machine), 2, TRUE, GET_X_LPARAM(message.lParam), GET_Y_LPARAM(message.lParam));
|
||||
break;
|
||||
|
||||
case WM_XBUTTONDOWN:
|
||||
dispatch = !wininput_handle_mouse_button(3, TRUE, GET_X_LPARAM(message.lParam), GET_Y_LPARAM(message.lParam));
|
||||
dispatch = !handle_mouse_button(WINOSD(machine), 3, TRUE, GET_X_LPARAM(message.lParam), GET_Y_LPARAM(message.lParam));
|
||||
break;
|
||||
|
||||
// forward mouse button ups to the input system
|
||||
case WM_LBUTTONUP:
|
||||
dispatch = !wininput_handle_mouse_button(0, FALSE, GET_X_LPARAM(message.lParam), GET_Y_LPARAM(message.lParam));
|
||||
dispatch = !handle_mouse_button(WINOSD(machine), 0, FALSE, GET_X_LPARAM(message.lParam), GET_Y_LPARAM(message.lParam));
|
||||
break;
|
||||
|
||||
case WM_RBUTTONUP:
|
||||
dispatch = !wininput_handle_mouse_button(1, FALSE, GET_X_LPARAM(message.lParam), GET_Y_LPARAM(message.lParam));
|
||||
dispatch = !handle_mouse_button(WINOSD(machine), 1, FALSE, GET_X_LPARAM(message.lParam), GET_Y_LPARAM(message.lParam));
|
||||
break;
|
||||
|
||||
case WM_MBUTTONUP:
|
||||
dispatch = !wininput_handle_mouse_button(2, FALSE, GET_X_LPARAM(message.lParam), GET_Y_LPARAM(message.lParam));
|
||||
dispatch = !handle_mouse_button(WINOSD(machine), 2, FALSE, GET_X_LPARAM(message.lParam), GET_Y_LPARAM(message.lParam));
|
||||
break;
|
||||
|
||||
case WM_XBUTTONUP:
|
||||
dispatch = !wininput_handle_mouse_button(3, FALSE, GET_X_LPARAM(message.lParam), GET_Y_LPARAM(message.lParam));
|
||||
dispatch = !handle_mouse_button(WINOSD(machine), 3, FALSE, GET_X_LPARAM(message.lParam), GET_Y_LPARAM(message.lParam));
|
||||
break;
|
||||
|
||||
case WM_KEYDOWN:
|
||||
if (NOT_ALREADY_DOWN(message.lParam))
|
||||
dispatch = !handle_keypress(WINOSD(machine), message.wParam, TRUE, SCAN_CODE(message.lParam), IS_EXTENDED(message.lParam));
|
||||
break;
|
||||
|
||||
case WM_KEYUP:
|
||||
dispatch = !handle_keypress(WINOSD(machine), message.wParam, FALSE, SCAN_CODE(message.lParam), IS_EXTENDED(message.lParam));
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -688,7 +727,7 @@ void winwindow_update_cursor_state(running_machine &machine)
|
||||
// 2. we also hide the cursor in full screen mode and when the window doesn't have a menu
|
||||
// 3. we also hide the cursor in windowed mode if we're not paused and
|
||||
// the input system requests it
|
||||
if (winwindow_has_focus() && ((!video_config.windowed && !win_window_list->win_has_menu()) || (!machine.paused() && wininput_should_hide_mouse())))
|
||||
if (winwindow_has_focus() && ((!video_config.windowed && !win_window_list->win_has_menu()) || (!machine.paused() && downcast<windows_osd_interface&>(machine.osd()).should_hide_mouse())))
|
||||
{
|
||||
win_window_info *window = win_window_list;
|
||||
RECT bounds;
|
||||
@ -1152,6 +1191,7 @@ int win_window_info::wnd_extra_height()
|
||||
unsigned __stdcall win_window_info::thread_entry(void *param)
|
||||
{
|
||||
MSG message;
|
||||
windows_osd_interface *osd = static_cast<windows_osd_interface*>(param);
|
||||
|
||||
// make a bogus user call to make us a message thread
|
||||
PeekMessage(&message, nullptr, 0, 0, PM_NOREMOVE);
|
||||
@ -1179,36 +1219,36 @@ unsigned __stdcall win_window_info::thread_entry(void *param)
|
||||
|
||||
// forward mouse button downs to the input system
|
||||
case WM_LBUTTONDOWN:
|
||||
dispatch = !wininput_handle_mouse_button(0, TRUE, GET_X_LPARAM(message.lParam), GET_Y_LPARAM(message.lParam));
|
||||
dispatch = !handle_mouse_button(osd, 0, TRUE, GET_X_LPARAM(message.lParam), GET_Y_LPARAM(message.lParam));
|
||||
break;
|
||||
|
||||
case WM_RBUTTONDOWN:
|
||||
dispatch = !wininput_handle_mouse_button(1, TRUE, GET_X_LPARAM(message.lParam), GET_Y_LPARAM(message.lParam));
|
||||
dispatch = !handle_mouse_button(osd, 1, TRUE, GET_X_LPARAM(message.lParam), GET_Y_LPARAM(message.lParam));
|
||||
break;
|
||||
|
||||
case WM_MBUTTONDOWN:
|
||||
dispatch = !wininput_handle_mouse_button(2, TRUE, GET_X_LPARAM(message.lParam), GET_Y_LPARAM(message.lParam));
|
||||
dispatch = !handle_mouse_button(osd, 2, TRUE, GET_X_LPARAM(message.lParam), GET_Y_LPARAM(message.lParam));
|
||||
break;
|
||||
|
||||
case WM_XBUTTONDOWN:
|
||||
dispatch = !wininput_handle_mouse_button(3, TRUE, GET_X_LPARAM(message.lParam), GET_Y_LPARAM(message.lParam));
|
||||
dispatch = !handle_mouse_button(osd, 3, TRUE, GET_X_LPARAM(message.lParam), GET_Y_LPARAM(message.lParam));
|
||||
break;
|
||||
|
||||
// forward mouse button ups to the input system
|
||||
case WM_LBUTTONUP:
|
||||
dispatch = !wininput_handle_mouse_button(0, FALSE, GET_X_LPARAM(message.lParam), GET_Y_LPARAM(message.lParam));
|
||||
dispatch = !handle_mouse_button(osd, 0, FALSE, GET_X_LPARAM(message.lParam), GET_Y_LPARAM(message.lParam));
|
||||
break;
|
||||
|
||||
case WM_RBUTTONUP:
|
||||
dispatch = !wininput_handle_mouse_button(1, FALSE, GET_X_LPARAM(message.lParam), GET_Y_LPARAM(message.lParam));
|
||||
dispatch = !handle_mouse_button(osd, 1, FALSE, GET_X_LPARAM(message.lParam), GET_Y_LPARAM(message.lParam));
|
||||
break;
|
||||
|
||||
case WM_MBUTTONUP:
|
||||
dispatch = !wininput_handle_mouse_button(2, FALSE, GET_X_LPARAM(message.lParam), GET_Y_LPARAM(message.lParam));
|
||||
dispatch = !handle_mouse_button(osd, 2, FALSE, GET_X_LPARAM(message.lParam), GET_Y_LPARAM(message.lParam));
|
||||
break;
|
||||
|
||||
case WM_XBUTTONUP:
|
||||
dispatch = !wininput_handle_mouse_button(3, FALSE, GET_X_LPARAM(message.lParam), GET_Y_LPARAM(message.lParam));
|
||||
dispatch = !handle_mouse_button(osd, 3, FALSE, GET_X_LPARAM(message.lParam), GET_Y_LPARAM(message.lParam));
|
||||
break;
|
||||
|
||||
// a terminate message to the thread posts a quit
|
||||
@ -1369,7 +1409,7 @@ LRESULT CALLBACK win_window_info::video_window_proc(HWND wnd, UINT message, WPAR
|
||||
|
||||
// input: handle the raw input
|
||||
case WM_INPUT:
|
||||
wininput_handle_raw((HRAWINPUT)lparam);
|
||||
downcast<windows_osd_interface&>(window->machine().osd()).handle_input_event(INPUT_EVENT_RAWINPUT, &lparam);
|
||||
break;
|
||||
|
||||
// syskeys - ignore
|
||||
|
@ -238,6 +238,29 @@ private:
|
||||
// TYPE DEFINITIONS
|
||||
//============================================================
|
||||
|
||||
enum input_event
|
||||
{
|
||||
INPUT_EVENT_KEYDOWN,
|
||||
INPUT_EVENT_KEYUP,
|
||||
INPUT_EVENT_RAWINPUT,
|
||||
INPUT_EVENT_MOUSE_BUTTON
|
||||
};
|
||||
|
||||
struct KeyPressEventArgs
|
||||
{
|
||||
input_event event_id;
|
||||
UINT8 vkey;
|
||||
UINT8 scancode;
|
||||
};
|
||||
|
||||
struct MouseButtonEventArgs
|
||||
{
|
||||
int button;
|
||||
int keydown;
|
||||
int xpos;
|
||||
int ypos;
|
||||
};
|
||||
|
||||
class windows_osd_interface : public osd_common_t
|
||||
{
|
||||
public:
|
||||
@ -252,25 +275,25 @@ public:
|
||||
// video overridables
|
||||
virtual slider_state *get_slider_list() override;
|
||||
|
||||
// input overridables
|
||||
virtual void customize_input_type_list(simple_list<input_type_entry> &typelist) override;
|
||||
|
||||
virtual void video_register() override;
|
||||
|
||||
virtual bool video_init() override;
|
||||
virtual bool window_init() override;
|
||||
virtual bool input_init() override;
|
||||
virtual void input_pause() override;
|
||||
virtual void input_resume() override;
|
||||
virtual bool output_init() override;
|
||||
|
||||
virtual void video_exit() override;
|
||||
virtual void window_exit() override;
|
||||
virtual void input_exit() override;
|
||||
virtual void output_exit() override;
|
||||
|
||||
void extract_video_config();
|
||||
|
||||
// windows osd specific
|
||||
bool handle_input_event(input_event eventid, void *eventdata);
|
||||
bool should_hide_mouse();
|
||||
void poll_input(running_machine &machine);
|
||||
|
||||
windows_options &options() { return m_options; }
|
||||
|
||||
private:
|
||||
|
Loading…
Reference in New Issue
Block a user