Various input and OSD refactoring:

osd: Supply OSD object to modules on initialisation.  Encapsulated some
event handling in the OSD objects rather than leaving it in free
functions.  Put various stuff in namespaces.

osd/modules/input: Enabled dinput, xinput and winhybrid modules for
Windows SDL builds, and enabled background input for dinput and xinput
(and by extension winhybrid) modules.  Also fixed some COM and X11
resource leaks.

osd/modules/input/input_sdl.cpp: Flipped SDL mouse button order to match
Windows, and exposed vertical and horizontal scroll as Z and rZ axes.
Moved SDL UI event handling out of input devices into OSD object.

osd/modules/input_rawinput.cpp: Changed lightgun Z axis token so it's
correctly identified as a relative axis (it maps to the scroll wheel
equivalent).

osd: Added an option to choose the network provider module.  Mostly
useful if you build with both TUN/TAP and pcap support included, or if
you want to disable emulated networking completely.

emu/input.cpp: Use a better strategy for assembling input code names
that uses fewer temporary strings and doesn't require use of the
non-Unicode-aware space trimming function (fixes MT08552).

osd/modules/input_dinput.cpp: Improved polling logic.

osd: Made various parts of the input code less dependent on concrete emu
objects, and reduced inappropriately passing around the machine object.
Made input modules less dependent on OSD implementation.  Encapsulated
some stuff and got rid of some vestigial newui and SDL1 support code.
Cleaned up some interfaces.  Moved OSD options classes to their own
files.

Prepare to remove main.h from emu.h - it's mostly used to get the
application name, which the vast majority of emulated devices don't need
to do.
This commit is contained in:
Vas Crabb 2023-01-29 03:02:02 +11:00
parent 01fcb2e0de
commit 68472d3d72
111 changed files with 4784 additions and 4392 deletions

View File

@ -743,9 +743,12 @@ OSD-related Options
**-[no]background_input**
Sets whether input is accepted or ignored when MAME does not have UI focus.
Currently supported for RawInput mouse/keyboard input on Windows, and SDL
game controller/joystick input. This setting is ignored when the debugger
is enabled. The default is OFF (**-nobackground_input**).
This setting is ignored when the debugger is enabled. The default is OFF
(**-nobackground_input**).
Currently supported for RawInput mouse/keyboard input, DirectInput
mouse/keyboard/joystick input and XInput joystick input on Windows, and SDL
game controller/joystick input.
Example:
.. code-block:: bash
@ -1017,11 +1020,31 @@ Example:
mame -midiprovider none dx100 -midiin canyon.mid
.. _mame-commandline-networkprovider:
**-networkprovider** *<module>*
Chooses how MAME will provide communication for emulated packet-oriented
network interfaces (e.g. Ethernet cards). Supported options are ``taptun``
to use the TUN/TAP, TAP-Windows or similar, ``pcap`` to use a pcap library,
or ``none`` to disable communication for emulated network interfaces.
Available options depend on your operating system. By default, ``taptun``
and ``none`` are available on Windows and Linux, and ``pcap`` and ``none``
are available on macOS.
The default is ``auto`` which will use ``taptun`` if available, falling back
to ``pcap``.
Example:
.. code-block:: bash
mame -networkprovider pcap apple2ee -sl3 uthernet
.. _mame-commandline-cliverbs:
OSD CLI Verbs
-------------
OSD Command-Line Verbs
----------------------
.. _mame-commandline-listmidi:

View File

@ -65,6 +65,7 @@ OSD-related Options
| :ref:`lightgunprovider <mame-commandline-lightgunprovider>`
| :ref:`joystickprovider <mame-commandline-joystickprovider>`
| :ref:`midiprovider <mame-commandline-midiprovider>`
| :ref:`networkprovider <mame-commandline-networkprovider>`
OSD CLI Verbs

View File

@ -102,9 +102,8 @@ function osdmodulesbuild()
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_wincommon.h",
MAME_DIR .. "src/osd/modules/input/input_windows.cpp",
MAME_DIR .. "src/osd/modules/input/input_windows.h",
MAME_DIR .. "src/osd/modules/input/input_xinput.cpp",

View File

@ -100,6 +100,7 @@ function maintargetosdoptions(_target,_subtarget)
configuration { }
end
links {
"dinput8",
"psapi",
}
elseif _OPTIONS["targetos"]=="haiku" then
@ -426,16 +427,19 @@ project ("osd_" .. _OPTIONS["osd"])
end
files {
MAME_DIR .. "src/osd/sdl/osdsdl.h",
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/video.cpp",
MAME_DIR .. "src/osd/sdl/window.cpp",
MAME_DIR .. "src/osd/sdl/window.h",
MAME_DIR .. "src/osd/modules/osdwindow.cpp",
MAME_DIR .. "src/osd/modules/osdwindow.h",
MAME_DIR .. "src/osd/modules/render/drawsdl.cpp",
MAME_DIR .. "src/osd/sdl/osdsdl.cpp",
MAME_DIR .. "src/osd/sdl/osdsdl.h",
MAME_DIR .. "src/osd/sdl/sdlmain.cpp",
MAME_DIR .. "src/osd/sdl/sdlopts.cpp",
MAME_DIR .. "src/osd/sdl/sdlopts.h",
MAME_DIR .. "src/osd/sdl/sdlprefix.h",
MAME_DIR .. "src/osd/sdl/video.cpp",
MAME_DIR .. "src/osd/sdl/window.cpp",
MAME_DIR .. "src/osd/sdl/window.h",
}
files {
MAME_DIR .. "src/osd/modules/render/draw13.cpp",

View File

@ -142,9 +142,10 @@ project ("osd_" .. _OPTIONS["osd"])
MAME_DIR .. "src/osd/windows/window.h",
MAME_DIR .. "src/osd/modules/osdwindow.cpp",
MAME_DIR .. "src/osd/modules/osdwindow.h",
MAME_DIR .. "src/osd/windows/winmenu.cpp",
MAME_DIR .. "src/osd/windows/winmain.cpp",
MAME_DIR .. "src/osd/windows/winmain.h",
MAME_DIR .. "src/osd/windows/winopts.cpp",
MAME_DIR .. "src/osd/windows/winopts.h",
MAME_DIR .. "src/osd/osdepend.h",
MAME_DIR .. "src/osd/modules/debugger/win/consolewininfo.cpp",
MAME_DIR .. "src/osd/modules/debugger/win/consolewininfo.h",

View File

@ -17,6 +17,7 @@
#include "debugger.h"
#include "fileio.h"
#include "main.h"
#include "corestr.h"

View File

@ -20,6 +20,7 @@
#include "debugger.h"
#include "emuopts.h"
#include "fileio.h"
#include "main.h"
#include "screen.h"
#include "uiinput.h"

View File

@ -9,9 +9,12 @@
**************************************************************************/
#include "emu.h"
#include "emuopts.h"
#include "main.h"
#include "screen.h"
//**************************************************************************
// DRIVER STATE
//**************************************************************************

View File

@ -10,10 +10,13 @@
#include "emu.h"
#include "emuopts.h"
#include "drivenum.h"
#include "softlist_dev.h"
#include "hashfile.h"
#include "drivenum.h"
#include "hashfile.h"
#include "main.h"
#include "softlist_dev.h"
// lib/util
#include "corestr.h"
#include "path.h"

View File

@ -15,8 +15,10 @@
#include "drivenum.h"
#include "emuopts.h"
#include "fileio.h"
#include "main.h"
#include "softlist.h"
// lib/util
#include "corestr.h"
#include "xmlfile.h"
#include "zippath.h"

View File

@ -638,50 +638,39 @@ input_code input_manager::code_from_itemid(input_item_id itemid) const
std::string input_manager::code_name(input_code code) const
{
// if nothing there, return an empty string
input_device_item *item = item_from_code(code);
if (item == nullptr)
input_device_item const *const item = item_from_code(code);
if (!item)
return std::string();
// determine the devclass part
const char *devclass = (*devclass_string_table)[code.device_class()];
// determine the devindex part
std::string devindex = string_format("%d", code.device_index() + 1);
// if we're unifying all devices, don't display a number
if (!m_class[code.device_class()]->multi())
devindex.clear();
std::string str;
// keyboard 0 doesn't show a class or index if it is the only one
input_device_class device_class = item->device().devclass();
if (device_class == DEVICE_CLASS_KEYBOARD && m_class[device_class]->maxindex() == 0)
input_device_class const device_class = item->device().devclass();
if ((device_class != DEVICE_CLASS_KEYBOARD) || (m_class[device_class]->maxindex() > 0))
{
devclass = "";
devindex.clear();
// determine the devclass part
str = (*devclass_string_table)[code.device_class()];
// if we're unifying all devices, don't display a number
if (m_class[code.device_class()]->multi())
str.append(util::string_format(" %d ", code.device_index() + 1));
else
str.append(" ");
}
// devcode part comes from the item name
std::string_view devcode = item->name();
// append item name - redundant with joystick switch left/right/up/down
if ((device_class != DEVICE_CLASS_JOYSTICK) || (code.item_class() == ITEM_CLASS_SWITCH))
{
if ((code.item_modifier() < ITEM_MODIFIER_LEFT) || (code.item_modifier() > ITEM_MODIFIER_DOWN))
str.append(item->name());
}
// determine the modifier part
const char *modifier = (*modifier_string_table)[code.item_modifier()];
// devcode is redundant with joystick switch left/right/up/down
if (device_class == DEVICE_CLASS_JOYSTICK && code.item_class() == ITEM_CLASS_SWITCH)
if (code.item_modifier() >= ITEM_MODIFIER_LEFT && code.item_modifier() <= ITEM_MODIFIER_DOWN)
devcode = std::string_view();
// concatenate the strings
std::string str(devclass);
if (!devindex.empty())
str.append(" ").append(devindex);
if (!devcode.empty())
str.append(" ").append(devcode);
if (modifier != nullptr)
// append the modifier
char const *const modifier = (*modifier_string_table)[code.item_modifier()];
if (modifier && *modifier)
str.append(" ").append(modifier);
// delete any leading spaces
return std::string(strtrimspace(str));
return str;
}

View File

@ -96,6 +96,7 @@
#include "emuopts.h"
#include "fileio.h"
#include "inputdev.h"
#include "main.h"
#include "natkeyboard.h"
#include "profiler.h"
@ -109,6 +110,7 @@
#include "osdepend.h"
#include <algorithm>
#include <cctype>
#include <ctime>

View File

@ -20,6 +20,7 @@
#include "fileio.h"
#include "http.h"
#include "image.h"
#include "main.h"
#include "natkeyboard.h"
#include "network.h"
#include "render.h"

View File

@ -9,20 +9,25 @@
***************************************************************************/
#include "emu.h"
#include "main.h"
#include "emuopts.h"
#include "http.h"
machine_manager::machine_manager(emu_options& options, osd_interface& osd)
: m_osd(osd),
machine_manager::machine_manager(emu_options& options, osd_interface& osd) :
m_osd(osd),
m_options(options),
m_machine(nullptr)
{
}
machine_manager::~machine_manager()
{
}
void machine_manager::start_http_server()
{
m_http = std::make_unique<http_manager>(options().http(), options().http_port(), options().http_root());

View File

@ -11,6 +11,7 @@
#include "emu.h"
#include "fileio.h"
#include "main.h"
#include "screen.h"
#include "aviio.h"

View File

@ -14,6 +14,7 @@
#include "emuopts.h"
#include "fileio.h"
#include "main.h"
#include "rendfont.h"
#include "rendutil.h"
#include "video/rgbutil.h"

View File

@ -14,7 +14,9 @@
#include "drivenum.h"
#include "emuopts.h"
#include "fileio.h"
#include "main.h"
#include "softlist_dev.h"
#include "ui/uimain.h"
#include "corestr.h"

View File

@ -25,6 +25,8 @@
#include "emu.h"
#include "emuopts.h"
#include "main.h"
#include "util/coreutil.h"
#include "util/ioprocs.h"
#include "util/ioprocsfilter.h"

View File

@ -13,6 +13,7 @@
#include "emuopts.h"
#include "fileio.h"
#include "main.h"
#include "render.h"
#include "rendutil.h"

View File

@ -12,6 +12,7 @@
#include "config.h"
#include "emuopts.h"
#include "main.h"
#include "speaker.h"
#include "wavwrite.h"

View File

@ -12,6 +12,7 @@
#include "validity.h"
#include "emuopts.h"
#include "main.h"
#include "romload.h"
#include "speaker.h"
#include "video/rgbutil.h"

View File

@ -9,15 +9,17 @@
***************************************************************************/
#include "emu.h"
#include "emuopts.h"
#include "debugger.h"
#include "fileio.h"
#include "ui/uimain.h"
#include "crsshair.h"
#include "rendersw.hxx"
#include "debugger.h"
#include "emuopts.h"
#include "fileio.h"
#include "main.h"
#include "output.h"
#include "screen.h"
#include "ui/uimain.h"
#include "corestr.h"
#include "path.h"
#include "png.h"
@ -25,6 +27,8 @@
#include "osdepend.h"
#include "rendersw.hxx"
//**************************************************************************
// DEBUGGING

View File

@ -20,6 +20,7 @@
// emu
#include "config.h"
#include "drivenum.h"
#include "main.h"
#include "romload.h"
#include "screen.h"
#include "softlist_dev.h"

View File

@ -6,12 +6,14 @@
Controls execution of the core MAME system.
***************************************************************************/
#ifndef MAME_FRONTEND_MAME_MAME_H
#define MAME_FRONTEND_MAME_MAME_H
#pragma once
#include "main.h"
namespace sol {
struct load_result;

View File

@ -11,13 +11,17 @@
#include "emu.h"
#include "mameopts.h"
#include "drivenum.h"
#include "fileio.h"
#include "screen.h"
#include "softlist_dev.h"
#include "hashfile.h"
#include "clifront.h"
// emu
#include "drivenum.h"
#include "fileio.h"
#include "hashfile.h"
#include "main.h"
#include "screen.h"
#include "softlist_dev.h"
// lib/util
#include "path.h"
#include "zippath.h"

View File

@ -18,6 +18,7 @@
#include "drivenum.h"
#include "fileio.h"
#include "main.h"
#include "uiinput.h"
#include "util/corestr.h"

View File

@ -440,7 +440,6 @@ float text_layout::actual_width()
m_calculated_actual_width = 0;
for (const auto &line : m_lines)
m_calculated_actual_width = std::max(m_calculated_actual_width, line->width());
}
// return it

View File

@ -4,9 +4,11 @@
Ensoniq panel/display device
*/
#include "emu.h"
#include "http.h"
#include "esqpanel.h"
#include "http.h"
#include "main.h"
//**************************************************************************
// External panel support
//**************************************************************************

View File

@ -9,6 +9,7 @@
****************************************************************************/
#include "emu.h"
#include "main.h"
#define APPNAME "MAME"
#define APPNAME_LOWER "mame"

View File

@ -4,7 +4,6 @@
* debug_module.h
*
*/
#ifndef MAME_OSD_DEBUGGER_DEBUG_MODULE_H
#define MAME_OSD_DEBUGGER_DEBUG_MODULE_H
@ -13,6 +12,7 @@
#include "osdepend.h"
#include "modules/osdmodule.h"
//============================================================
// CONSTANTS
//============================================================
@ -22,14 +22,11 @@
class debug_module
{
public:
virtual ~debug_module() { }
virtual ~debug_module() = default;
virtual void init_debugger(running_machine &machine) = 0;
virtual void wait_for_debugger(device_t &device, bool firststop) = 0;
virtual void debugger_update() = 0;
};
#endif // MAME_OSD_DEBUGGER_DEBUG_MODULE_H

View File

@ -23,6 +23,8 @@
#include <cinttypes>
namespace osd {
namespace {
//-------------------------------------------------------------------------
@ -516,7 +518,7 @@ public:
virtual ~debug_gdbstub() { }
virtual int init(const osd_options &options) override;
virtual int init(osd_interface &osd, const osd_options &options) override;
virtual void exit() override;
virtual void init_debugger(running_machine &machine) override;
@ -630,7 +632,7 @@ private:
};
//-------------------------------------------------------------------------
int debug_gdbstub::init(const osd_options &options)
int debug_gdbstub::init(osd_interface &osd, const osd_options &options)
{
m_debugger_port = options.debugger_port();
return 0;
@ -1495,5 +1497,7 @@ void debug_gdbstub::handle_character(char ch)
} // anonymous namespace
} // namespace osd
//-------------------------------------------------------------------------
MODULE_DEFINITION(DEBUG_GDBSTUB, debug_gdbstub)
MODULE_DEFINITION(DEBUG_GDBSTUB, osd::debug_gdbstub)

View File

@ -25,6 +25,8 @@
#include "modules/osdmodule.h"
#include "zippath.h"
namespace osd {
namespace {
class debug_area
@ -122,7 +124,7 @@ public:
virtual ~debug_imgui() { }
virtual int init(const osd_options &options) override { return 0; }
virtual int init(osd_interface &osd, const osd_options &options) override { return 0; }
virtual void exit() override {};
virtual void init_debugger(running_machine &machine) override;
@ -1031,16 +1033,16 @@ void debug_imgui::refresh_filelist()
m_filelist.emplace_back(std::move(temp));
}
first = m_filelist.size();
const osd::directory::entry *dirent;
const directory::entry *dirent;
while((dirent = dir->readdir()) != nullptr)
{
file_entry temp;
switch(dirent->type)
{
case osd::directory::entry::entry_type::FILE:
case directory::entry::entry_type::FILE:
temp.type = file_entry_type::FILE;
break;
case osd::directory::entry::entry_type::DIR:
case directory::entry::entry_type::DIR:
temp.type = file_entry_type::DIRECTORY;
break;
default:
@ -1196,10 +1198,10 @@ void debug_imgui::draw_create_dialog(const char* label)
if(ImGui::InputText("##createfilename",m_path,1024,ImGuiInputTextFlags_EnterReturnsTrue))
{
auto entry = osd_stat(m_path);
auto file_type = (entry != nullptr) ? entry->type : osd::directory::entry::entry_type::NONE;
if(file_type == osd::directory::entry::entry_type::NONE)
auto file_type = (entry != nullptr) ? entry->type : directory::entry::entry_type::NONE;
if(file_type == directory::entry::entry_type::NONE)
create_image();
if(file_type == osd::directory::entry::entry_type::FILE)
if(file_type == directory::entry::entry_type::FILE)
m_create_confirm_wait = true;
// cannot overwrite a directory, so nothing will be none in that case.
}
@ -1246,10 +1248,10 @@ void debug_imgui::draw_create_dialog(const char* label)
if(ImGui::Button("OK##mount"))
{
auto entry = osd_stat(m_path);
auto file_type = (entry != nullptr) ? entry->type : osd::directory::entry::entry_type::NONE;
if(file_type == osd::directory::entry::entry_type::NONE)
auto file_type = (entry != nullptr) ? entry->type : directory::entry::entry_type::NONE;
if(file_type == directory::entry::entry_type::NONE)
create_image();
if(file_type == osd::directory::entry::entry_type::FILE)
if(file_type == directory::entry::entry_type::FILE)
m_create_confirm_wait = true;
// cannot overwrite a directory, so nothing will be none in that case.
m_create_open = false;
@ -1586,4 +1588,6 @@ void debug_imgui::debugger_update()
} // anonymous namespace
MODULE_DEFINITION(DEBUG_IMGUI, debug_imgui)
} // namespace osd
MODULE_DEFINITION(DEBUG_IMGUI, osd::debug_imgui)

View File

@ -24,11 +24,6 @@
// MAMEOS headers
#include "modules/lib/osdobj_common.h"
#include "osx/debugosx.h"
#ifdef OSD_MAC
#include "osdmac.h"
#else
#include "osdsdl.h"
#endif
#include "debug_module.h"
#import "osx/debugconsole.h"
@ -61,12 +56,12 @@ public:
[m_console release];
}
virtual int init(const osd_options &options);
virtual void exit();
virtual int init(osd_interface &osd, const osd_options &options) override;
virtual void exit() override;
virtual void init_debugger(running_machine &machine);
virtual void wait_for_debugger(device_t &device, bool firststop);
virtual void debugger_update();
virtual void init_debugger(running_machine &machine) override;
virtual void wait_for_debugger(device_t &device, bool firststop) override;
virtual void debugger_update() override;
private:
void create_console();
@ -91,7 +86,7 @@ std::atomic_bool debugger_osx::s_added_menus(false);
// initialise debugger module
//============================================================
int debugger_osx::init(const osd_options &options)
int debugger_osx::init(osd_interface &osd, const osd_options &options)
{
return 0;
}

View File

@ -43,9 +43,11 @@ bool winwindow_qt_filter(void *message);
#endif
namespace osd {
namespace {
class debug_qt : public osd_module, public debug_module, protected osd::debugger::qt::DebuggerQt
class debug_qt : public osd_module, public debug_module, protected debugger::qt::DebuggerQt
#if defined(_WIN32) && !defined(SDLMAME_WIN32)
, public QAbstractNativeEventFilter
#endif
@ -61,7 +63,7 @@ public:
virtual ~debug_qt() { }
virtual int init(const osd_options &options) override { return 0; }
virtual int init(osd_interface &osd, const osd_options &options) override { return 0; }
virtual void exit() override;
virtual void init_debugger(running_machine &machine) override;
@ -83,7 +85,7 @@ private:
void load_window_configurations(util::xml::data_node const &parentnode);
running_machine *m_machine;
osd::debugger::qt::MainWindow *m_mainwindow;
debugger::qt::MainWindow *m_mainwindow;
util::xml::file::ptr m_config;
};
@ -142,7 +144,7 @@ void debug_qt::wait_for_debugger(device_t &device, bool firststop)
// Dialog initialization
if (!m_mainwindow)
{
m_mainwindow = new osd::debugger::qt::MainWindow(*this);
m_mainwindow = new debugger::qt::MainWindow(*this);
if (m_config)
{
load_window_configurations(*m_config->get_first_child());
@ -211,31 +213,31 @@ void debug_qt::configuration_save(config_type which_type, util::xml::data_node *
void debug_qt::load_window_configurations(util::xml::data_node const &parentnode)
{
for (util::xml::data_node const *wnode = parentnode.get_child(osd::debugger::NODE_WINDOW); wnode; wnode = wnode->get_next_sibling(osd::debugger::NODE_WINDOW))
for (util::xml::data_node const *wnode = parentnode.get_child(debugger::NODE_WINDOW); wnode; wnode = wnode->get_next_sibling(debugger::NODE_WINDOW))
{
osd::debugger::qt::WindowQt *win = nullptr;
switch (wnode->get_attribute_int(osd::debugger::ATTR_WINDOW_TYPE, -1))
debugger::qt::WindowQt *win = nullptr;
switch (wnode->get_attribute_int(debugger::ATTR_WINDOW_TYPE, -1))
{
case osd::debugger::WINDOW_TYPE_CONSOLE:
case debugger::WINDOW_TYPE_CONSOLE:
win = m_mainwindow;
break;
case osd::debugger::WINDOW_TYPE_MEMORY_VIEWER:
win = new osd::debugger::qt::MemoryWindow(*this);
case debugger::WINDOW_TYPE_MEMORY_VIEWER:
win = new debugger::qt::MemoryWindow(*this);
break;
case osd::debugger::WINDOW_TYPE_DISASSEMBLY_VIEWER:
win = new osd::debugger::qt::DasmWindow(*this);
case debugger::WINDOW_TYPE_DISASSEMBLY_VIEWER:
win = new debugger::qt::DasmWindow(*this);
break;
case osd::debugger::WINDOW_TYPE_ERROR_LOG_VIEWER:
win = new osd::debugger::qt::LogWindow(*this);
case debugger::WINDOW_TYPE_ERROR_LOG_VIEWER:
win = new debugger::qt::LogWindow(*this);
break;
case osd::debugger::WINDOW_TYPE_POINTS_VIEWER:
win = new osd::debugger::qt::BreakpointsWindow(*this);
case debugger::WINDOW_TYPE_POINTS_VIEWER:
win = new debugger::qt::BreakpointsWindow(*this);
break;
case osd::debugger::WINDOW_TYPE_DEVICES_VIEWER:
win = new osd::debugger::qt::DevicesWindow(*this);
case debugger::WINDOW_TYPE_DEVICES_VIEWER:
win = new debugger::qt::DevicesWindow(*this);
break;
case osd::debugger::WINDOW_TYPE_DEVICE_INFO_VIEWER:
win = new osd::debugger::qt::DeviceInformationWindow(*this);
case debugger::WINDOW_TYPE_DEVICE_INFO_VIEWER:
win = new debugger::qt::DeviceInformationWindow(*this);
break;
}
if (win)
@ -245,10 +247,12 @@ void debug_qt::load_window_configurations(util::xml::data_node const &parentnode
} // anonymous namespace
} // namespace osd
#else // USE_QTDEBUG
MODULE_NOT_SUPPORTED(debug_qt, OSD_DEBUG_PROVIDER, "qt")
namespace osd { namespace { MODULE_NOT_SUPPORTED(debug_qt, OSD_DEBUG_PROVIDER, "qt") } }
#endif
MODULE_DEFINITION(DEBUG_QT, debug_qt)
MODULE_DEFINITION(DEBUG_QT, osd::debug_qt)

View File

@ -8,7 +8,6 @@
#include "emu.h"
#include "debug_module.h"
#include "modules/osdmodule.h"
#if defined(OSD_WINDOWS) /*|| defined(SDLMAME_WIN32)*/
@ -22,28 +21,34 @@
#include "win/pointswininfo.h"
#include "win/uimetrics.h"
// emu
#include "config.h"
#include "debugger.h"
#include "debug/debugcpu.h"
#include "util/xmlfile.h"
// osd/windows
#include "window.h"
#include "../input/input_common.h"
#include "../input/input_windows.h"
#include "winmain.h"
#include "../input/input_windows.h" // for the keyboard translation table
namespace osd {
namespace {
class debugger_windows :
public osd_module,
public debug_module,
protected osd::debugger::win::debugger_windows_interface
protected debugger::win::debugger_windows_interface
{
public:
debugger_windows() :
osd_module(OSD_DEBUG_PROVIDER, "windows"),
debug_module(),
m_osd(nullptr),
m_machine(nullptr),
m_metrics(),
m_waiting_for_debugger(false),
@ -57,7 +62,7 @@ public:
virtual ~debugger_windows() { }
virtual int init(const osd_options &options) override { return 0; }
virtual int init(osd_interface &osd, osd_options const &options) override;
virtual void exit() override;
virtual void init_debugger(running_machine &machine) override;
@ -67,7 +72,7 @@ public:
protected:
virtual running_machine &machine() const override { return *m_machine; }
virtual osd::debugger::win::ui_metrics &metrics() const override { return *m_metrics; }
virtual debugger::win::ui_metrics &metrics() const override { return *m_metrics; }
virtual void set_color_theme(int index) override;
virtual bool get_save_window_arrangement() const override { return m_save_windows; }
virtual void set_save_window_arrangement(bool save) override { m_save_windows = save; }
@ -75,11 +80,11 @@ protected:
virtual bool const &waiting_for_debugger() const override { return m_waiting_for_debugger; }
virtual bool seq_pressed() const override;
virtual void create_memory_window() override { create_window<osd::debugger::win::memorywin_info>(); }
virtual void create_disasm_window() override { create_window<osd::debugger::win::disasmwin_info>(); }
virtual void create_log_window() override { create_window<osd::debugger::win::logwin_info>(); }
virtual void create_points_window() override { create_window<osd::debugger::win::pointswin_info>(); }
virtual void remove_window(osd::debugger::win::debugwin_info &info) override;
virtual void create_memory_window() override { create_window<debugger::win::memorywin_info>(); }
virtual void create_disasm_window() override { create_window<debugger::win::disasmwin_info>(); }
virtual void create_log_window() override { create_window<debugger::win::logwin_info>(); }
virtual void create_points_window() override { create_window<debugger::win::pointswin_info>(); }
virtual void remove_window(debugger::win::debugwin_info &info) override;
virtual void show_all() override;
virtual void hide_all() override;
@ -94,11 +99,12 @@ private:
void load_configuration(util::xml::data_node const &parentnode);
windows_osd_interface *m_osd;
running_machine *m_machine;
std::unique_ptr<osd::debugger::win::ui_metrics> m_metrics;
std::unique_ptr<debugger::win::ui_metrics> m_metrics;
bool m_waiting_for_debugger;
std::vector<std::unique_ptr<osd::debugger::win::debugwin_info> > m_window_list;
osd::debugger::win::consolewin_info *m_main_console;
std::vector<std::unique_ptr<debugger::win::debugwin_info> > m_window_list;
debugger::win::consolewin_info *m_main_console;
POINT m_next_window_pos;
LONG m_window_start_x;
@ -108,6 +114,16 @@ private:
};
int debugger_windows::init(osd_interface &osd, osd_options const &options)
{
m_osd = dynamic_cast<windows_osd_interface *>(&osd);
if (!m_osd)
return -1;
return 0;
}
void debugger_windows::exit()
{
// loop over windows and free them
@ -123,7 +139,7 @@ void debugger_windows::exit()
void debugger_windows::init_debugger(running_machine &machine)
{
m_machine = &machine;
m_metrics = std::make_unique<osd::debugger::win::ui_metrics>(downcast<osd_options &>(m_machine->options()));
m_metrics = std::make_unique<debugger::win::ui_metrics>(downcast<osd_options &>(m_machine->options()));
machine.configuration().config_register(
"debugger",
configuration_manager::load_delegate(&debugger_windows::config_load, this),
@ -136,7 +152,7 @@ void debugger_windows::wait_for_debugger(device_t &device, bool firststop)
// create a console window
if (!m_main_console)
{
m_main_console = create_window<osd::debugger::win::consolewin_info>();
m_main_console = create_window<debugger::win::consolewin_info>();
// set the starting position for new auxiliary windows
HMONITOR const nearest_monitor = MonitorFromWindow(
@ -286,7 +302,7 @@ bool debugger_windows::seq_pressed() const
}
void debugger_windows::remove_window(osd::debugger::win::debugwin_info &info)
void debugger_windows::remove_window(debugger::win::debugwin_info &info)
{
for (auto it = m_window_list.begin(); it != m_window_list.end(); ++it)
if (it->get() == &info) {
@ -378,10 +394,10 @@ void debugger_windows::config_load(config_type cfgtype, config_level cfglevel, u
{
if (config_type::DEFAULT == cfgtype)
{
m_save_windows = 0 != parentnode->get_attribute_int(osd::debugger::ATTR_DEBUGGER_SAVE_WINDOWS, m_save_windows ? 1 : 0);
util::xml::data_node const *const colors = parentnode->get_child(osd::debugger::NODE_COLORS);
m_save_windows = 0 != parentnode->get_attribute_int(debugger::ATTR_DEBUGGER_SAVE_WINDOWS, m_save_windows ? 1 : 0);
util::xml::data_node const *const colors = parentnode->get_child(debugger::NODE_COLORS);
if (colors)
m_metrics->set_color_theme(colors->get_attribute_int(osd::debugger::ATTR_COLORS_THEME, m_metrics->get_color_theme()));
m_metrics->set_color_theme(colors->get_attribute_int(debugger::ATTR_COLORS_THEME, m_metrics->get_color_theme()));
}
else if (config_type::SYSTEM == cfgtype)
{
@ -404,10 +420,10 @@ void debugger_windows::config_save(config_type cfgtype, util::xml::data_node *pa
{
if (config_type::DEFAULT == cfgtype)
{
parentnode->set_attribute_int(osd::debugger::ATTR_DEBUGGER_SAVE_WINDOWS, m_save_windows ? 1 : 0);
util::xml::data_node *const colors = parentnode->add_child(osd::debugger::NODE_COLORS, nullptr);
parentnode->set_attribute_int(debugger::ATTR_DEBUGGER_SAVE_WINDOWS, m_save_windows ? 1 : 0);
util::xml::data_node *const colors = parentnode->add_child(debugger::NODE_COLORS, nullptr);
if (colors)
colors->set_attribute_int(osd::debugger::ATTR_COLORS_THEME, m_metrics->get_color_theme());
colors->set_attribute_int(debugger::ATTR_COLORS_THEME, m_metrics->get_color_theme());
}
else if (m_save_windows && (config_type::SYSTEM == cfgtype))
{
@ -419,30 +435,30 @@ void debugger_windows::config_save(config_type cfgtype, util::xml::data_node *pa
void debugger_windows::load_configuration(util::xml::data_node const &parentnode)
{
for (util::xml::data_node const *node = parentnode.get_child(osd::debugger::NODE_WINDOW); node; node = node->get_next_sibling(osd::debugger::NODE_WINDOW))
for (util::xml::data_node const *node = parentnode.get_child(debugger::NODE_WINDOW); node; node = node->get_next_sibling(debugger::NODE_WINDOW))
{
osd::debugger::win::debugwin_info *win = nullptr;
switch (node->get_attribute_int(osd::debugger::ATTR_WINDOW_TYPE, -1))
debugger::win::debugwin_info *win = nullptr;
switch (node->get_attribute_int(debugger::ATTR_WINDOW_TYPE, -1))
{
case osd::debugger::WINDOW_TYPE_CONSOLE:
case debugger::WINDOW_TYPE_CONSOLE:
m_main_console->restore_configuration_from_node(*node);
break;
case osd::debugger::WINDOW_TYPE_MEMORY_VIEWER:
win = create_window<osd::debugger::win::memorywin_info>();
case debugger::WINDOW_TYPE_MEMORY_VIEWER:
win = create_window<debugger::win::memorywin_info>();
break;
case osd::debugger::WINDOW_TYPE_DISASSEMBLY_VIEWER:
win = create_window<osd::debugger::win::disasmwin_info>();
case debugger::WINDOW_TYPE_DISASSEMBLY_VIEWER:
win = create_window<debugger::win::disasmwin_info>();
break;
case osd::debugger::WINDOW_TYPE_ERROR_LOG_VIEWER:
win = create_window<osd::debugger::win::logwin_info>();
case debugger::WINDOW_TYPE_ERROR_LOG_VIEWER:
win = create_window<debugger::win::logwin_info>();
break;
case osd::debugger::WINDOW_TYPE_POINTS_VIEWER:
win = create_window<osd::debugger::win::pointswin_info>();
case debugger::WINDOW_TYPE_POINTS_VIEWER:
win = create_window<debugger::win::pointswin_info>();
break;
case osd::debugger::WINDOW_TYPE_DEVICES_VIEWER:
case debugger::WINDOW_TYPE_DEVICES_VIEWER:
// not supported
break;
case osd::debugger::WINDOW_TYPE_DEVICE_INFO_VIEWER:
case debugger::WINDOW_TYPE_DEVICE_INFO_VIEWER:
// not supported
break;
default:
@ -455,8 +471,12 @@ void debugger_windows::load_configuration(util::xml::data_node const &parentnode
} // anonymous namespace
} // namespace osd
#else // not Windows
MODULE_NOT_SUPPORTED(debugger_windows, OSD_DEBUG_PROVIDER, "windows")
namespace osd { namespace { MODULE_NOT_SUPPORTED(debugger_windows, OSD_DEBUG_PROVIDER, "windows") } }
#endif
MODULE_DEFINITION(DEBUG_WINDOWS, debugger_windows)
MODULE_DEFINITION(DEBUG_WINDOWS, osd::debugger_windows)

View File

@ -8,27 +8,28 @@
#include "emu.h"
#include "debug_module.h"
#include "modules/osdmodule.h"
#include "debug/debugcon.h"
#include "debug/debugcpu.h"
#include "debugger.h"
namespace osd {
namespace {
class debug_none : public osd_module, public debug_module
{
public:
debug_none()
: osd_module(OSD_DEBUG_PROVIDER, "none"), debug_module(),
debug_none() :
osd_module(OSD_DEBUG_PROVIDER, "none"), debug_module(),
m_machine(nullptr)
{
}
virtual ~debug_none() { }
virtual int init(const osd_options &options) override { return 0; }
virtual int init(osd_interface &osd, const osd_options &options) override { return 0; }
virtual void exit() override { }
virtual void init_debugger(running_machine &machine) override;
@ -55,4 +56,6 @@ void debug_none::debugger_update()
} // anonymous namespace
MODULE_DEFINITION(DEBUG_NONE, debug_none)
} // namespace osd
MODULE_DEFINITION(DEBUG_NONE, osd::debug_none)

View File

@ -6,7 +6,7 @@
*/
#include "font_module.h"
#include "modules/osdmodule.h"
#include "modules/lib/osdlib.h"
#if defined(OSD_WINDOWS)
@ -681,7 +681,7 @@ public:
return true;
}
virtual int init(const osd_options &options) override
virtual int init(osd_interface &osd, const osd_options &options) override
{
HRESULT result;

View File

@ -4,9 +4,12 @@
* font_none.c
*
*/
#include "font_module.h"
#include "modules/osdmodule.h"
namespace osd {
namespace {
class osd_font_none : public osd_font
{
@ -23,10 +26,15 @@ class font_none : public osd_module, public font_module
public:
font_none() : osd_module(OSD_FONT_PROVIDER, "none"), font_module() { }
virtual int init(const osd_options &options) override { return 0; }
virtual int init(osd_interface &osd, const osd_options &options) override { return 0; }
virtual osd_font::ptr font_alloc() override { return std::make_unique<osd_font_none>(); }
virtual bool get_font_families(std::string const &font_path, std::vector<std::pair<std::string, std::string> > &result) override { return false; }
};
MODULE_DEFINITION(FONT_NONE, font_none)
} // anonymous namespace
} // namespace osd
MODULE_DEFINITION(FONT_NONE, osd::font_none)

View File

@ -6,7 +6,6 @@
*/
#include "font_module.h"
#include "modules/osdmodule.h"
#ifdef SDLMAME_MACOSX
@ -212,7 +211,7 @@ class font_osx : public osd_module, public font_module
public:
font_osx() : osd_module(OSD_FONT_PROVIDER, "osx"), font_module() { }
virtual int init(const osd_options &options) override { return 0; }
virtual int init(osd_interface &osd, const osd_options &options) override { return 0; }
virtual osd_font::ptr font_alloc() override { return std::make_unique<osd_font_osx>(); }
virtual bool get_font_families(std::string const &font_path, std::vector<std::pair<std::string, std::string> > &result) override;

View File

@ -6,7 +6,6 @@
*/
#include "font_module.h"
#include "modules/osdmodule.h"
#if defined(SDLMAME_UNIX) && !defined(SDLMAME_MACOSX) && !defined(SDLMAME_HAIKU) && !defined(SDLMAME_ANDROID)
@ -305,7 +304,7 @@ public:
return std::make_unique<osd_font_sdl>();
}
virtual int init(const osd_options &options) override
virtual int init(osd_interface &osd, const osd_options &options) override
{
if (TTF_Init() == -1)
{

View File

@ -7,7 +7,6 @@
#include "font_module.h"
#include "modules/osdmodule.h"
#if defined(OSD_WINDOWS) || defined(SDLMAME_WIN32)
@ -25,6 +24,8 @@
#include <io.h>
namespace osd {
namespace {
class osd_font_windows : public osd_font
@ -83,7 +84,7 @@ bool osd_font_windows::open(std::string const &font_path, std::string const &_na
logfont.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
// copy in the face name
osd::text::tstring face = osd::text::to_tstring(name);
text::tstring face = text::to_tstring(name);
_tcsncpy(logfont.lfFaceName, face.c_str(), std::size(logfont.lfFaceName));
logfont.lfFaceName[sizeof(logfont.lfFaceName) / sizeof(TCHAR)-1] = 0;
@ -108,7 +109,7 @@ bool osd_font_windows::open(std::string const &font_path, std::string const &_na
}
// if it doesn't match our request, fail
std::string utf = osd::text::from_tstring(&realname[0]);
std::string utf = text::from_tstring(&realname[0]);
int result = core_stricmp(utf, name);
// if we didn't match, nuke our font and fall back
@ -288,7 +289,7 @@ class font_win : public osd_module, public font_module
public:
font_win() : osd_module(OSD_FONT_PROVIDER, "win"), font_module() { }
virtual int init(const osd_options &options) override { return 0; }
virtual int init(osd_interface &osd, const osd_options &options) override { return 0; }
virtual osd_font::ptr font_alloc() override { return std::make_unique<osd_font_windows>(); }
@ -298,7 +299,7 @@ private:
static int CALLBACK font_family_callback(LOGFONT const *lpelfe, TEXTMETRIC const *lpntme, DWORD FontType, LPARAM lParam)
{
auto &result = *reinterpret_cast<std::vector<std::pair<std::string, std::string> > *>(lParam);
std::string face = osd::text::from_tstring(lpelfe->lfFaceName);
std::string face = text::from_tstring(lpelfe->lfFaceName);
if ((face[0] != '@') && (result.empty() || (result.back().first != face))) result.emplace_back(face, face);
return TRUE;
}
@ -326,10 +327,12 @@ bool font_win::get_font_families(std::string const &font_path, std::vector<std::
} // anonymous namespace
} // namespace osd
#else // defined(OSD_WINDOWS) || defined(SDLMAME_WIN32)
MODULE_NOT_SUPPORTED(font_win, OSD_FONT_PROVIDER, "win")
namespace osd { namespace { MODULE_NOT_SUPPORTED(font_win, OSD_FONT_PROVIDER, "win") } }
#endif // defined(OSD_WINDOWS) || defined(SDLMAME_WIN32)
MODULE_DEFINITION(FONT_WINDOWS, font_win)
MODULE_DEFINITION(FONT_WINDOWS, osd::font_win)

View File

@ -8,159 +8,159 @@
//
//============================================================
#include "modules/lib/osdobj_common.h"
// MAME headers
#include "emu.h"
#include "input_common.h"
#include "inputdev.h" // FIXME: still using concrete input device class in input_module_base::poll
#include "modules/lib/osdobj_common.h"
#include "emu.h" // so we can get an input manager from the running machine
//============================================================
// Keyboard translation table
//============================================================
#if defined(OSD_WINDOWS) || defined(SDLMAME_WIN32)
#include <windows.h>
#define KEY_TRANS_WIN32(disc, virtual) KEY_##disc, virtual,
#else
#define KEY_TRANS_WIN32(disc, virtual)
#endif
#if defined(OSD_SDL) || defined(SDLMAME_WIN32)
#include <SDL2/SDL.h>
#define KEY_TRANS_SDL(sdlsc) SDL_SCANCODE_##sdlsc,
#else
#define KEY_TRANS_SDL(sdlsc)
#endif
#define KEY_TRANS_ENTRY0(mame, sdlsc, disc, virtual, ascii, UI) { ITEM_ID_##mame, KEY_TRANS_SDL(sdlsc) KEY_TRANS_WIN32(disc, virtual) ascii, "ITEM_ID_"#mame, UI }
#define KEY_TRANS_ENTRY1(mame, sdlsc, disc, virtual, ascii) { ITEM_ID_##mame, KEY_TRANS_SDL(sdlsc) KEY_TRANS_WIN32(disc, virtual) ascii, "ITEM_ID_"#mame, #mame }
// winnt.h defines this
#ifdef DELETE
#undef DELETE
#endif
//============================================================
// 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 }
#elif defined(OSD_SDL)
// SDL include
#include <SDL2/SDL.h>
#define KEY_TRANS_ENTRY0(mame, sdlsc, sdlkey, disc, virtual, ascii, UI) { ITEM_ID_##mame, SDL_SCANCODE_ ## sdlsc, ascii, "ITEM_ID_"#mame, (char *) UI }
#define KEY_TRANS_ENTRY1(mame, sdlsc, sdlkey, disc, virtual, ascii) { ITEM_ID_##mame, SDL_SCANCODE_ ## sdlsc, ascii, "ITEM_ID_"#mame, (char*) #mame }
#else
// osd mini
#endif
// FIXME: sdl_key can be removed from the table below. It is no longer used.
#if defined(OSD_WINDOWS) || defined(OSD_SDL)
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, NONUSHASH, UNKNOWN, OEM_102, VK_OEM_102, '<'),
// MAME key sdl scancode di scancode virtual key ascii ui
KEY_TRANS_ENTRY0(ESC, ESCAPE, ESCAPE, VK_ESCAPE, 27, "ESCAPE"),
KEY_TRANS_ENTRY1(1, 1, 1, '1', '1'),
KEY_TRANS_ENTRY1(2, 2, 2, '2', '2'),
KEY_TRANS_ENTRY1(3, 3, 3, '3', '3'),
KEY_TRANS_ENTRY1(4, 4, 4, '4', '4'),
KEY_TRANS_ENTRY1(5, 5, 5, '5', '5'),
KEY_TRANS_ENTRY1(6, 6, 6, '6', '6'),
KEY_TRANS_ENTRY1(7, 7, 7, '7', '7'),
KEY_TRANS_ENTRY1(8, 8, 8, '8', '8'),
KEY_TRANS_ENTRY1(9, 9, 9, '9', '9'),
KEY_TRANS_ENTRY1(0, 0, 0, '0', '0'),
KEY_TRANS_ENTRY1(MINUS, MINUS, MINUS, VK_OEM_MINUS, '-'),
KEY_TRANS_ENTRY1(EQUALS, EQUALS, EQUALS, VK_OEM_PLUS, '='),
KEY_TRANS_ENTRY1(BACKSPACE, BACKSPACE, BACK, VK_BACK, 8),
KEY_TRANS_ENTRY1(TAB, TAB, TAB, VK_TAB, 9),
KEY_TRANS_ENTRY1(Q, Q, Q, 'Q', 'Q'),
KEY_TRANS_ENTRY1(W, W, W, 'W', 'W'),
KEY_TRANS_ENTRY1(E, E, E, 'E', 'E'),
KEY_TRANS_ENTRY1(R, R, R, 'R', 'R'),
KEY_TRANS_ENTRY1(T, T, T, 'T', 'T'),
KEY_TRANS_ENTRY1(Y, Y, Y, 'Y', 'Y'),
KEY_TRANS_ENTRY1(U, U, U, 'U', 'U'),
KEY_TRANS_ENTRY1(I, I, I, 'I', 'I'),
KEY_TRANS_ENTRY1(O, O, O, 'O', 'O'),
KEY_TRANS_ENTRY1(P, P, P, 'P', 'P'),
KEY_TRANS_ENTRY1(OPENBRACE, LEFTBRACKET, LBRACKET, VK_OEM_4, '['),
KEY_TRANS_ENTRY1(CLOSEBRACE, RIGHTBRACKET, RBRACKET, VK_OEM_6, ']'),
KEY_TRANS_ENTRY0(ENTER, RETURN, RETURN, VK_RETURN, 13, "RETURN"),
KEY_TRANS_ENTRY1(LCONTROL, LCTRL, LCONTROL, VK_LCONTROL, 0),
KEY_TRANS_ENTRY1(A, A, A, 'A', 'A'),
KEY_TRANS_ENTRY1(S, S, S, 'S', 'S'),
KEY_TRANS_ENTRY1(D, D, D, 'D', 'D'),
KEY_TRANS_ENTRY1(F, F, F, 'F', 'F'),
KEY_TRANS_ENTRY1(G, G, G, 'G', 'G'),
KEY_TRANS_ENTRY1(H, H, H, 'H', 'H'),
KEY_TRANS_ENTRY1(J, J, J, 'J', 'J'),
KEY_TRANS_ENTRY1(K, K, K, 'K', 'K'),
KEY_TRANS_ENTRY1(L, L, L, 'L', 'L'),
KEY_TRANS_ENTRY1(COLON, SEMICOLON, SEMICOLON, VK_OEM_1, ';'),
KEY_TRANS_ENTRY1(QUOTE, APOSTROPHE, APOSTROPHE, VK_OEM_7, '\''),
KEY_TRANS_ENTRY1(TILDE, GRAVE, GRAVE, VK_OEM_3, '`'),
KEY_TRANS_ENTRY1(LSHIFT, LSHIFT, LSHIFT, VK_LSHIFT, 0),
KEY_TRANS_ENTRY1(BACKSLASH, BACKSLASH, BACKSLASH, VK_OEM_5, '\\'),
// KEY_TRANS_ENTRY1(BACKSLASH2, NONUSHASH, UNKNOWN, OEM_102, VK_OEM_102, '<'),
// This is the additional key that ISO keyboards have over ANSI ones, located between left shift and Y.
KEY_TRANS_ENTRY1(BACKSLASH2, NONUSBACKSLASH, UNKNOWN, 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, CANCEL, CANCEL, UNKNOWN, 0, 0, "CANCEL"),
KEY_TRANS_ENTRY1(BS_PAD, KP_BACKSPACE, KP_BACKSPACE, UNKNOWN, 0, 0),
KEY_TRANS_ENTRY1(TAB_PAD, KP_TAB, KP_TAB, UNKNOWN, 0, 0),
KEY_TRANS_ENTRY1(00_PAD, KP_00, KP_00, UNKNOWN, 0, 0),
KEY_TRANS_ENTRY1(000_PAD, KP_000, KP_000, UNKNOWN, 0, 0),
KEY_TRANS_ENTRY1(COMMA_PAD, KP_COMMA, KP_COMMA, NUMPADCOMMA, 0, 0),
KEY_TRANS_ENTRY1(EQUALS_PAD, KP_EQUALS, KP_EQUALS, NUMPADEQUALS, 0, 0),
KEY_TRANS_ENTRY1(BACKSLASH2, NONUSBACKSLASH, OEM_102, VK_OEM_102, '<'),
KEY_TRANS_ENTRY1(Z, Z, Z, 'Z', 'Z'),
KEY_TRANS_ENTRY1(X, X, X, 'X', 'X'),
KEY_TRANS_ENTRY1(C, C, C, 'C', 'C'),
KEY_TRANS_ENTRY1(V, V, V, 'V', 'V'),
KEY_TRANS_ENTRY1(B, B, B, 'B', 'B'),
KEY_TRANS_ENTRY1(N, N, N, 'N', 'N'),
KEY_TRANS_ENTRY1(M, M, M, 'M', 'M'),
KEY_TRANS_ENTRY1(COMMA, COMMA, COMMA, VK_OEM_COMMA, ','),
KEY_TRANS_ENTRY1(STOP, PERIOD, PERIOD, VK_OEM_PERIOD, '.'),
KEY_TRANS_ENTRY1(SLASH, SLASH, SLASH, VK_OEM_2, '/'),
KEY_TRANS_ENTRY1(RSHIFT, RSHIFT, RSHIFT, VK_RSHIFT, 0),
KEY_TRANS_ENTRY1(ASTERISK, KP_MULTIPLY, MULTIPLY, VK_MULTIPLY, '*'),
KEY_TRANS_ENTRY1(LALT, LALT, LMENU, VK_LMENU, 0),
KEY_TRANS_ENTRY1(SPACE, SPACE, SPACE, VK_SPACE, ' '),
KEY_TRANS_ENTRY1(CAPSLOCK, CAPSLOCK, CAPITAL, VK_CAPITAL, 0),
KEY_TRANS_ENTRY1(F1, F1, F1, VK_F1, 0),
KEY_TRANS_ENTRY1(F2, F2, F2, VK_F2, 0),
KEY_TRANS_ENTRY1(F3, F3, F3, VK_F3, 0),
KEY_TRANS_ENTRY1(F4, F4, F4, VK_F4, 0),
KEY_TRANS_ENTRY1(F5, F5, F5, VK_F5, 0),
KEY_TRANS_ENTRY1(F6, F6, F6, VK_F6, 0),
KEY_TRANS_ENTRY1(F7, F7, F7, VK_F7, 0),
KEY_TRANS_ENTRY1(F8, F8, F8, VK_F8, 0),
KEY_TRANS_ENTRY1(F9, F9, F9, VK_F9, 0),
KEY_TRANS_ENTRY1(F10, F10, F10, VK_F10, 0),
KEY_TRANS_ENTRY1(NUMLOCK, NUMLOCKCLEAR, NUMLOCK, VK_NUMLOCK, 0),
KEY_TRANS_ENTRY1(SCRLOCK, SCROLLLOCK, SCROLL, VK_SCROLL, 0),
KEY_TRANS_ENTRY1(7_PAD, KP_7, NUMPAD7, VK_NUMPAD7, 0),
KEY_TRANS_ENTRY1(8_PAD, KP_8, NUMPAD8, VK_NUMPAD8, 0),
KEY_TRANS_ENTRY1(9_PAD, KP_9, NUMPAD9, VK_NUMPAD9, 0),
KEY_TRANS_ENTRY1(MINUS_PAD, KP_MINUS, SUBTRACT, VK_SUBTRACT, 0),
KEY_TRANS_ENTRY1(4_PAD, KP_4, NUMPAD4, VK_NUMPAD4, 0),
KEY_TRANS_ENTRY1(5_PAD, KP_5, NUMPAD5, VK_NUMPAD5, 0),
KEY_TRANS_ENTRY1(6_PAD, KP_6, NUMPAD6, VK_NUMPAD6, 0),
KEY_TRANS_ENTRY1(PLUS_PAD, KP_PLUS, ADD, VK_ADD, 0),
KEY_TRANS_ENTRY1(1_PAD, KP_1, NUMPAD1, VK_NUMPAD1, 0),
KEY_TRANS_ENTRY1(2_PAD, KP_2, NUMPAD2, VK_NUMPAD2, 0),
KEY_TRANS_ENTRY1(3_PAD, KP_3, NUMPAD3, VK_NUMPAD3, 0),
KEY_TRANS_ENTRY1(0_PAD, KP_0, NUMPAD0, VK_NUMPAD0, 0),
KEY_TRANS_ENTRY1(DEL_PAD, KP_PERIOD, DECIMAL, VK_DECIMAL, 0),
KEY_TRANS_ENTRY1(F11, F11, F11, VK_F11, 0),
KEY_TRANS_ENTRY1(F12, F12, F12, VK_F12, 0),
KEY_TRANS_ENTRY1(F13, F13, F13, VK_F13, 0),
KEY_TRANS_ENTRY1(F14, F14, F14, VK_F14, 0),
KEY_TRANS_ENTRY1(F15, F15, F15, VK_F15, 0),
KEY_TRANS_ENTRY1(ENTER_PAD, KP_ENTER, NUMPADENTER, VK_RETURN, 0),
KEY_TRANS_ENTRY1(RCONTROL, RCTRL, RCONTROL, VK_RCONTROL, 0),
KEY_TRANS_ENTRY1(SLASH_PAD, KP_DIVIDE, DIVIDE, VK_DIVIDE, 0),
KEY_TRANS_ENTRY1(PRTSCR, PRINTSCREEN, SYSRQ, 0, 0),
KEY_TRANS_ENTRY1(RALT, RALT, RMENU, VK_RMENU, 0),
KEY_TRANS_ENTRY1(HOME, HOME, HOME, VK_HOME, 0),
KEY_TRANS_ENTRY1(UP, UP, UP, VK_UP, 0),
KEY_TRANS_ENTRY1(PGUP, PAGEUP, PRIOR, VK_PRIOR, 0),
KEY_TRANS_ENTRY1(LEFT, LEFT, LEFT, VK_LEFT, 0),
KEY_TRANS_ENTRY1(RIGHT, RIGHT, RIGHT, VK_RIGHT, 0),
KEY_TRANS_ENTRY1(END, END, END, VK_END, 0),
KEY_TRANS_ENTRY1(DOWN, DOWN, DOWN, VK_DOWN, 0),
KEY_TRANS_ENTRY1(PGDN, PAGEDOWN, NEXT, VK_NEXT, 0),
KEY_TRANS_ENTRY1(INSERT, INSERT, INSERT, VK_INSERT, 0),
KEY_TRANS_ENTRY0(DEL, DELETE, DELETE, VK_DELETE, 0, "DELETE"),
KEY_TRANS_ENTRY1(LWIN, LGUI, LWIN, VK_LWIN, 0),
KEY_TRANS_ENTRY1(RWIN, RGUI, RWIN, VK_RWIN, 0),
KEY_TRANS_ENTRY1(MENU, MENU, APPS, VK_APPS, 0),
KEY_TRANS_ENTRY1(PAUSE, PAUSE, PAUSE, VK_PAUSE, 0),
KEY_TRANS_ENTRY0(CANCEL, CANCEL, UNKNOWN, 0, 0, "CANCEL"),
KEY_TRANS_ENTRY1(BS_PAD, KP_BACKSPACE, UNKNOWN, 0, 0),
KEY_TRANS_ENTRY1(TAB_PAD, KP_TAB, UNKNOWN, 0, 0),
KEY_TRANS_ENTRY1(00_PAD, KP_00, UNKNOWN, 0, 0),
KEY_TRANS_ENTRY1(000_PAD, KP_000, UNKNOWN, 0, 0),
KEY_TRANS_ENTRY1(COMMA_PAD, KP_COMMA, NUMPADCOMMA, 0, 0),
KEY_TRANS_ENTRY1(EQUALS_PAD, KP_EQUALS, NUMPADEQUALS, 0, 0),
// New keys introduced in Windows 2000. These have no MAME codes to
// preserve compatibility with old config files that may refer to them
@ -169,19 +169,19 @@ key_trans_entry keyboard_trans_table::s_default_table[] =
// 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")
KEY_TRANS_ENTRY1(OTHER_SWITCH, MUTE, MUTE, VK_VOLUME_MUTE, 0),
KEY_TRANS_ENTRY1(OTHER_SWITCH, VOLUMEDOWN, VOLUMEDOWN, VK_VOLUME_DOWN, 0),
KEY_TRANS_ENTRY1(OTHER_SWITCH, VOLUMEUP, VOLUMEUP, VK_VOLUME_UP, 0),
KEY_TRANS_ENTRY1(OTHER_SWITCH, AC_HOME, WEBHOME, VK_BROWSER_HOME, 0),
KEY_TRANS_ENTRY1(OTHER_SWITCH, AC_SEARCH, WEBSEARCH, VK_BROWSER_SEARCH, 0),
KEY_TRANS_ENTRY1(OTHER_SWITCH, AC_BOOKMARKS, WEBFAVORITES, VK_BROWSER_FAVORITES, 0),
KEY_TRANS_ENTRY1(OTHER_SWITCH, AC_REFRESH, WEBREFRESH, VK_BROWSER_REFRESH, 0),
KEY_TRANS_ENTRY1(OTHER_SWITCH, AC_STOP, WEBSTOP, VK_BROWSER_STOP, 0),
KEY_TRANS_ENTRY1(OTHER_SWITCH, AC_FORWARD, WEBFORWARD, VK_BROWSER_FORWARD, 0),
KEY_TRANS_ENTRY1(OTHER_SWITCH, AC_BACK, WEBBACK, VK_BROWSER_BACK, 0),
KEY_TRANS_ENTRY1(OTHER_SWITCH, MAIL, MAIL, VK_LAUNCH_MAIL, 0),
KEY_TRANS_ENTRY1(OTHER_SWITCH, MEDIASELECT, MEDIASELECT, VK_LAUNCH_MEDIA_SELECT, 0),
KEY_TRANS_ENTRY0(INVALID, UNKNOWN, ESCAPE, 0, 0, "INVALID")
};
// The private constructor to create the default instance
@ -226,14 +226,12 @@ input_item_id keyboard_trans_table::lookup_mame_code(const char *scode) const
}
// Windows specific lookup methods
#if defined(OSD_WINDOWS)
#if defined(OSD_WINDOWS) || defined(SDLMAME_WIN32)
input_item_id keyboard_trans_table::map_di_scancode_to_itemid(int scancode) const
{
int tablenum;
// scan the table for a match
for (tablenum = 0; tablenum < m_table_size; tablenum++)
for (int tablenum = 0; tablenum < m_table_size; tablenum++)
if (m_table[tablenum].scan_code == scancode)
return m_table[tablenum].mame_key;
@ -261,64 +259,43 @@ int keyboard_trans_table::vkey_for_mame_code(input_code code) const
return 0;
}
#endif
#endif // defined(OSD_WINDOWS) || defined(SDLMAME_WIN32)
int input_module_base::init(const osd_options &options)
input_module_base::input_module_base(const char *type, const char* name) :
osd_module(type, name),
m_clock(),
m_last_poll(timepoint_type::min()),
m_background_input(false),
m_options(nullptr),
m_manager(nullptr)
{
}
int input_module_base::init(osd_interface &osd, 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;
// don't enable background input when debugging
m_background_input = !options.debug() && options.background_input();
return 0;
}
void input_module_base::poll(running_machine &machine)
void input_module_base::input_init(running_machine &machine)
{
// ignore if not enabled
if (m_input_enabled)
m_manager = &machine.input();
}
void input_module_base::poll_if_necessary()
{
timepoint_type const now = m_clock.now();
if (now >= (m_last_poll + std::chrono::milliseconds(MIN_POLLING_INTERVAL)))
{
// grab the current time
m_last_poll = m_clock.now();
m_last_poll = now;
before_poll(machine);
before_poll();
// 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();
poll();
}
}
void input_module_base::pause()
{
// keep track of the paused state
m_input_paused = true;
}
void input_module_base::resume()
{
// keep track of the paused state
m_input_paused = false;
}
void input_module_base::exit()
{
devicelist().free_all_devices();
}

View File

@ -15,8 +15,12 @@
#include "input_module.h"
#include "interface/inputman.h"
#include "modules/osdmodule.h"
#include "util/strformat.h"
#include <algorithm>
#include <cassert>
#include <chrono>
#include <functional>
#include <memory>
@ -191,76 +195,66 @@ enum
#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:
const std::string m_name;
const std::string m_id;
osd::input_device * m_device;
running_machine & m_machine;
input_module & m_module;
input_device_class m_deviceclass;
public:
// Constructor
device_info(running_machine &machine, std::string &&name, std::string &&id, input_device_class deviceclass, input_module &module) :
device_info(std::string &&name, std::string &&id, input_module &module) :
m_name(std::move(name)),
m_id(std::move(id)),
m_device(nullptr),
m_machine(machine),
m_module(module),
m_deviceclass(deviceclass)
m_module(module)
{
}
// Destructor
virtual ~device_info() { }
virtual ~device_info() = default;
// Getters
running_machine & machine() const { return m_machine; }
const std::string & name() const { return m_name; }
const std::string & id() const { return m_id; }
osd::input_device * device() const { return m_device; }
input_module & module() const { return m_module; }
input_device_class deviceclass() const { return m_deviceclass; }
const std::string &name() const { return m_name; }
const std::string &id() const { return m_id; }
input_module &module() const { return m_module; }
// Poll and reset methods
virtual void poll() { }
virtual void reset() = 0;
virtual void configure(osd::input_device &device) = 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;
static inline constexpr unsigned DEFAULT_EVENT_QUEUE_SIZE = 20;
std::queue<TEvent> m_event_queue;
protected:
std::mutex m_device_lock;
virtual void process_event(TEvent &ev) = 0;
virtual void process_event(TEvent const &ev) = 0;
public:
event_based_device(running_machine &machine, std::string &&name, std::string &&id, input_device_class deviceclass, input_module &module) :
device_info(machine, std::move(name), std::move(id), deviceclass, module)
event_based_device(std::string &&name, std::string &&id, input_module &module) :
device_info(std::move(name), std::move(id), module)
{
}
void queue_events(const TEvent *events, int count)
void queue_events(TEvent const *events, int count)
{
std::lock_guard<std::mutex> scope_lock(m_device_lock);
for (int i = 0; i < count; i++)
@ -278,27 +272,28 @@ public:
// Process each event until the queue is empty
while (!m_event_queue.empty())
{
TEvent &next_event = m_event_queue.front();
process_event(next_event);
process_event(m_event_queue.front());
m_event_queue.pop();
}
}
};
//============================================================
// input_device_list class
//============================================================
template <typename Info>
class input_device_list
{
private:
std::vector<std::unique_ptr<device_info>> m_list;
std::vector<std::unique_ptr<Info> > m_list;
public:
auto size() const { return m_list.size(); }
auto empty() const { return m_list.empty(); }
auto begin() { return m_list.begin(); }
auto end() { return m_list.end(); }
auto begin() const { return m_list.begin(); }
auto end() const { return m_list.end(); }
void poll_devices()
{
@ -312,18 +307,11 @@ public:
device->reset();
}
void free_device(device_info &devinfo)
{
// find the device to remove
const auto device_matches = [&devinfo] (std::unique_ptr<device_info> &device) { return &devinfo == device.get(); };
m_list.erase(std::remove_if(std::begin(m_list), std::end(m_list), device_matches), m_list.end());
}
template <typename T>
void for_each_device(T &&action)
{
for (auto &device: m_list)
action(device.get());
action(*device);
}
void free_all_devices()
@ -332,41 +320,34 @@ public:
m_list.pop_back();
}
template <typename TActual, typename... TArgs>
TActual &create_device(running_machine &machine, std::string &&name, std::string &&id, input_module &module, TArgs &&... args)
template <typename Actual>
Actual &add_device(std::unique_ptr<Actual> &&devinfo)
{
// allocate the device object
auto devinfo = std::make_unique<TActual>(machine, std::move(name), std::move(id), module, std::forward<TArgs>(args)...);
return add_device(machine.input(), std::move(devinfo));
}
template <typename TActual>
TActual &add_device(osd::input_manager &manager, std::unique_ptr<TActual> &&devinfo)
{
// Add the device to the machine
devinfo->m_device = &manager.add_device(devinfo->deviceclass(), devinfo->name(), devinfo->id(), devinfo.get());
// append us to the list
return *static_cast<TActual *>(m_list.emplace_back(std::move(devinfo)).get());
// append us to the list and return reference
Actual &result = *devinfo;
m_list.emplace_back(std::move(devinfo));
return result;
}
};
// keyboard translation table
struct key_trans_entry {
struct key_trans_entry
{
input_item_id mame_key;
#if defined(OSD_SDL)
#if defined(OSD_SDL) || defined(SDLMAME_WIN32)
int sdl_scancode;
#elif defined(OSD_WINDOWS)
#endif
#if defined(OSD_WINDOWS) || defined(SDLMAME_WIN32)
int scan_code;
unsigned char virtual_key;
#endif
char ascii_key;
char const * mame_key_name;
char * ui_name;
char const * mame_key_name;
char const * ui_name;
};
class keyboard_trans_table
@ -379,7 +360,7 @@ private:
std::unique_ptr<key_trans_entry[]> m_custom_table;
key_trans_entry * m_table;
uint32_t m_table_size;
uint32_t m_table_size;
public:
// constructor
@ -392,7 +373,7 @@ public:
input_item_id lookup_mame_code(const char * scode) const;
int lookup_mame_index(const char * scode) const;
#if defined(OSD_WINDOWS)
#if defined(OSD_WINDOWS) || defined(SDLMAME_WIN32)
input_item_id map_di_scancode_to_itemid(int di_scancode) const;
int vkey_for_mame_code(input_code code) const;
#endif
@ -406,75 +387,122 @@ public:
key_trans_entry & operator [](int i) const { return m_table[i]; }
};
//============================================================
// input_module_base - base class for input modules
//============================================================
class osd_options;
class input_module_base : public osd_module, public input_module
{
private:
// 10 milliseconds polling interval
static constexpr inline unsigned MIN_POLLING_INTERVAL = 10;
typedef std::chrono::high_resolution_clock clock_type;
typedef std::chrono::time_point<std::chrono::high_resolution_clock> timepoint_type;
using clock_type = std::chrono::high_resolution_clock;
using timepoint_type = std::chrono::time_point<std::chrono::high_resolution_clock>;
// 10 milliseconds polling interval
#define MIN_POLLING_INTERVAL 10
clock_type m_clock;
timepoint_type m_last_poll;
bool m_background_input;
const osd_options * m_options;
osd::input_manager * m_manager;
class input_module_base : public input_module
virtual void poll() = 0;
protected:
input_module_base(char const *type, char const *name);
osd::input_manager & manager() { assert(m_manager); return *m_manager; }
const osd_options * options() const { return m_options; }
bool background_input() const { return m_background_input; }
virtual void before_poll() { }
public:
virtual int init(osd_interface &osd, const osd_options &options) override;
virtual void input_init(running_machine &machine) override;
virtual void poll_if_necessary() override;
virtual void reset_devices() = 0; // SDL OSD uses this to forcibly release keys
};
//============================================================
// input_module_impl - base class for input modules
//============================================================
template <typename Info, typename OsdImpl>
class input_module_impl : public input_module_base
{
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),
m_options(nullptr)
virtual void exit() override
{
devicelist().free_all_devices();
}
virtual int init(osd_interface &osd, const osd_options &options) override
{
m_osd = dynamic_cast<OsdImpl *>(&osd);
if (!m_osd)
return -1;
return input_module_base::init(osd, options);
}
virtual void reset_devices() override { devicelist().reset_devices(); }
protected:
using input_module_base::input_module_base;
input_device_list<Info> &devicelist() { return m_devicelist; }
OsdImpl &osd() { assert(m_osd); return *m_osd; }
virtual void before_poll() override
{
// periodically process events, in case they're not coming through
// this also will make sure the mouse state is up-to-date
osd().process_events();
}
virtual bool should_poll_devices()
{
return background_input() || osd().has_focus();
}
template <typename Actual, typename... Params>
Actual &create_device(input_device_class deviceclass, std::string &&name, std::string &&id, Params &&... args)
{
// allocate the device object and add it to the input manager
return add_device(
deviceclass,
std::make_unique<Actual>(std::move(name), std::move(id), *this, std::forward<Params>(args)...));
}
template <typename Actual>
Actual &add_device(input_device_class deviceclass, std::unique_ptr<Actual> &&devinfo)
{
// add it to the input manager and append it to the list
osd::input_device &osddev = manager().add_device(deviceclass, devinfo->name(), devinfo->id(), devinfo.get());
devinfo->configure(osddev);
return devicelist().add_device(std::move(devinfo));
}
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() const { return m_options; }
input_device_list & devicelist() { return m_devicelist; }
bool input_enabled() const { return m_input_enabled; }
bool input_paused() const { return m_input_paused; }
bool mouse_enabled() const { return m_mouse_enabled; }
bool lightgun_enabled() const { return m_lightgun_enabled; }
virtual int init(const osd_options &options) override;
virtual void poll_if_necessary(running_machine &machine) override
virtual void poll() override final
{
auto elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(m_clock.now() - m_last_poll);
if (elapsed.count() >= MIN_POLLING_INTERVAL)
{
poll(machine);
}
// poll all of the devices
if (should_poll_devices())
m_devicelist.poll_devices();
else
m_devicelist.reset_devices();
}
virtual void pause() override;
virtual void resume() override;
virtual void exit() override;
protected:
virtual int init_internal() { return 0; }
virtual void poll(running_machine &machine);
virtual bool should_poll_devices(running_machine &machine) = 0;
virtual void before_poll(running_machine &machine) { }
input_device_list<Info> m_devicelist;
OsdImpl *m_osd = nullptr;
};
template <class TItem>
int generic_button_get_state(void *device_internal, void *item_internal)
{
@ -482,10 +510,11 @@ int generic_button_get_state(void *device_internal, void *item_internal)
TItem *itemdata = static_cast<TItem*>(item_internal);
// return the current state
devinfo->module().poll_if_necessary(devinfo->machine());
devinfo->module().poll_if_necessary();
return *itemdata >> 7;
}
template <class TItem>
int generic_axis_get_state(void *device_internal, void *item_internal)
{
@ -493,10 +522,11 @@ int generic_axis_get_state(void *device_internal, void *item_internal)
TItem *axisdata = static_cast<TItem*>(item_internal);
// return the current state
devinfo->module().poll_if_necessary(devinfo->machine());
devinfo->module().poll_if_necessary();
return *axisdata;
}
//============================================================
// default_button_name
//============================================================
@ -524,23 +554,22 @@ const char *const default_axis_name[] =
inline int32_t normalize_absolute_axis(double raw, double rawmin, double rawmax)
{
double center = (rawmax + rawmin) / 2.0;
// make sure we have valid data
// make sure we have valid arguments
if (rawmin >= rawmax)
return int32_t(raw);
double const center = (rawmax + rawmin) / 2.0;
if (raw >= center)
{
// above center
double result = (raw - center) * osd::INPUT_ABSOLUTE_MAX / (rawmax - center);
return std::min(result, (double)osd::INPUT_ABSOLUTE_MAX);
double const result = (raw - center) * double(osd::INPUT_ABSOLUTE_MAX) / (rawmax - center);
return int32_t(std::min(result, double(osd::INPUT_ABSOLUTE_MAX)));
}
else
{
// below center
double result = -((center - raw) * (double)-osd::INPUT_ABSOLUTE_MIN / (center - rawmin));
return std::max(result, (double)osd::INPUT_ABSOLUTE_MIN);
double result = -((center - raw) * double(-osd::INPUT_ABSOLUTE_MIN) / (center - rawmin));
return int32_t(std::max(result, double(osd::INPUT_ABSOLUTE_MIN)));
}
}

View File

@ -8,71 +8,39 @@
#include "modules/osdmodule.h"
#if defined(OSD_WINDOWS)
#if defined(OSD_WINDOWS) || defined(SDLMAME_WIN32)
#include "emu.h"
// emu
#include "emu.h" // put this here before Windows headers define interface as a macro
#include "input_dinput.h"
#include "winutil.h"
#include "windows/winutil.h"
#include <mutex>
// lib/util
#include "util/corestr.h"
#ifdef SDLMAME_WIN32
#include <SDL2/SDL.h>
#include <SDL2/SDL_syswm.h>
#endif
#include <algorithm>
#include <iterator>
#include <memory>
// standard windows headers
#include <initguid.h>
#include <tchar.h>
namespace osd {
namespace {
using namespace Microsoft::WRL;
//============================================================
// dinput_joystick_pov_get_state
//============================================================
int32_t dinput_joystick_pov_get_state(void *device_internal, void *item_internal)
BOOL CALLBACK device_enum_interface_callback(LPCDIDEVICEINSTANCE instance, LPVOID ref)
{
auto *devinfo = static_cast<dinput_joystick_device *>(device_internal);
int povnum = reinterpret_cast<uintptr_t>(item_internal) / 4;
int povdir = reinterpret_cast<uintptr_t>(item_internal) % 4;
int32_t result = 0;
// get the current state
devinfo->module().poll_if_necessary(devinfo->machine());
const DWORD 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;
}
//============================================================
// dinput_set_dword_property
//============================================================
HRESULT dinput_set_dword_property(ComPtr<IDirectInputDevice8> 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 device->SetProperty(property_guid, &dipdw.diph);
return static_cast<device_enum_interface *>(ref)->device_enum_callback(instance);
}
@ -80,76 +48,52 @@ HRESULT dinput_set_dword_property(ComPtr<IDirectInputDevice8> device, REFGUID pr
// dinput_module - base directinput module
//============================================================
class dinput_module : public wininput_module, public device_enum_interface
class dinput_module : public input_module_impl<dinput_device, osd_common_t>, public device_enum_interface
{
protected:
std::unique_ptr<dinput_api_helper> m_dinput_helper;
public:
dinput_module(const char* type, const char* name)
: wininput_module(type, name),
m_dinput_helper(nullptr)
dinput_module(const char* type, const char* name) :
input_module_impl<dinput_device, osd_common_t>(type, name),
m_dinput_helper(nullptr)
{
}
int init_internal() override
virtual int init(osd_interface &osd, osd_options const &options) override
{
m_dinput_helper = std::make_unique<dinput_api_helper>();
int result = m_dinput_helper->initialize();
if (result != 0)
return result;
return 0;
}
void exit() override
{
wininput_module::exit();
m_dinput_helper.reset();
}
void input_init(running_machine &machine) override
{
HRESULT result = m_dinput_helper->enum_attached_devices(dinput_devclass(), this, &machine);
if (result != DI_OK)
fatalerror("DirectInput: Unable to enumerate devices (result=%08X)\n", uint32_t(result));
}
static std::string device_item_name(dinput_device *devinfo, int offset, const char *defstring, const char *suffix)
{
DIDEVICEOBJECTINSTANCE instance = { 0 };
HRESULT result;
// query the key name
instance.dwSize = sizeof(instance);
result = devinfo->dinput.device->GetObjectInfo(&instance, offset, DIPH_BYOFFSET);
// if we got an error and have no default string, just return nullptr
if (result != DI_OK)
int const result = m_dinput_helper->initialize();
if (result)
{
if (defstring == nullptr)
return nullptr;
// Return the default value
std::string result(defstring);
if (suffix)
result.append(" ").append(suffix);
m_dinput_helper.reset();
return result;
}
// convert the name to utf8
std::string namestring = osd::text::from_tstring(instance.tszName);
return input_module_impl<dinput_device, osd_common_t>::init(osd, options);
}
// if no suffix, return as-is
if (suffix)
namestring.append(" ").append(suffix);
return namestring;
virtual void exit() override
{
input_module_impl<dinput_device, osd_common_t>::exit();
m_dinput_helper.reset();
}
virtual void input_init(running_machine &machine) override
{
input_module_impl<dinput_device, osd_common_t>::input_init(machine);
HRESULT result = m_dinput_helper->enum_attached_devices(dinput_devclass(), *this);
if (result != DI_OK)
fatalerror("DirectInput: Unable to enumerate devices (result=%08X)\n", uint32_t(result));
}
protected:
virtual int dinput_devclass() = 0;
};
class keyboard_input_dinput : public dinput_module
{
public:
@ -158,42 +102,29 @@ public:
{
}
int dinput_devclass() override
virtual int dinput_devclass() override
{
return DI8DEVCLASS_KEYBOARD;
}
BOOL device_enum_callback(LPCDIDEVICEINSTANCE instance, LPVOID ref) override
virtual BOOL device_enum_callback(LPCDIDEVICEINSTANCE instance) override
{
running_machine &machine = *static_cast<running_machine *>(ref);
dinput_keyboard_device *devinfo;
int keynum;
// allocate and link in a new device
devinfo = m_dinput_helper->create_device<dinput_keyboard_device>(machine, *this, instance, &c_dfDIKeyboard, nullptr, dinput_cooperative_level::FOREGROUND);
if (devinfo == nullptr)
goto exit;
auto devinfo = m_dinput_helper->create_device<dinput_keyboard_device>(
*this,
instance,
&c_dfDIKeyboard,
nullptr,
background_input() ? dinput_cooperative_level::BACKGROUND : dinput_cooperative_level::FOREGROUND,
[] (auto...) { return true; });
if (devinfo)
add_device(DEVICE_CLASS_KEYBOARD, std::move(devinfo));
// 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, std::size(defname), "Scan%03d", keynum);
name = device_item_name(devinfo, keynum, defname, nullptr);
// add the item to the device
devinfo->device()->add_item(name, itemid, generic_button_get_state<std::uint8_t>, &devinfo->keyboard.state[keynum]);
}
exit:
return DIENUM_CONTINUE;
}
};
class mouse_input_dinput : public dinput_module
{
public:
@ -202,68 +133,40 @@ public:
{
}
int dinput_devclass() override
virtual int dinput_devclass() override
{
return DI8DEVCLASS_POINTER;
}
BOOL device_enum_callback(LPCDIDEVICEINSTANCE instance, LPVOID ref) override
virtual BOOL device_enum_callback(LPCDIDEVICEINSTANCE instance) override
{
dinput_mouse_device *devinfo = nullptr;
running_machine &machine = *static_cast<running_machine *>(ref);
int axisnum, butnum;
HRESULT result;
// allocate and link in a new device
devinfo = m_dinput_helper->create_device<dinput_mouse_device>(machine, *this, instance, &c_dfDIMouse2, &c_dfDIMouse, dinput_cooperative_level::FOREGROUND);
if (!devinfo)
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 %u (%s)\n", static_cast<unsigned int>(devicelist().size()), devinfo->name());
goto error;
}
// cap the number of axes and buttons based on the format
devinfo->dinput.caps.dwAxes = std::min(devinfo->dinput.caps.dwAxes, DWORD(3));
devinfo->dinput.caps.dwButtons = std::min(devinfo->dinput.caps.dwButtons, DWORD((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], nullptr);
devinfo->device()->add_item(
name,
static_cast<input_item_id>(ITEM_ID_XAXIS + axisnum),
generic_axis_get_state<LONG>,
&devinfo->mouse.lX + axisnum);
}
// populate the buttons
for (butnum = 0; butnum < devinfo->dinput.caps.dwButtons; butnum++)
{
auto offset = reinterpret_cast<uintptr_t>(&static_cast<DIMOUSESTATE *>(nullptr)->rgbButtons[butnum]);
// add to the mouse device
std::string name = device_item_name(devinfo, offset, default_button_name(butnum).c_str(), nullptr);
devinfo->device()->add_item(
name,
static_cast<input_item_id>(ITEM_ID_BUTTON1 + butnum),
generic_button_get_state<BYTE>,
&devinfo->mouse.rgbButtons[butnum]);
}
exit:
return DIENUM_CONTINUE;
error:
auto devinfo = m_dinput_helper->create_device<dinput_mouse_device>(
*this,
instance,
&c_dfDIMouse2,
&c_dfDIMouse,
background_input() ? dinput_cooperative_level::BACKGROUND : dinput_cooperative_level::FOREGROUND,
[] (auto const &device, auto const &format) -> bool
{
// set relative mode
HRESULT const result = dinput_api_helper::set_dword_property(
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.\n");
return false;
}
return true;
});
if (devinfo)
devicelist().free_device(*devinfo);
goto exit;
add_device(DEVICE_CLASS_MOUSE, std::move(devinfo));
return DIENUM_CONTINUE;
}
};
@ -276,33 +179,39 @@ public:
{
}
int dinput_devclass() override
virtual int dinput_devclass() override
{
return DI8DEVCLASS_GAMECTRL;
}
BOOL device_enum_callback(LPCDIDEVICEINSTANCE instance, LPVOID ref) override
virtual BOOL device_enum_callback(LPCDIDEVICEINSTANCE instance) override
{
dinput_cooperative_level cooperative_level = dinput_cooperative_level::FOREGROUND;
running_machine &machine = *static_cast<running_machine *>(ref);
dinput_joystick_device *devinfo;
int result = 0;
if (!osd_common_t::s_window_list.empty() && osd_common_t::s_window_list.front()->win_has_menu())
cooperative_level = dinput_cooperative_level::BACKGROUND;
// allocate and link in a new device
devinfo = m_dinput_helper->create_device<dinput_joystick_device>(machine, *this, instance, &c_dfDIJoystick, nullptr, cooperative_level);
if (devinfo == nullptr)
goto exit;
auto devinfo = m_dinput_helper->create_device<dinput_joystick_device>(
*this,
instance,
&c_dfDIJoystick,
nullptr,
background_input() ? dinput_cooperative_level::BACKGROUND : dinput_cooperative_level::FOREGROUND,
[] (auto const &device, auto const &format) -> bool
{
// set absolute mode
HRESULT const result = dinput_api_helper::set_dword_property(
device,
DIPROP_AXISMODE,
0,
DIPH_DEVICE,
DIPROPAXISMODE_ABS);
if ((result != DI_OK) && (result != DI_PROPNOEFFECT))
{
osd_printf_error("DirectInput: Unable to set absolute mode for joystick.\n");
return false;
}
return true;
});
if (devinfo)
add_device(DEVICE_CLASS_JOYSTICK, std::move(devinfo));
result = devinfo->configure();
if (result != 0)
{
osd_printf_error("Failed to configure DI Joystick device. Error 0x%x\n", static_cast<unsigned int>(result));
}
exit:
return DIENUM_CONTINUE;
}
};
@ -314,62 +223,110 @@ public:
// dinput_device - base directinput device
//============================================================
dinput_device::dinput_device(running_machine &machine, std::string &&name, std::string &&id, input_device_class deviceclass, input_module &module) :
device_info(machine, std::move(name), std::move(id), deviceclass, module),
dinput({nullptr})
dinput_device::dinput_device(
std::string &&name,
std::string &&id,
input_module &module,
Microsoft::WRL::ComPtr<IDirectInputDevice8> &&device,
DIDEVCAPS const &caps,
LPCDIDATAFORMAT format) :
device_info(std::move(name), std::move(id), module),
m_device(std::move(device)),
m_caps(caps),
m_format(format)
{
}
dinput_device::~dinput_device()
{
if (dinput.device)
dinput.device.Reset();
}
HRESULT dinput_device::poll_dinput(LPVOID pState) const
{
HRESULT result;
// first poll the device, then get the state
dinput.device->Poll();
// GetDeviceState returns the immediate state
result = dinput.device->GetDeviceState(dinput.format->dwDataSize, pState);
result = m_device->Poll();
// handle lost inputs here
if (result == DIERR_INPUTLOST || result == DIERR_NOTACQUIRED)
if ((result == DIERR_INPUTLOST) || (result == DIERR_NOTACQUIRED))
{
result = dinput.device->Acquire();
if (result == DI_OK)
result = dinput.device->GetDeviceState(dinput.format->dwDataSize, pState);
result = m_device->Acquire();
if ((result == DI_OK) || (result == S_FALSE))
result = m_device->Poll();
}
// GetDeviceState returns the immediate state
if ((result == DI_OK) || (result == DI_NOEFFECT))
result = m_device->GetDeviceState(m_format->dwDataSize, pState);
return result;
}
std::string dinput_device::item_name(int offset, std::string_view defstring, const char *suffix) const
{
// query the key name
DIDEVICEOBJECTINSTANCE instance = { 0 };
instance.dwSize = sizeof(instance);
HRESULT const result = m_device->GetObjectInfo(&instance, offset, DIPH_BYOFFSET);
// use the default value if it failed
std::string name;
if (result != DI_OK)
name = defstring;
else
name = text::from_tstring(instance.tszName);
// if no suffix, return as-is
if (suffix)
name.append(" ").append(suffix);
return name;
}
//============================================================
// dinput_keyboard_device - directinput keyboard device
//============================================================
dinput_keyboard_device::dinput_keyboard_device(running_machine &machine, std::string &&name, std::string &&id, input_module &module) :
dinput_device(machine, std::move(name), std::move(id), DEVICE_CLASS_KEYBOARD, module),
keyboard({{0}})
dinput_keyboard_device::dinput_keyboard_device(
std::string &&name,
std::string &&id,
input_module &module,
Microsoft::WRL::ComPtr<IDirectInputDevice8> &&device,
DIDEVCAPS const &caps,
LPCDIDATAFORMAT format) :
dinput_device(std::move(name), std::move(id), module, std::move(device), caps, format),
m_keyboard({ { 0 } })
{
}
// Polls the direct input immediate state
void dinput_keyboard_device::poll()
{
// poll the DirectInput immediate state
std::lock_guard<std::mutex> scope_lock(m_device_lock);
// Poll the state
dinput_device::poll_dinput(&keyboard.state);
poll_dinput(&m_keyboard.state);
}
void dinput_keyboard_device::reset()
{
memset(&keyboard.state, 0, sizeof(keyboard.state));
memset(&m_keyboard.state, 0, sizeof(m_keyboard.state));
}
void dinput_keyboard_device::configure(input_device &device)
{
// populate it
char defname[20];
for (int keynum = 0; keynum < MAX_KEYS; keynum++)
{
input_item_id itemid = keyboard_trans_table::instance().map_di_scancode_to_itemid(keynum);
// generate/fetch the name
snprintf(defname, std::size(defname), "Scan%03d", keynum);
// add the item to the device
device.add_item(
item_name(keynum, defname, nullptr),
itemid,
generic_button_get_state<std::uint8_t>,
&m_keyboard.state[keynum]);
}
}
@ -377,26 +334,63 @@ void dinput_keyboard_device::reset()
// dinput_mouse_device - directinput mouse device
//============================================================
dinput_mouse_device::dinput_mouse_device(running_machine &machine, std::string &&name, std::string &&id, input_module &module) :
dinput_device(machine, std::move(name), std::move(id), DEVICE_CLASS_MOUSE, module),
mouse({0})
dinput_mouse_device::dinput_mouse_device(
std::string &&name,
std::string &&id,
input_module &module,
Microsoft::WRL::ComPtr<IDirectInputDevice8> &&device,
DIDEVCAPS const &caps,
LPCDIDATAFORMAT format) :
dinput_device(std::move(name), std::move(id), module, std::move(device), caps, format),
m_mouse({0})
{
// cap the number of axes and buttons based on the format
m_caps.dwAxes = std::min(m_caps.dwAxes, DWORD(3));
m_caps.dwButtons = std::min(m_caps.dwButtons, DWORD((m_format == &c_dfDIMouse) ? 4 : 8));
}
void dinput_mouse_device::poll()
{
// poll
dinput_device::poll_dinput(&mouse);
// scale the axis data
mouse.lX *= osd::INPUT_RELATIVE_PER_PIXEL;
mouse.lY *= osd::INPUT_RELATIVE_PER_PIXEL;
mouse.lZ *= osd::INPUT_RELATIVE_PER_PIXEL;
if (poll_dinput(&m_mouse) == DI_OK)
{
// scale the axis data
m_mouse.lX *= INPUT_RELATIVE_PER_PIXEL;
m_mouse.lY *= INPUT_RELATIVE_PER_PIXEL;
m_mouse.lZ *= INPUT_RELATIVE_PER_PIXEL;
}
}
void dinput_mouse_device::reset()
{
memset(&mouse, 0, sizeof(mouse));
memset(&m_mouse, 0, sizeof(m_mouse));
}
void dinput_mouse_device::configure(input_device &device)
{
// populate the axes
for (int axisnum = 0; axisnum < m_caps.dwAxes; axisnum++)
{
// add to the mouse device and optionally to the gun device as well
device.add_item(
item_name(offsetof(DIMOUSESTATE, lX) + axisnum * sizeof(LONG), default_axis_name[axisnum], nullptr),
input_item_id(ITEM_ID_XAXIS + axisnum),
generic_axis_get_state<LONG>,
&m_mouse.lX + axisnum);
}
// populate the buttons
for (int butnum = 0; butnum < m_caps.dwButtons; butnum++)
{
auto offset = reinterpret_cast<uintptr_t>(&static_cast<DIMOUSESTATE *>(nullptr)->rgbButtons[butnum]);
// add to the mouse device
device.add_item(
item_name(offset, default_button_name(butnum), nullptr),
input_item_id(ITEM_ID_BUTTON1 + butnum),
generic_button_get_state<BYTE>,
&m_mouse.rgbButtons[butnum]);
}
}
@ -404,64 +398,58 @@ void dinput_mouse_device::reset()
// dinput_joystick_device - directinput joystick device
//============================================================
dinput_joystick_device::dinput_joystick_device(running_machine &machine, std::string &&name, std::string &&id, input_module &module) :
dinput_device(machine, std::move(name), std::move(id), DEVICE_CLASS_JOYSTICK, module),
joystick({{0}})
dinput_joystick_device::dinput_joystick_device(
std::string &&name,
std::string &&id,
input_module &module,
Microsoft::WRL::ComPtr<IDirectInputDevice8> &&device,
DIDEVCAPS const &caps,
LPCDIDATAFORMAT format) :
dinput_device(std::move(name), std::move(id), module, std::move(device), caps, format),
m_joystick({ { 0 } })
{
// cap the number of axes, POVs, and buttons based on the format
m_caps.dwAxes = std::min(m_caps.dwAxes, DWORD(8));
m_caps.dwPOVs = std::min(m_caps.dwPOVs, DWORD(4));
m_caps.dwButtons = std::min(m_caps.dwButtons, DWORD(128));
}
void dinput_joystick_device::reset()
{
memset(&joystick.state, 0, sizeof(joystick.state));
std::fill(std::begin(joystick.state.rgdwPOV), std::end(joystick.state.rgdwPOV), 0xffff);
memset(&m_joystick.state, 0, sizeof(m_joystick.state));
std::fill(std::begin(m_joystick.state.rgdwPOV), std::end(m_joystick.state.rgdwPOV), 0xffff);
}
void dinput_joystick_device::poll()
{
int axisnum;
// poll the device first
if (dinput_device::poll_dinput(&joystick.state) != ERROR_SUCCESS)
return;
// normalize axis values
for (axisnum = 0; axisnum < 8; axisnum++)
if (dinput_device::poll_dinput(&m_joystick.state) == DI_OK)
{
LONG *axis = (&joystick.state.lX) + axisnum;
*axis = normalize_absolute_axis(*axis, joystick.rangemin[axisnum], joystick.rangemax[axisnum]);
// normalize axis values
for (int axisnum = 0; axisnum < 8; axisnum++)
{
LONG *const axis = &m_joystick.state.lX + axisnum;
*axis = normalize_absolute_axis(*axis, m_joystick.rangemin[axisnum], m_joystick.rangemax[axisnum]);
}
}
}
int dinput_joystick_device::configure()
void dinput_joystick_device::configure(input_device &device)
{
HRESULT result;
auto &devicelist = static_cast<input_module_base&>(module()).devicelist();
// temporary approximation of index
int devindex = devicelist.size();
// set absolute mode
result = dinput_set_dword_property(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", devindex, name());
// turn off deadzone; we do our own calculations
result = dinput_set_dword_property(dinput.device, DIPROP_DEADZONE, 0, DIPH_DEVICE, 0);
result = dinput_api_helper::set_dword_property(m_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", devindex, name());
osd_printf_warning("DirectInput: Unable to reset deadzone for joystick %s.\n", name());
// turn off saturation; we do our own calculations
result = dinput_set_dword_property(dinput.device, DIPROP_SATURATION, 0, DIPH_DEVICE, 10000);
result = dinput_api_helper::set_dword_property(m_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", devindex, name());
// cap the number of axes, POVs, and buttons based on the format
dinput.caps.dwAxes = std::min(dinput.caps.dwAxes, DWORD(8));
dinput.caps.dwPOVs = std::min(dinput.caps.dwPOVs, DWORD(4));
dinput.caps.dwButtons = std::min(dinput.caps.dwButtons, DWORD(128));
osd_printf_warning("DirectInput: Unable to reset saturation for joystick %s.\n", name());
// populate the axes
for (uint32_t axisnum = 0, axiscount = 0; axiscount < dinput.caps.dwAxes && axisnum < 8; axisnum++)
for (uint32_t axisnum = 0, axiscount = 0; axiscount < m_caps.dwAxes && axisnum < 8; axisnum++)
{
// fetch the range of this axis
DIPROPRANGE dipr;
@ -469,67 +457,62 @@ int dinput_joystick_device::configure()
dipr.diph.dwHeaderSize = sizeof(dipr.diph);
dipr.diph.dwObj = offsetof(DIJOYSTATE2, lX) + axisnum * sizeof(LONG);
dipr.diph.dwHow = DIPH_BYOFFSET;
result = dinput.device->GetProperty(DIPROP_RANGE, &dipr.diph);
result = m_device->GetProperty(DIPROP_RANGE, &dipr.diph);
if (result != DI_OK)
{
osd_printf_verbose("DirectInput: Unable to get properties for joystick %s axis %u.\n", name(), axisnum);
continue;
}
joystick.rangemin[axisnum] = dipr.lMin;
joystick.rangemax[axisnum] = dipr.lMax;
m_joystick.rangemin[axisnum] = dipr.lMin;
m_joystick.rangemax[axisnum] = dipr.lMax;
// populate the item description as well
std::string name = dinput_module::device_item_name(this, offsetof(DIJOYSTATE2, lX) + axisnum * sizeof(LONG), default_axis_name[axisnum], nullptr);
device()->add_item(
name,
static_cast<input_item_id>(ITEM_ID_XAXIS + axisnum),
generic_axis_get_state<LONG>,
&joystick.state.lX + axisnum);
device.add_item(
item_name(offsetof(DIJOYSTATE2, lX) + axisnum * sizeof(LONG), default_axis_name[axisnum], nullptr),
input_item_id(ITEM_ID_XAXIS + axisnum),
generic_axis_get_state<LONG>,
&m_joystick.state.lX + axisnum);
axiscount++;
}
// populate the POVs
for (uint32_t povnum = 0; povnum < dinput.caps.dwPOVs; povnum++)
for (uint32_t povnum = 0; povnum < m_caps.dwPOVs; povnum++)
{
std::string name;
// left
name = dinput_module::device_item_name(this, offsetof(DIJOYSTATE2, rgdwPOV) + povnum * sizeof(DWORD), default_pov_name(povnum).c_str(), "Left");
device()->add_item(
name,
device.add_item(
item_name(offsetof(DIJOYSTATE2, rgdwPOV) + povnum * sizeof(DWORD), default_pov_name(povnum), "Left"),
input_item_id(povnum * 4 + ITEM_ID_HAT1LEFT),
dinput_joystick_pov_get_state,
&dinput_joystick_device::pov_get_state,
reinterpret_cast<void *>(uintptr_t(povnum * 4 + POVDIR_LEFT)));
// right
name = dinput_module::device_item_name(this, offsetof(DIJOYSTATE2, rgdwPOV) + povnum * sizeof(DWORD), default_pov_name(povnum).c_str(), "Right");
device()->add_item(
name,
device.add_item(
item_name(offsetof(DIJOYSTATE2, rgdwPOV) + povnum * sizeof(DWORD), default_pov_name(povnum), "Right"),
input_item_id(povnum * 4 + ITEM_ID_HAT1RIGHT),
dinput_joystick_pov_get_state,
&dinput_joystick_device::pov_get_state,
reinterpret_cast<void *>(uintptr_t(povnum * 4 + POVDIR_RIGHT)));
// up
name = dinput_module::device_item_name(this, offsetof(DIJOYSTATE2, rgdwPOV) + povnum * sizeof(DWORD), default_pov_name(povnum).c_str(), "Up");
device()->add_item(
name,
device.add_item(
item_name(offsetof(DIJOYSTATE2, rgdwPOV) + povnum * sizeof(DWORD), default_pov_name(povnum), "Up"),
input_item_id(povnum * 4 + ITEM_ID_HAT1UP),
dinput_joystick_pov_get_state,
&dinput_joystick_device::pov_get_state,
reinterpret_cast<void *>(uintptr_t(povnum * 4 + POVDIR_UP)));
// down
name = dinput_module::device_item_name(this, offsetof(DIJOYSTATE2, rgdwPOV) + povnum * sizeof(DWORD), default_pov_name(povnum).c_str(), "Down");
device()->add_item(
name,
device.add_item(
item_name(offsetof(DIJOYSTATE2, rgdwPOV) + povnum * sizeof(DWORD), default_pov_name(povnum), "Down"),
input_item_id(povnum * 4 + ITEM_ID_HAT1DOWN),
dinput_joystick_pov_get_state,
&dinput_joystick_device::pov_get_state,
reinterpret_cast<void *>(uintptr_t(povnum * 4 + POVDIR_DOWN)));
}
// populate the buttons
for (uint32_t butnum = 0; butnum < dinput.caps.dwButtons; butnum++)
for (uint32_t butnum = 0; butnum < m_caps.dwButtons; butnum++)
{
auto offset = reinterpret_cast<uintptr_t>(&static_cast<DIJOYSTATE2 *>(nullptr)->rgbButtons[butnum]);
std::string name = dinput_module::device_item_name(this, offset, default_button_name(butnum).c_str(), nullptr);
input_item_id itemid;
if (butnum < INPUT_MAX_BUTTONS)
@ -539,7 +522,35 @@ int dinput_joystick_device::configure()
else
itemid = ITEM_ID_OTHER_SWITCH;
device()->add_item(name, itemid, generic_button_get_state<BYTE>, &joystick.state.rgbButtons[butnum]);
device.add_item(
item_name(offset, default_button_name(butnum), nullptr),
itemid,
generic_button_get_state<BYTE>,
&m_joystick.state.rgbButtons[butnum]);
}
}
int32_t dinput_joystick_device::pov_get_state(void *device_internal, void *item_internal)
{
auto *const devinfo = static_cast<dinput_joystick_device *>(device_internal);
int const povnum = uintptr_t(item_internal) / 4;
int const povdir = uintptr_t(item_internal) % 4;
// get the current state
devinfo->module().poll_if_necessary();
DWORD const pov = devinfo->m_joystick.state.rgdwPOV[povnum];
// if invalid, return 0
if ((pov & 0xffff) == 0xffff)
return 0;
// return the current state
switch (povdir)
{
case POVDIR_LEFT: return (pov >= 22500) && (pov <= 31500);
case POVDIR_RIGHT: return (pov >= 4500) && (pov <= 13500);
case POVDIR_UP: return (pov >= 31500) || (pov <= 4500);
case POVDIR_DOWN: return (pov >= 13500) && (pov <= 22500);
}
return 0;
@ -573,25 +584,118 @@ int dinput_api_helper::initialize()
}
HRESULT dinput_api_helper::enum_attached_devices(int devclass, device_enum_interface *enumerate_interface, void *state) const
HRESULT dinput_api_helper::enum_attached_devices(int devclass, device_enum_interface &enumerate_interface) const
{
device_enum_interface::dinput_callback_context ctx;
ctx.self = enumerate_interface;
ctx.state = state;
return m_dinput->EnumDevices(devclass, device_enum_interface::enum_callback, &ctx, DIEDFL_ATTACHEDONLY);
return m_dinput->EnumDevices(devclass, device_enum_interface_callback, &enumerate_interface, DIEDFL_ATTACHEDONLY);
}
#else // defined(OSD_WINDOWS)
std::pair<Microsoft::WRL::ComPtr<IDirectInputDevice8>, LPCDIDATAFORMAT> dinput_api_helper::open_device(
LPCDIDEVICEINSTANCE instance,
LPCDIDATAFORMAT format1,
LPCDIDATAFORMAT format2,
dinput_cooperative_level cooperative_level)
{
HRESULT result;
// attempt to create a device
Microsoft::WRL::ComPtr<IDirectInputDevice8> device;
result = m_dinput->CreateDevice(instance->guidInstance, device.GetAddressOf(), nullptr);
if (result != DI_OK)
{
osd_printf_error("DirectInput: Unable to create device.\n");
return std::make_pair(nullptr, nullptr);
}
// attempt to set the data format
LPCDIDATAFORMAT format = format1;
result = device->SetDataFormat(format);
if ((result != DI_OK) && format2)
{
// use the secondary format if available
osd_printf_verbose("DirectInput: Error setting primary data format, trying secondary format.\n");
format = format2;
result = device->SetDataFormat(format);
}
if (result != DI_OK)
{
osd_printf_error("DirectInput: Unable to set data format.\n");
return std::make_pair(nullptr, nullptr);
}
// default window to the first window in the list
HWND window_handle;
DWORD di_cooperative_level;
#if defined(OSD_WINDOWS)
auto const window = std::static_pointer_cast<win_window_info>(osd_common_t::s_window_list.front());
bool const standalone_window = window && !window->attached_mode();
#elif defined(SDLMAME_WIN32)
auto const window = std::static_pointer_cast<sdl_window_info>(osd_common_t::s_window_list.front());
bool const standalone_window = bool(window);
#endif
if (!standalone_window)
{
// in attached mode we have to ignore the caller and hook up to the desktop window
window_handle = GetDesktopWindow();
di_cooperative_level = DISCL_BACKGROUND | DISCL_NONEXCLUSIVE;
}
else
{
#if defined(OSD_WINDOWS)
window_handle = window->platform_window();
#elif defined(SDLMAME_WIN32)
auto const sdlwindow = window->platform_window();
SDL_SysWMinfo info;
SDL_VERSION(&info.version);
SDL_GetWindowWMInfo(sdlwindow, &info);
window_handle = info.info.win.window;
#endif
switch (cooperative_level)
{
case dinput_cooperative_level::BACKGROUND:
di_cooperative_level = DISCL_BACKGROUND | DISCL_NONEXCLUSIVE;
break;
case dinput_cooperative_level::FOREGROUND:
di_cooperative_level = DISCL_FOREGROUND | DISCL_NONEXCLUSIVE;
break;
default:
throw false;
}
}
// set the cooperative level
result = device->SetCooperativeLevel(window_handle, di_cooperative_level);
if (result != DI_OK)
{
osd_printf_error("DirectInput: Unable to set cooperative level.\n");
return std::make_pair(nullptr, nullptr);
}
// return new device
return std::make_pair(std::move(device), format);
}
} // namespace osd
#else // defined(OSD_WINDOWS) || defined(SDLMAME_WIN32)
#include "input_module.h"
namespace osd {
namespace {
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 // defined(OSD_WINDOWS)
} // anonymous namespace
MODULE_DEFINITION(KEYBOARDINPUT_DINPUT, keyboard_input_dinput)
MODULE_DEFINITION(MOUSEINPUT_DINPUT, mouse_input_dinput)
MODULE_DEFINITION(JOYSTICKINPUT_DINPUT, joystick_input_dinput)
} // namespace osd
#endif // defined(OSD_WINDOWS) || defined(SDLMAME_WIN32)
MODULE_DEFINITION(KEYBOARDINPUT_DINPUT, osd::keyboard_input_dinput)
MODULE_DEFINITION(MOUSEINPUT_DINPUT, osd::mouse_input_dinput)
MODULE_DEFINITION(JOYSTICKINPUT_DINPUT, osd::joystick_input_dinput)

View File

@ -10,7 +10,7 @@
#pragma once
#include "input_windows.h"
#include "input_wincommon.h"
#include "modules/lib/osdlib.h"
#include "modules/lib/osdobj_common.h"
@ -19,11 +19,19 @@
#include "strconv.h"
#include <memory>
#include <mutex>
#include <string>
#include <string_view>
#include <utility>
#include <dinput.h>
#include <windows.h>
#include <wrl/client.h>
namespace osd {
//============================================================
// dinput_device - base directinput device
//============================================================
@ -31,28 +39,11 @@
class device_enum_interface
{
public:
struct dinput_callback_context
{
device_enum_interface * self;
void * state;
};
virtual ~device_enum_interface() = default;
virtual ~device_enum_interface()
{
}
static BOOL CALLBACK enum_callback(LPCDIDEVICEINSTANCE instance, LPVOID ref)
{
auto context = static_cast<dinput_callback_context*>(ref);
return context->self->device_enum_callback(instance, context->state);
}
virtual BOOL device_enum_callback(LPCDIDEVICEINSTANCE instance, LPVOID ref) = 0;
virtual BOOL device_enum_callback(LPCDIDEVICEINSTANCE instance) = 0;
};
// Typedef for dynamically loaded function
typedef HRESULT (WINAPI *dinput_create_fn)(HINSTANCE, DWORD, LPDIRECTINPUT8 *, LPUNKNOWN);
enum class dinput_cooperative_level
{
FOREGROUND,
@ -61,101 +52,70 @@ enum class dinput_cooperative_level
class dinput_api_helper
{
private:
Microsoft::WRL::ComPtr<IDirectInput8> m_dinput;
osd::dynamic_module::ptr m_dinput_dll;
public:
dinput_api_helper();
virtual ~dinput_api_helper();
~dinput_api_helper();
int initialize();
template <class TDevice>
TDevice *create_device(
running_machine &machine,
template <typename TDevice, typename TCallback>
std::unique_ptr<TDevice> create_device(
input_module_base &module,
LPCDIDEVICEINSTANCE instance,
LPCDIDATAFORMAT format1,
LPCDIDATAFORMAT format2,
dinput_cooperative_level cooperative_level)
dinput_cooperative_level cooperative_level,
TCallback &&callback)
{
HRESULT result;
std::shared_ptr<win_window_info> window;
HWND hwnd;
auto [device, format] = open_device(instance, format1, format2, cooperative_level);
if (!device)
return nullptr;
// convert instance name to utf8
std::string utf8_instance_name = osd::text::from_tstring(instance->tszInstanceName);
// get the capabilities
DIDEVCAPS caps;
caps.dwSize = sizeof(caps);
HRESULT const result = device->GetCapabilities(&caps);
if (result != DI_OK)
return nullptr;
if (!callback(device, format))
return nullptr;
// convert instance name to UTF-8
std::string utf8_instance_name = text::from_tstring(instance->tszInstanceName);
// set device id to name + product unique identifier + instance unique identifier
std::string utf8_instance_id = utf8_instance_name + " product_" + guid_to_string(instance->guidProduct) + " instance_" + guid_to_string(instance->guidInstance);
// allocate memory for the device object
TDevice &devinfo = module.devicelist().create_device<TDevice>(machine, std::move(utf8_instance_name), std::move(utf8_instance_id), module);
// attempt to create a device
result = m_dinput->CreateDevice(instance->guidInstance, devinfo.dinput.device.GetAddressOf(), nullptr);
if (result != DI_OK)
goto error;
// get the caps
devinfo.dinput.caps.dwSize = sizeof(devinfo.dinput.caps);
result = devinfo.dinput.device->GetCapabilities(&devinfo.dinput.caps);
if (result != DI_OK)
goto error;
// attempt to set the data format
devinfo.dinput.format = format1;
result = devinfo.dinput.device->SetDataFormat(devinfo.dinput.format);
if (result != DI_OK)
{
// use the secondary format if available
if (format2)
{
devinfo.dinput.format = format2;
result = devinfo.dinput.device->SetDataFormat(devinfo.dinput.format);
}
if (result != DI_OK)
goto error;
}
// default window to the first window in the list
window = std::static_pointer_cast<win_window_info>(osd_common_t::s_window_list.front());
DWORD di_cooperative_level;
if (window->attached_mode())
{
// in attached mode we have to ignore the caller and hook up to the desktop window
hwnd = GetDesktopWindow();
di_cooperative_level = DISCL_BACKGROUND | DISCL_NONEXCLUSIVE;
}
else
{
hwnd = window->platform_window();
switch (cooperative_level)
{
case dinput_cooperative_level::BACKGROUND:
di_cooperative_level = DISCL_BACKGROUND | DISCL_NONEXCLUSIVE;
break;
case dinput_cooperative_level::FOREGROUND:
di_cooperative_level = DISCL_FOREGROUND | DISCL_NONEXCLUSIVE;
break;
default:
throw false;
}
}
// set the cooperative level
result = devinfo.dinput.device->SetCooperativeLevel(hwnd, di_cooperative_level);
if (result != DI_OK)
goto error;
return &devinfo;
error:
module.devicelist().free_device(devinfo);
return nullptr;
return std::make_unique<TDevice>(
std::move(utf8_instance_name),
std::move(utf8_instance_id),
module,
std::move(device),
caps,
format);
}
HRESULT enum_attached_devices(int devclass, device_enum_interface *enumerate_interface, void *state) const;
HRESULT enum_attached_devices(int devclass, device_enum_interface &enumerate_interface) const;
template <typename T>
static HRESULT set_dword_property(
T &&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 device->SetProperty(property_guid, &dipdw.diph);
}
static std::string guid_to_string(const GUID& guid)
{
@ -172,70 +132,111 @@ public:
return guid_string;
}
private:
std::pair<Microsoft::WRL::ComPtr<IDirectInputDevice8>, LPCDIDATAFORMAT> open_device(
LPCDIDEVICEINSTANCE instance,
LPCDIDATAFORMAT format1,
LPCDIDATAFORMAT format2,
dinput_cooperative_level cooperative_level);
Microsoft::WRL::ComPtr<IDirectInput8> m_dinput;
dynamic_module::ptr m_dinput_dll;
};
class dinput_device : public device_info
{
public:
// DirectInput-specific information about a device
struct dinput_api_state
{
Microsoft::WRL::ComPtr<IDirectInputDevice8> device;
DIDEVCAPS caps;
LPCDIDATAFORMAT format;
};
dinput_api_state dinput;
dinput_device(running_machine &machine, std::string &&name, std::string &&id, input_device_class deviceclass, input_module &module);
virtual ~dinput_device();
protected:
dinput_device(
std::string &&name,
std::string &&id,
input_module &module,
Microsoft::WRL::ComPtr<IDirectInputDevice8> &&device,
DIDEVCAPS const &caps,
LPCDIDATAFORMAT format);
HRESULT poll_dinput(LPVOID pState) const;
std::string item_name(int offset, std::string_view defstr, char const *suffix) const;
// DirectInput-specific information about a device
Microsoft::WRL::ComPtr<IDirectInputDevice8> const m_device;
DIDEVCAPS m_caps;
LPCDIDATAFORMAT const m_format;
};
class dinput_keyboard_device : public dinput_device
{
private:
std::mutex m_device_lock;
public:
keyboard_state keyboard;
dinput_keyboard_device(
std::string &&name,
std::string &&id,
input_module &module,
Microsoft::WRL::ComPtr<IDirectInputDevice8> &&device,
DIDEVCAPS const &caps,
LPCDIDATAFORMAT format);
dinput_keyboard_device(running_machine &machine, std::string &&name, std::string &&id, input_module &module);
virtual void poll() override;
virtual void reset() override;
virtual void configure(input_device &device) override;
void poll() override;
void reset() override;
private:
std::mutex m_device_lock;
keyboard_state m_keyboard;
};
class dinput_mouse_device : public dinput_device
{
public:
mouse_state mouse;
dinput_mouse_device(
std::string &&name,
std::string &&id,
input_module &module,
Microsoft::WRL::ComPtr<IDirectInputDevice8> &&device,
DIDEVCAPS const &caps,
LPCDIDATAFORMAT format);
public:
dinput_mouse_device(running_machine &machine, std::string &&name, std::string &&id, input_module &module);
void poll() override;
void reset() override;
virtual void configure(input_device &device) override;
private:
mouse_state m_mouse;
};
// 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;
public:
dinput_joystick_device(running_machine &machine, std::string &&name, std::string &&id, input_module &module);
dinput_joystick_device(
std::string &&name,
std::string &&id,
input_module &module,
Microsoft::WRL::ComPtr<IDirectInputDevice8> &&device,
DIDEVCAPS const &caps,
LPCDIDATAFORMAT format);
void reset() override;
void poll() override;
int configure();
void configure(input_device &device) override;
private:
// state information for a joystick; DirectInput state must be first element
struct dinput_joystick_state
{
DIJOYSTATE state;
LONG rangemin[8];
LONG rangemax[8];
};
static int32_t pov_get_state(void *device_internal, void *item_internal);
dinput_joystick_state m_joystick;
};
} // namespace osd
#endif // MAME_OSD_INPUT_INPUT_DINPUT_H

View File

@ -37,7 +37,7 @@ void mac_osd_interface::customize_input_type_list(std::vector<input_type_entry>
{
}
void mac_osd_interface::poll_inputs(running_machine &machine)
void mac_osd_interface::poll_inputs()
{
MacPollInputs();
}

View File

@ -15,20 +15,13 @@
#include "modules/osdmodule.h"
class input_module : public osd_module
class input_module
{
public:
input_module(const char *type, const char *name)
: osd_module(type, name)
{
}
virtual ~input_module() { }
virtual ~input_module() = default;
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 poll_if_necessary() = 0;
};
//============================================================

View File

@ -7,56 +7,58 @@
//============================================================
#include "input_module.h"
#include "modules/osdmodule.h"
class keyboard_input_none : public input_module
namespace osd {
namespace {
class keyboard_input_none : public osd_module, 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 { }
keyboard_input_none() : osd_module(OSD_KEYBOARDINPUT_PROVIDER, "none") { }
int init(osd_interface &osd, const osd_options &options) override { return 0; }
void input_init(running_machine &machine) override { }
void pause() override { }
void resume() override { }
void poll_if_necessary() override { }
};
MODULE_DEFINITION(KEYBOARD_NONE, keyboard_input_none)
class mouse_input_none : public input_module
class mouse_input_none : public osd_module, public input_module
{
public:
mouse_input_none() : input_module(OSD_MOUSEINPUT_PROVIDER, "none") { }
int init(const osd_options &options) override { return 0; }
mouse_input_none() : osd_module(OSD_MOUSEINPUT_PROVIDER, "none") { }
int init(osd_interface &osd, 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 { }
void poll_if_necessary() override { }
};
MODULE_DEFINITION(MOUSE_NONE, mouse_input_none)
class lightgun_input_none : public input_module
class lightgun_input_none : public osd_module, public input_module
{
public:
lightgun_input_none() : input_module(OSD_LIGHTGUNINPUT_PROVIDER, "none") { }
int init(const osd_options &options) override { return 0; }
lightgun_input_none() : osd_module(OSD_LIGHTGUNINPUT_PROVIDER, "none") { }
int init(osd_interface &osd, 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 { }
void poll_if_necessary() override { }
};
MODULE_DEFINITION(LIGHTGUN_NONE, lightgun_input_none)
class joystick_input_none : public input_module
class joystick_input_none : public osd_module, public input_module
{
public:
joystick_input_none() : input_module(OSD_JOYSTICKINPUT_PROVIDER, "none") { }
int init(const osd_options &options) override { return 0; }
joystick_input_none() : osd_module(OSD_JOYSTICKINPUT_PROVIDER, "none") { }
int init(osd_interface &osd, 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 { }
void poll_if_necessary() override { }
};
MODULE_DEFINITION(JOYSTICK_NONE, joystick_input_none)
} // anonymous namesapce
} // namespace osd
MODULE_DEFINITION(KEYBOARD_NONE, osd::keyboard_input_none)
MODULE_DEFINITION(MOUSE_NONE, osd::mouse_input_none)
MODULE_DEFINITION(LIGHTGUN_NONE, osd::lightgun_input_none)
MODULE_DEFINITION(JOYSTICK_NONE, osd::joystick_input_none)

View File

@ -10,18 +10,21 @@
#if defined(OSD_WINDOWS)
// MAME headers
#include "emu.h"
#include "input_windows.h"
#include "input_wincommon.h"
#include "winmain.h"
#include "window.h"
#include "modules/lib/osdlib.h"
#include "strconv.h"
// MAME headers
#include "emu.h"
#include <algorithm>
#include <cassert>
#include <functional>
#include <mutex>
#include <new>
@ -31,6 +34,8 @@
#include <tchar.h>
namespace osd {
namespace {
class safe_regkey
@ -222,6 +227,7 @@ std::wstring improve_name_from_usb_path(const std::wstring &regpath)
return trim_prefix(regstring);
}
//============================================================
// rawinput_device_improve_name
//============================================================
@ -262,19 +268,36 @@ std::wstring rawinput_device_improve_name(const std::wstring &name)
class rawinput_device : public event_based_device<RAWINPUT>
{
private:
HANDLE m_handle = nullptr;
public:
rawinput_device(running_machine &machine, std::string &&name, std::string &&id, input_device_class deviceclass, input_module &module) :
event_based_device(machine, std::move(name), std::move(id), deviceclass, module)
rawinput_device(std::string &&name, std::string &&id, input_module &module, HANDLE handle) :
event_based_device(std::move(name), std::move(id), module),
m_handle(handle)
{
}
HANDLE device_handle() const { return m_handle; }
void set_handle(HANDLE handle) { m_handle = handle; }
bool reconnect_candidate(std::string_view i) const { return !m_handle && (id() == i); }
void detach_device()
{
assert(m_handle);
m_handle = nullptr;
osd_printf_verbose("RawInput: %s [ID %s] disconnected\n", name(), id());
}
void attach_device(HANDLE handle)
{
assert(!m_handle);
m_handle = handle;
osd_printf_verbose("RawInput: %s [ID %s] reconnected\n", name(), id());
}
private:
HANDLE m_handle;
};
//============================================================
// rawinput_keyboard_device
//============================================================
@ -282,20 +305,18 @@ public:
class rawinput_keyboard_device : public rawinput_device
{
public:
keyboard_state keyboard;
rawinput_keyboard_device(running_machine &machine, std::string &&name, std::string &&id, input_module &module) :
rawinput_device(machine, std::move(name), std::move(id), DEVICE_CLASS_KEYBOARD, module),
keyboard({ { 0 } })
rawinput_keyboard_device(std::string &&name, std::string &&id, input_module &module, HANDLE handle) :
rawinput_device(std::move(name), std::move(id), module, handle),
m_keyboard({ { 0 } })
{
}
void reset() override
virtual void reset() override
{
memset(&keyboard, 0, sizeof(keyboard));
memset(&m_keyboard, 0, sizeof(m_keyboard));
}
void process_event(RAWINPUT &rawinput) override
virtual void process_event(RAWINPUT const &rawinput) override
{
// determine the full DIK-compatible scancode
uint8_t scancode = (rawinput.data.keyboard.MakeCode & 0x7f) | ((rawinput.data.keyboard.Flags & RI_KEY_E0) ? 0x80 : 0x00);
@ -305,149 +326,231 @@ public:
return;
// set or clear the key
keyboard.state[scancode] = (rawinput.data.keyboard.Flags & RI_KEY_BREAK) ? 0x00 : 0x80;
m_keyboard.state[scancode] = (rawinput.data.keyboard.Flags & RI_KEY_BREAK) ? 0x00 : 0x80;
}
virtual void configure(input_device &device) override
{
keyboard_trans_table const &table = keyboard_trans_table::instance();
for (int keynum = 0; keynum < MAX_KEYS; keynum++)
{
input_item_id itemid = table.map_di_scancode_to_itemid(keynum);
WCHAR keyname[100];
// generate the name
if (GetKeyNameTextW(((keynum & 0x7f) << 16) | ((keynum & 0x80) << 17), keyname, std::size(keyname)) == 0)
_snwprintf(keyname, std::size(keyname), L"Scan%03d", keynum);
std::string name = text::from_wstring(keyname);
// add the item to the device
device.add_item(
name,
itemid,
generic_button_get_state<std::uint8_t>,
&m_keyboard.state[keynum]);
}
}
private:
keyboard_state m_keyboard;
};
//============================================================
// rawinput_mouse_device
//============================================================
class rawinput_mouse_device : public rawinput_device
{
private:
std::mutex m_device_lock;
public:
mouse_state mouse;
rawinput_mouse_device(running_machine &machine, std::string &&name, std::string &&id, input_module &module) :
rawinput_device(machine, std::move(name), std::move(id), DEVICE_CLASS_MOUSE, module),
mouse({0})
rawinput_mouse_device(std::string &&name, std::string &&id, input_module &module, HANDLE handle) :
rawinput_device(std::move(name), std::move(id), module, handle),
m_mouse({0})
{
}
void poll() override
virtual void poll() override
{
mouse.lX = 0;
mouse.lY = 0;
mouse.lZ = 0;
m_mouse.lX = 0;
m_mouse.lY = 0;
m_mouse.lZ = 0;
rawinput_device::poll();
}
void reset() override
virtual void reset() override
{
memset(&mouse, 0, sizeof(mouse));
memset(&m_mouse, 0, sizeof(m_mouse));
}
void process_event(RAWINPUT &rawinput) override
virtual void configure(input_device &device) override
{
// populate the axes
for (int axisnum = 0; axisnum < 3; axisnum++)
{
device.add_item(
default_axis_name[axisnum],
input_item_id(ITEM_ID_XAXIS + axisnum),
generic_axis_get_state<LONG>,
&m_mouse.lX + axisnum);
}
// populate the buttons
for (int butnum = 0; butnum < 5; butnum++)
{
device.add_item(
default_button_name(butnum),
input_item_id(ITEM_ID_BUTTON1 + butnum),
generic_button_get_state<BYTE>,
&m_mouse.rgbButtons[butnum]);
}
}
virtual void process_event(RAWINPUT const &rawinput) override
{
// If this data was intended for a rawinput mouse
if (rawinput.data.mouse.usFlags == MOUSE_MOVE_RELATIVE)
{
mouse.lX += rawinput.data.mouse.lLastX * osd::INPUT_RELATIVE_PER_PIXEL;
mouse.lY += rawinput.data.mouse.lLastY * osd::INPUT_RELATIVE_PER_PIXEL;
m_mouse.lX += rawinput.data.mouse.lLastX * INPUT_RELATIVE_PER_PIXEL;
m_mouse.lY += rawinput.data.mouse.lLastY * INPUT_RELATIVE_PER_PIXEL;
// update zaxis
if (rawinput.data.mouse.usButtonFlags & RI_MOUSE_WHEEL)
mouse.lZ += static_cast<int16_t>(rawinput.data.mouse.usButtonData) * osd::INPUT_RELATIVE_PER_PIXEL;
m_mouse.lZ += int16_t(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;
if (rawinput.data.mouse.usButtonFlags & RI_MOUSE_BUTTON_1_DOWN) m_mouse.rgbButtons[0] = 0x80;
if (rawinput.data.mouse.usButtonFlags & RI_MOUSE_BUTTON_1_UP) m_mouse.rgbButtons[0] = 0x00;
if (rawinput.data.mouse.usButtonFlags & RI_MOUSE_BUTTON_2_DOWN) m_mouse.rgbButtons[1] = 0x80;
if (rawinput.data.mouse.usButtonFlags & RI_MOUSE_BUTTON_2_UP) m_mouse.rgbButtons[1] = 0x00;
if (rawinput.data.mouse.usButtonFlags & RI_MOUSE_BUTTON_3_DOWN) m_mouse.rgbButtons[2] = 0x80;
if (rawinput.data.mouse.usButtonFlags & RI_MOUSE_BUTTON_3_UP) m_mouse.rgbButtons[2] = 0x00;
if (rawinput.data.mouse.usButtonFlags & RI_MOUSE_BUTTON_4_DOWN) m_mouse.rgbButtons[3] = 0x80;
if (rawinput.data.mouse.usButtonFlags & RI_MOUSE_BUTTON_4_UP) m_mouse.rgbButtons[3] = 0x00;
if (rawinput.data.mouse.usButtonFlags & RI_MOUSE_BUTTON_5_DOWN) m_mouse.rgbButtons[4] = 0x80;
if (rawinput.data.mouse.usButtonFlags & RI_MOUSE_BUTTON_5_UP) m_mouse.rgbButtons[4] = 0x00;
}
}
private:
mouse_state m_mouse;
};
//============================================================
// rawinput_lightgun_device
//============================================================
class rawinput_lightgun_device : public rawinput_device
{
private:
std::mutex m_device_lock;
public:
mouse_state lightgun;
rawinput_lightgun_device(running_machine &machine, std::string &&name, std::string &&id, input_module &module) :
rawinput_device(machine, std::move(name), std::move(id), DEVICE_CLASS_LIGHTGUN, module),
lightgun({0})
rawinput_lightgun_device(std::string &&name, std::string &&id, input_module &module, HANDLE handle) :
rawinput_device(std::move(name), std::move(id), module, handle),
m_lightgun({0})
{
}
void poll() override
virtual void poll() override
{
lightgun.lZ = 0;
m_lightgun.lZ = 0;
rawinput_device::poll();
}
void reset() override
virtual void reset() override
{
memset(&lightgun, 0, sizeof(lightgun));
memset(&m_lightgun, 0, sizeof(m_lightgun));
}
void process_event(RAWINPUT &rawinput) override
virtual void configure(input_device &device) override
{
// populate the axes
for (int axisnum = 0; axisnum < 2; axisnum++)
{
device.add_item(
default_axis_name[axisnum],
input_item_id(ITEM_ID_XAXIS + axisnum),
generic_axis_get_state<LONG>,
&m_lightgun.lX + axisnum);
}
// scroll wheel is always relative if present
device.add_item(
default_axis_name[2],
ITEM_ID_ADD_RELATIVE1,
generic_axis_get_state<LONG>,
&m_lightgun.lZ);
// populate the buttons
for (int butnum = 0; butnum < 5; butnum++)
{
device.add_item(
default_button_name(butnum),
input_item_id(ITEM_ID_BUTTON1 + butnum),
generic_button_get_state<BYTE>,
&m_lightgun.rgbButtons[butnum]);
}
}
virtual void process_event(RAWINPUT const &rawinput) override
{
// If this data was intended for a rawinput lightgun
if (rawinput.data.mouse.usFlags & MOUSE_MOVE_ABSOLUTE)
{
// update the X/Y positions
lightgun.lX = normalize_absolute_axis(rawinput.data.mouse.lLastX, 0, osd::INPUT_ABSOLUTE_MAX);
lightgun.lY = normalize_absolute_axis(rawinput.data.mouse.lLastY, 0, osd::INPUT_ABSOLUTE_MAX);
m_lightgun.lX = normalize_absolute_axis(rawinput.data.mouse.lLastX, 0, INPUT_ABSOLUTE_MAX);
m_lightgun.lY = normalize_absolute_axis(rawinput.data.mouse.lLastY, 0, INPUT_ABSOLUTE_MAX);
// update zaxis
if (rawinput.data.mouse.usButtonFlags & RI_MOUSE_WHEEL)
lightgun.lZ += static_cast<int16_t>(rawinput.data.mouse.usButtonData) * osd::INPUT_RELATIVE_PER_PIXEL;
m_lightgun.lZ += int16_t(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) lightgun.rgbButtons[0] = 0x80;
if (rawinput.data.mouse.usButtonFlags & RI_MOUSE_BUTTON_1_UP) lightgun.rgbButtons[0] = 0x00;
if (rawinput.data.mouse.usButtonFlags & RI_MOUSE_BUTTON_2_DOWN) lightgun.rgbButtons[1] = 0x80;
if (rawinput.data.mouse.usButtonFlags & RI_MOUSE_BUTTON_2_UP) lightgun.rgbButtons[1] = 0x00;
if (rawinput.data.mouse.usButtonFlags & RI_MOUSE_BUTTON_3_DOWN) lightgun.rgbButtons[2] = 0x80;
if (rawinput.data.mouse.usButtonFlags & RI_MOUSE_BUTTON_3_UP) lightgun.rgbButtons[2] = 0x00;
if (rawinput.data.mouse.usButtonFlags & RI_MOUSE_BUTTON_4_DOWN) lightgun.rgbButtons[3] = 0x80;
if (rawinput.data.mouse.usButtonFlags & RI_MOUSE_BUTTON_4_UP) lightgun.rgbButtons[3] = 0x00;
if (rawinput.data.mouse.usButtonFlags & RI_MOUSE_BUTTON_5_DOWN) lightgun.rgbButtons[4] = 0x80;
if (rawinput.data.mouse.usButtonFlags & RI_MOUSE_BUTTON_5_UP) lightgun.rgbButtons[4] = 0x00;
if (rawinput.data.mouse.usButtonFlags & RI_MOUSE_BUTTON_1_DOWN) m_lightgun.rgbButtons[0] = 0x80;
if (rawinput.data.mouse.usButtonFlags & RI_MOUSE_BUTTON_1_UP) m_lightgun.rgbButtons[0] = 0x00;
if (rawinput.data.mouse.usButtonFlags & RI_MOUSE_BUTTON_2_DOWN) m_lightgun.rgbButtons[1] = 0x80;
if (rawinput.data.mouse.usButtonFlags & RI_MOUSE_BUTTON_2_UP) m_lightgun.rgbButtons[1] = 0x00;
if (rawinput.data.mouse.usButtonFlags & RI_MOUSE_BUTTON_3_DOWN) m_lightgun.rgbButtons[2] = 0x80;
if (rawinput.data.mouse.usButtonFlags & RI_MOUSE_BUTTON_3_UP) m_lightgun.rgbButtons[2] = 0x00;
if (rawinput.data.mouse.usButtonFlags & RI_MOUSE_BUTTON_4_DOWN) m_lightgun.rgbButtons[3] = 0x80;
if (rawinput.data.mouse.usButtonFlags & RI_MOUSE_BUTTON_4_UP) m_lightgun.rgbButtons[3] = 0x00;
if (rawinput.data.mouse.usButtonFlags & RI_MOUSE_BUTTON_5_DOWN) m_lightgun.rgbButtons[4] = 0x80;
if (rawinput.data.mouse.usButtonFlags & RI_MOUSE_BUTTON_5_UP) m_lightgun.rgbButtons[4] = 0x00;
}
}
private:
mouse_state m_lightgun;
};
//============================================================
// rawinput_module - base class for rawinput modules
//============================================================
class rawinput_module : public wininput_module
class rawinput_module : public wininput_module<rawinput_device>
{
private:
std::mutex m_module_lock;
public:
rawinput_module(const char *type, const char *name) : wininput_module(type, name)
rawinput_module(const char *type, const char *name) : wininput_module<rawinput_device>(type, name)
{
}
bool probe() override
virtual bool probe() override
{
return true;
}
void input_init(running_machine &machine) override
virtual void input_init(running_machine &machine) override
{
wininput_module<rawinput_device>::input_init(machine);
// get initial number of devices
UINT device_count = 0;
if (GetRawInputDeviceList(nullptr, &device_count, sizeof(RAWINPUTDEVICELIST)) != 0)
@ -479,11 +582,7 @@ public:
// iterate backwards through devices; new devices are added at the head
for (int devnum = retrieved - 1; devnum >= 0; devnum--)
add_rawinput_device(machine, rawinput_devices[devnum]);
// don't enable background input when debugging
if (!machine.options().debug())
m_global_inputs_enabled = options()->background_input();
add_rawinput_device(rawinput_devices[devnum]);
// If we added no devices, no need to register for notifications
if (devicelist().empty())
@ -494,7 +593,7 @@ public:
registration.usUsagePage = usagepage();
registration.usUsage = usage();
registration.dwFlags = RIDEV_DEVNOTIFY;
if (m_global_inputs_enabled)
if (background_input())
registration.dwFlags |= RIDEV_INPUTSINK;
registration.hwndTarget = std::static_pointer_cast<win_window_info>(osd_common_t::s_window_list.front())->platform_window();
@ -503,17 +602,12 @@ public:
}
protected:
virtual void add_rawinput_device(running_machine &machine, RAWINPUTDEVICELIST const &device) = 0;
virtual void add_rawinput_device(RAWINPUTDEVICELIST const &device) = 0;
virtual USHORT usagepage() = 0;
virtual USHORT usage() = 0;
int init_internal() override
{
return 0;
}
template<class TDevice>
TDevice *create_rawinput_device(running_machine &machine, RAWINPUTDEVICELIST const &rawinputdevice)
TDevice *create_rawinput_device(input_device_class deviceclass, RAWINPUTDEVICELIST const &rawinputdevice)
{
// determine the length of the device name, allocate it, and fetch it if not nameless
UINT name_length = 0;
@ -528,34 +622,30 @@ protected:
if (wcsstr(tname.get(), L"Root#RDP_") != nullptr)
return nullptr;
// improve the name and then allocate a device
std::string utf8_name = osd::text::from_wstring(rawinput_device_improve_name(tname.get()));
// improve the name
std::string utf8_name = text::from_wstring(rawinput_device_improve_name(tname.get()));
// set device ID to raw input name
std::string utf8_id = osd::text::from_wstring(tname.get());
std::string utf8_id = text::from_wstring(tname.get());
tname.reset();
TDevice &devinfo = devicelist().create_device<TDevice>(machine, std::move(utf8_name), std::move(utf8_id), *this);
// Add the handle
devinfo.set_handle(rawinputdevice.hDevice);
return &devinfo;
// allocate a device
return &create_device<TDevice>(
deviceclass,
std::move(utf8_name),
std::move(utf8_id),
rawinputdevice.hDevice);
}
bool handle_input_event(input_event eventid, void *eventdata) override
virtual bool handle_input_event(input_event eventid, void *eventdata) override
{
switch (eventid)
{
// handle raw input data
case INPUT_EVENT_RAWINPUT:
{
// ignore if not enabled
if (!input_enabled())
return false;
HRAWINPUT rawinputdevice = *static_cast<HRAWINPUT *>(eventdata);
HRAWINPUT const rawinputdevice = *static_cast<HRAWINPUT *>(eventdata);
BYTE small_buffer[4096];
std::unique_ptr<BYTE []> larger_buffer;
@ -595,13 +685,12 @@ protected:
devicelist().end(),
[input] (auto const &device)
{
auto devinfo = dynamic_cast<rawinput_device *>(device.get());
return devinfo && (input->header.hDevice == devinfo->device_handle());
return input->header.hDevice == device->device_handle();
});
if (devicelist().end() == target_device)
return false;
static_cast<rawinput_device *>(target_device->get())->queue_events(input, 1);
(*target_device)->queue_events(input, 1);
return true;
}
}
@ -609,7 +698,7 @@ protected:
case INPUT_EVENT_ARRIVAL:
{
HRAWINPUT rawinputdevice = *static_cast<HRAWINPUT *>(eventdata);
HRAWINPUT const rawinputdevice = *static_cast<HRAWINPUT *>(eventdata);
// determine the length of the device name, allocate it, and fetch it if not nameless
UINT name_length = 0;
@ -619,7 +708,7 @@ protected:
std::unique_ptr<WCHAR []> tname = std::make_unique<WCHAR []>(name_length + 1);
if (name_length > 1 && GetRawInputDeviceInfoW(rawinputdevice, RIDI_DEVICENAME, tname.get(), &name_length) == UINT(-1))
return false;
std::string utf8_id = osd::text::from_wstring(tname.get());
std::string utf8_id = text::from_wstring(tname.get());
tname.reset();
std::lock_guard<std::mutex> scope_lock(m_module_lock);
@ -630,20 +719,19 @@ protected:
devicelist().end(),
[&utf8_id] (auto const &device)
{
auto devinfo = dynamic_cast<rawinput_device *>(device.get());
return devinfo && !devinfo->device_handle() && (devinfo->id() == utf8_id);
return device->reconnect_candidate(utf8_id);
});
if (devicelist().end() == target_device)
return false;
static_cast<rawinput_device *>(target_device->get())->set_handle(rawinputdevice);
(*target_device)->attach_device(rawinputdevice);
return true;
}
break;
case INPUT_EVENT_REMOVAL:
{
HRAWINPUT rawinputdevice = *static_cast<HRAWINPUT *>(eventdata);
HRAWINPUT const rawinputdevice = *static_cast<HRAWINPUT *>(eventdata);
std::lock_guard<std::mutex> scope_lock(m_module_lock);
@ -653,15 +741,14 @@ protected:
devicelist().end(),
[rawinputdevice] (auto const &device)
{
auto devinfo = dynamic_cast<rawinput_device *>(device.get());
return devinfo && (rawinputdevice == devinfo->device_handle());
return rawinputdevice == device->device_handle();
});
if (devicelist().end() == target_device)
return false;
(*target_device)->reset();
static_cast<rawinput_device *>(target_device->get())->set_handle(nullptr);
(*target_device)->detach_device();
return true;
}
break;
@ -675,6 +762,7 @@ protected:
}
};
//============================================================
// keyboard_input_rawinput - rawinput keyboard module
//============================================================
@ -682,45 +770,26 @@ protected:
class keyboard_input_rawinput : public rawinput_module
{
public:
keyboard_input_rawinput()
: rawinput_module(OSD_KEYBOARDINPUT_PROVIDER, "rawinput")
keyboard_input_rawinput() : rawinput_module(OSD_KEYBOARDINPUT_PROVIDER, "rawinput")
{
}
protected:
USHORT usagepage() override { return 1; }
USHORT usage() override { return 6; }
virtual USHORT usagepage() override { return 1; }
virtual USHORT usage() override { return 6; }
void add_rawinput_device(running_machine &machine, RAWINPUTDEVICELIST const &device) override
virtual void add_rawinput_device(RAWINPUTDEVICELIST const &device) override
{
// make sure this is a keyboard
if (device.dwType != RIM_TYPEKEYBOARD)
return;
// allocate and link in a new device
auto *devinfo = create_rawinput_device<rawinput_keyboard_device>(machine, device);
if (devinfo == nullptr)
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);
WCHAR keyname[100];
// generate the name
if (GetKeyNameTextW(((keynum & 0x7f) << 16) | ((keynum & 0x80) << 17), keyname, std::size(keyname)) == 0)
_snwprintf(keyname, std::size(keyname), L"Scan%03d", keynum);
std::string name = osd::text::from_wstring(keyname);
// add the item to the device
devinfo->device()->add_item(name, itemid, generic_button_get_state<std::uint8_t>, &devinfo->keyboard.state[keynum]);
}
create_rawinput_device<rawinput_keyboard_device>(DEVICE_CLASS_KEYBOARD, device);
}
};
//============================================================
// mouse_input_rawinput - rawinput mouse module
//============================================================
@ -728,48 +797,26 @@ protected:
class mouse_input_rawinput : public rawinput_module
{
public:
mouse_input_rawinput()
: rawinput_module(OSD_MOUSEINPUT_PROVIDER, "rawinput")
mouse_input_rawinput() : rawinput_module(OSD_MOUSEINPUT_PROVIDER, "rawinput")
{
}
protected:
USHORT usagepage() override { return 1; }
USHORT usage() override { return 2; }
virtual USHORT usagepage() override { return 1; }
virtual USHORT usage() override { return 2; }
void add_rawinput_device(running_machine &machine, RAWINPUTDEVICELIST const &device) override
virtual void add_rawinput_device(RAWINPUTDEVICELIST const &device) override
{
// make sure this is a mouse
if (device.dwType != RIM_TYPEMOUSE)
return;
// allocate and link in a new device
auto *devinfo = create_rawinput_device<rawinput_mouse_device>(machine, device);
if (devinfo == nullptr)
return;
// populate the axes
for (int axisnum = 0; axisnum < 3; axisnum++)
{
devinfo->device()->add_item(
default_axis_name[axisnum],
static_cast<input_item_id>(ITEM_ID_XAXIS + axisnum),
generic_axis_get_state<LONG>,
&devinfo->mouse.lX + axisnum);
}
// populate the buttons
for (int butnum = 0; butnum < 5; butnum++)
{
devinfo->device()->add_item(
default_button_name(butnum),
static_cast<input_item_id>(ITEM_ID_BUTTON1 + butnum),
generic_button_get_state<BYTE>,
&devinfo->mouse.rgbButtons[butnum]);
}
create_rawinput_device<rawinput_mouse_device>(DEVICE_CLASS_MOUSE, device);
}
};
//============================================================
// lightgun_input_rawinput - rawinput lightgun module
//============================================================
@ -777,61 +824,47 @@ protected:
class lightgun_input_rawinput : public rawinput_module
{
public:
lightgun_input_rawinput()
: rawinput_module(OSD_LIGHTGUNINPUT_PROVIDER, "rawinput")
lightgun_input_rawinput() : rawinput_module(OSD_LIGHTGUNINPUT_PROVIDER, "rawinput")
{
}
protected:
USHORT usagepage() override { return 1; }
USHORT usage() override { return 2; }
virtual USHORT usagepage() override { return 1; }
virtual USHORT usage() override { return 2; }
void add_rawinput_device(running_machine &machine, RAWINPUTDEVICELIST const &device) override
virtual void add_rawinput_device(RAWINPUTDEVICELIST const &device) override
{
// make sure this is a mouse
if (device.dwType != RIM_TYPEMOUSE)
return;
// allocate and link in a new device
auto *devinfo = create_rawinput_device<rawinput_lightgun_device>(machine, device);
if (devinfo == nullptr)
return;
// populate the axes
for (int axisnum = 0; axisnum < 3; axisnum++)
{
devinfo->device()->add_item(
default_axis_name[axisnum],
static_cast<input_item_id>(ITEM_ID_XAXIS + axisnum),
generic_axis_get_state<LONG>,
&devinfo->lightgun.lX + axisnum);
}
// populate the buttons
for (int butnum = 0; butnum < 5; butnum++)
{
devinfo->device()->add_item(
default_button_name(butnum),
static_cast<input_item_id>(ITEM_ID_BUTTON1 + butnum),
generic_button_get_state<BYTE>,
&devinfo->lightgun.rgbButtons[butnum]);
}
create_rawinput_device<rawinput_lightgun_device>(DEVICE_CLASS_LIGHTGUN, device);
}
};
} // anonymous namespace
} // namespace osd
#else // defined(OSD_WINDOWS)
#include "input_module.h"
namespace osd {
namespace {
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")
} // anonymous namespace
} // namespace osd
#endif // defined(OSD_WINDOWS)
MODULE_DEFINITION(KEYBOARDINPUT_RAWINPUT, keyboard_input_rawinput)
MODULE_DEFINITION(MOUSEINPUT_RAWINPUT, mouse_input_rawinput)
MODULE_DEFINITION(LIGHTGUNINPUT_RAWINPUT, lightgun_input_rawinput)
MODULE_DEFINITION(KEYBOARDINPUT_RAWINPUT, osd::keyboard_input_rawinput)
MODULE_DEFINITION(MOUSEINPUT_RAWINPUT, osd::mouse_input_rawinput)
MODULE_DEFINITION(LIGHTGUNINPUT_RAWINPUT, osd::lightgun_input_rawinput)

File diff suppressed because it is too large Load Diff

View File

@ -1,337 +0,0 @@
// 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)
#include "input_sdlcommon.h"
#include <cctype>
#include <cstddef>
#include <memory>
#include <algorithm>
// MAME headers
#include "emu.h"
#include "ui/uimain.h"
#include "uiinput.h"
#include "window.h"
#include "util/language.h"
#include "osdepend.h"
#include "strconv.h"
#include "../../sdl/osdsdl.h"
#include "input_common.h"
#define GET_WINDOW(ev) window_from_id((ev)->windowID)
//#define GET_WINDOW(ev) ((ev)->windowID)
static std::shared_ptr<sdl_window_info> window_from_id(Uint32 windowID)
{
SDL_Window *sdl_window = SDL_GetWindowFromID(windowID);
auto& windows = osd_common_t::s_window_list;
auto window = std::find_if(windows.begin(), windows.end(), [sdl_window](std::shared_ptr<osd_window> w)
{
return std::static_pointer_cast<sdl_window_info>(w)->platform_window() == sdl_window;
});
if (window == windows.end())
return nullptr;
return std::static_pointer_cast<sdl_window_info>(*window);
}
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
std::for_each(
subscribers.first,
subscribers.second,
[&sdlevent] (auto sub) { sub.second->handle_event(sdlevent); });
}
}
void sdl_event_manager::process_window_event(running_machine &machine, SDL_Event &sdlevent)
{
std::shared_ptr<sdl_window_info> window = GET_WINDOW(&sdlevent.window);
if (window == nullptr)
{
// This condition may occur when the fullscreen toggle is used
osd_printf_verbose("Skipped window event due to missing window param from SDL\n");
return;
}
switch (sdlevent.window.event)
{
case SDL_WINDOWEVENT_MOVED:
window->notify_changed();
m_focus_window = window;
break;
case SDL_WINDOWEVENT_RESIZED:
#ifdef SDLMAME_LINUX
/* 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);
}
break;
case SDL_WINDOWEVENT_ENTER:
m_mouse_over_window = 1;
break;
case SDL_WINDOWEVENT_LEAVE:
machine.ui_input().push_mouse_leave_event(window->target());
m_mouse_over_window = 0;
break;
case SDL_WINDOWEVENT_FOCUS_GAINED:
m_focus_window = window;
machine.ui_input().push_window_focus_event(window->target());
break;
case SDL_WINDOWEVENT_FOCUS_LOST:
machine.ui_input().push_window_defocus_event(window->target());
break;
case SDL_WINDOWEVENT_CLOSE:
machine.schedule_exit();
break;
}
}
//============================================================
// customize_input_type_list
//============================================================
void sdl_osd_interface::customize_input_type_list(std::vector<input_type_entry> &typelist)
{
// loop over the defaults
for (input_type_entry &entry : typelist)
{
switch (entry.type())
{
// configurable UI mode switch
case IPT_UI_TOGGLE_UI:
{
char const *const uimode = options().ui_mode_key();
input_item_id mameid_code = ITEM_ID_INVALID;
if (!uimode || !*uimode || !strcmp(uimode, "auto"))
{
#if defined(__APPLE__) && defined(__MACH__)
mameid_code = keyboard_trans_table::instance().lookup_mame_code("ITEM_ID_INSERT");
#endif
}
else
{
std::string fullmode("ITEM_ID_");
fullmode.append(uimode);
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", N_p("input-name", "Toggle Fullscreen"));
entry.defseq(SEQ_TYPE_STANDARD).set(KEYCODE_ENTER, 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.
// 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;
// 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", N_p("input-name", "Toggle Filter"));
entry.defseq(SEQ_TYPE_STANDARD).set(KEYCODE_F5, KEYCODE_LCONTROL);
break;
// LCTRL-F6 to decrease OpenGL prescaling
case IPT_OSD_6:
entry.configure_osd("DECREASE_PRESCALE", N_p("input-name", "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", N_p("input-name", "Increase Prescaling"));
entry.defseq(SEQ_TYPE_STANDARD).set(KEYCODE_F7, KEYCODE_LCONTROL);
break;
// lshift-lalt-F12 for fullscreen video (BGFX)
case IPT_OSD_8:
entry.configure_osd("RENDER_AVI", N_p("input-name", "Record Rendered Video"));
entry.defseq(SEQ_TYPE_STANDARD).set(KEYCODE_F12, KEYCODE_LSHIFT, KEYCODE_LALT);
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;
#if defined(__APPLE__) && defined(__MACH__)
// 78-key Apple MacBook & Bluetooth keyboards have no right control key
case IPT_MAHJONG_SCORE:
if (entry.player() == 0)
entry.defseq(SEQ_TYPE_STANDARD).set(KEYCODE_SLASH);
break;
#endif
// 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()
{
auto keybd = dynamic_cast<input_module_base*>(m_keyboard_input);
if (keybd != nullptr)
keybd->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().mouse_over_window())
return false;
// otherwise, yes
return true;
}
void sdl_osd_interface::process_events_buf()
{
SDL_PumpEvents();
}
//============================================================
// devmap_init - initializes a device_map based on
// an input option prefix and max number of devices
//============================================================
void device_map_t::init(running_machine &machine, 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++)
{
map[dev].name.clear();
map[dev].physical = -1;
logical[dev] = -1;
}
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
map[dev].name = remove_spaces(dev_name);
osd_printf_verbose("%s: Logical id %d: %s\n", label, dev + 1, map[dev].name);
initialized = 1;
}
}
}
#endif

View File

@ -1,142 +0,0 @@
// 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 MAME_OSD_INPUT_INPUT_SDLCOMMON_H
#define MAME_OSD_INPUT_INPUT_SDLCOMMON_H
#pragma once
// standard sdl header
#include <SDL2/SDL.h>
#include <algorithm>
#include <memory>
#include <mutex>
#include <string>
#include <unordered_map>
#define MAX_DEVMAP_ENTRIES 16
#define SDL_MODULE_EVENT_BUFFER_SIZE 5
struct device_map_t
{
struct {
std::string name;
int physical;
} map[MAX_DEVMAP_ENTRIES];
int logical[MAX_DEVMAP_ENTRIES];
int initialized;
void init(running_machine &machine, const char *opt, int max_devices, const char *label);
};
//============================================================
// event_manager_t
//============================================================
class sdl_event_subscriber
{
public:
virtual ~sdl_event_subscriber() {}
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:
virtual ~event_manager_t()
{
}
template <size_t N>
void subscribe(int const (&event_types)[N], TSubscriber *subscriber)
{
std::lock_guard<std::mutex> scope_lock(m_lock);
// Add the subscription
for (int i : event_types)
m_subscription_index.emplace(i, subscriber);
}
void unsubscribe(TSubscriber *subscriber)
{
std::lock_guard<std::mutex> scope_lock(m_lock);
// Remove the events that match the subscriber
for (auto it = begin(m_subscription_index); it != end(m_subscription_index);)
{
if (it->second == subscriber)
{
it = m_subscription_index.erase(it);
}
else
{
++it;
}
}
}
virtual void process_events(running_machine &machine) = 0;
};
class sdl_window_info;
class sdl_event_manager : public event_manager_t<sdl_event_subscriber>
{
private:
bool m_mouse_over_window;
std::shared_ptr<sdl_window_info> m_focus_window;
sdl_event_manager()
: m_mouse_over_window(true),
m_focus_window(nullptr)
{
}
public:
bool mouse_over_window() const { return m_mouse_over_window; }
bool has_focus() const { return m_focus_window != nullptr; }
std::shared_ptr<sdl_window_info> focus_window() const { 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 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;
}
#endif // MAME_OSD_INPUT_INPUT_SDLCOMMON_H

View File

@ -10,16 +10,25 @@
#if defined(OSD_WINDOWS)
#include "emu.h"
#include "input_windows.h"
#include "input_wincommon.h"
// osd/windows
#include "window.h"
// emu
#include "emu.h"
#include "inputdev.h"
#include "strconv.h"
// standard windows headers
#include <tchar.h>
namespace osd {
namespace {
//============================================================
@ -30,48 +39,21 @@ namespace {
class win32_keyboard_device : public event_based_device<KeyPressEventArgs>
{
public:
keyboard_state keyboard;
win32_keyboard_device(running_machine& machine, std::string &&name, std::string &&id, input_module &module)
: event_based_device(machine, std::move(name), std::move(id), DEVICE_CLASS_KEYBOARD, module),
keyboard({{0}})
win32_keyboard_device(std::string &&name, std::string &&id, input_module &module) :
event_based_device(std::move(name), std::move(id), module),
m_keyboard({{0}})
{
}
void reset() override
virtual void reset() override
{
memset(&keyboard, 0, sizeof(keyboard));
memset(&m_keyboard, 0, sizeof(m_keyboard));
}
protected:
void process_event(KeyPressEventArgs &args) override
virtual void configure(input_device &device) override
{
keyboard.state[args.scancode] = args.event_id == INPUT_EVENT_KEYDOWN ? 0x80 : 0x00;
}
};
keyboard_trans_table const &table = keyboard_trans_table::instance();
//============================================================
// keyboard_input_win32 - win32 keyboard input module
//============================================================
class keyboard_input_win32 : public wininput_module
{
private:
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
auto &devinfo = devicelist().create_device<win32_keyboard_device>(machine, "Win32 Keyboard 1", "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);
@ -80,63 +62,82 @@ public:
// generate the name
if (GetKeyNameText(((keynum & 0x7f) << 16) | ((keynum & 0x80) << 17), keyname, std::size(keyname)) == 0)
_sntprintf(keyname, std::size(keyname), TEXT("Scan%03d"), keynum);
std::string name = osd::text::from_tstring(keyname);
std::string name = text::from_tstring(keyname);
// add the item to the device
devinfo.device()->add_item(name, itemid, generic_button_get_state<std::uint8_t>, &devinfo.keyboard.state[keynum]);
device.add_item(
name,
itemid,
generic_button_get_state<std::uint8_t>,
&m_keyboard.state[keynum]);
}
}
bool handle_input_event(input_event eventid, void *eventdata) override
protected:
virtual void process_event(KeyPressEventArgs const &args) override
{
if (!input_enabled())
return false;
m_keyboard.state[args.scancode] = args.event_id == INPUT_EVENT_KEYDOWN ? 0x80 : 0x00;
}
KeyPressEventArgs *args;
private:
keyboard_state m_keyboard;
};
//============================================================
// keyboard_input_win32 - win32 keyboard input module
//============================================================
class keyboard_input_win32 : public wininput_module<win32_keyboard_device>
{
public:
keyboard_input_win32() : wininput_module<win32_keyboard_device>(OSD_KEYBOARDINPUT_PROVIDER, "win32")
{
}
virtual void input_init(running_machine &machine) override
{
wininput_module<win32_keyboard_device>::input_init(machine);
// Add a single win32 keyboard device that we'll monitor using Win32
create_device<win32_keyboard_device>(DEVICE_CLASS_KEYBOARD, "Win32 Keyboard 1", "Win32 Keyboard 1");
}
virtual bool handle_input_event(input_event eventid, void *eventdata) override
{
switch (eventid)
{
case INPUT_EVENT_KEYDOWN:
case INPUT_EVENT_KEYUP:
args = static_cast<KeyPressEventArgs*>(eventdata);
devicelist().for_each_device([args](auto device)
{
auto keyboard = dynamic_cast<win32_keyboard_device*>(device);
if (keyboard != nullptr)
keyboard->queue_events(args, 1);
});
case INPUT_EVENT_KEYDOWN:
case INPUT_EVENT_KEYUP:
devicelist().for_each_device(
[args = static_cast<KeyPressEventArgs const *>(eventdata)] (auto &device)
{
device.queue_events(args, 1);
});
return true;
return true;
default:
return false;
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, std::string &&name, std::string &&id, input_module &module)
: event_based_device(machine, std::move(name), std::move(id), DEVICE_CLASS_MOUSE, module),
mouse({0}),
win32_mouse({{0}})
win32_mouse_device(std::string &&name, std::string &&id, input_module &module) :
event_based_device(std::move(name), std::move(id), module),
m_mouse({0}),
m_win32_mouse({{0}})
{
}
void poll() override
virtual void poll() override
{
event_based_device::poll();
@ -149,140 +150,187 @@ public:
if (!(cursor_info.flags & CURSOR_SHOWING))
{
// We measure the position change from the previously set center position
mouse.lX = (cursor_info.ptScreenPos.x - win32_mouse.last_point.x) * osd::INPUT_RELATIVE_PER_PIXEL;
mouse.lY = (cursor_info.ptScreenPos.y - win32_mouse.last_point.y) * osd::INPUT_RELATIVE_PER_PIXEL;
m_mouse.lX = (cursor_info.ptScreenPos.x - m_win32_mouse.last_point.x) * INPUT_RELATIVE_PER_PIXEL;
m_mouse.lY = (cursor_info.ptScreenPos.y - m_win32_mouse.last_point.y) * INPUT_RELATIVE_PER_PIXEL;
RECT window_pos = {0};
GetWindowRect(std::static_pointer_cast<win_window_info>(osd_common_t::s_window_list.front())->platform_window(), &window_pos);
// 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;
m_win32_mouse.last_point.x = window_pos.left + (window_pos.right - window_pos.left) / 2;
m_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);
SetCursorPos(m_win32_mouse.last_point.x, m_win32_mouse.last_point.y);
}
}
void reset() override
virtual void configure(input_device &device) override
{
memset(&mouse, 0, sizeof(mouse));
memset(&win32_mouse, 0, sizeof(win32_mouse));
}
protected:
void process_event(MouseButtonEventArgs &args) override
{
// 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
{
public:
mouse_input_win32()
: wininput_module(OSD_MOUSEINPUT_PROVIDER, "win32")
{
}
virtual void input_init(running_machine &machine) override
{
if (!input_enabled() || !mouse_enabled())
return;
// allocate a device
auto &devinfo = devicelist().create_device<win32_mouse_device>(machine, "Win32 Mouse 1", "Win32 Mouse 1", *this);
// populate the axes
for (int axisnum = 0; axisnum < 2; axisnum++)
{
devinfo.device()->add_item(
default_axis_name[axisnum],
static_cast<input_item_id>(ITEM_ID_XAXIS + axisnum),
generic_axis_get_state<LONG>,
&devinfo.mouse.lX + axisnum);
device.add_item(
default_axis_name[axisnum],
input_item_id(ITEM_ID_XAXIS + axisnum),
generic_axis_get_state<LONG>,
&m_mouse.lX + axisnum);
}
// populate the buttons
for (int butnum = 0; butnum < 2; butnum++)
{
devinfo.device()->add_item(
default_button_name(butnum),
static_cast<input_item_id>(ITEM_ID_BUTTON1 + butnum),
generic_button_get_state<BYTE>,
&devinfo.mouse.rgbButtons[butnum]);
device.add_item(
default_button_name(butnum),
input_item_id(ITEM_ID_BUTTON1 + butnum),
generic_button_get_state<BYTE>,
&m_mouse.rgbButtons[butnum]);
}
}
bool handle_input_event(input_event eventid, void *eventdata) override
virtual void reset() override
{
if (!input_enabled() || !mouse_enabled() || eventid != INPUT_EVENT_MOUSE_BUTTON)
memset(&m_mouse, 0, sizeof(m_mouse));
memset(&m_win32_mouse, 0, sizeof(m_win32_mouse));
}
protected:
virtual void process_event(MouseButtonEventArgs const &args) override
{
// set the button state
m_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();
}
private:
struct win32_mouse_state
{
POINT last_point;
};
mouse_state m_mouse;
win32_mouse_state m_win32_mouse;
};
//============================================================
// mouse_input_win32 - win32 mouse input module
//============================================================
class mouse_input_win32 : public wininput_module<win32_mouse_device>
{
public:
mouse_input_win32() : wininput_module<win32_mouse_device>(OSD_MOUSEINPUT_PROVIDER, "win32")
{
}
virtual void input_init(running_machine &machine) override
{
wininput_module<win32_mouse_device>::input_init(machine);
if (!options()->mouse())
return;
// allocate a device
create_device<win32_mouse_device>(DEVICE_CLASS_MOUSE, "Win32 Mouse 1", "Win32 Mouse 1");
}
virtual bool handle_input_event(input_event eventid, void *eventdata) override
{
// TODO: remove need for this downcast
if (!downcast<::input_manager &>(manager()).device_class(DEVICE_CLASS_MOUSE).enabled() || eventid != INPUT_EVENT_MOUSE_BUTTON)
return false;
auto args = static_cast<MouseButtonEventArgs*>(eventdata);
devicelist().for_each_device([args](auto device)
{
auto mouse = dynamic_cast<win32_mouse_device*>(device);
if (mouse != nullptr)
mouse->queue_events(args, 1);
});
auto const *const args = static_cast<MouseButtonEventArgs *>(eventdata);
devicelist().for_each_device(
[args] (auto &device) { device.queue_events(args, 1); });
return true;
}
};
//============================================================
// win32_lightgun_device_base
//============================================================
class win32_lightgun_device_base : public event_based_device<MouseButtonEventArgs>
{
public:
virtual void reset() override
{
memset(&m_mouse, 0, sizeof(m_mouse));
}
virtual void configure(input_device &device) override
{
// populate the axes
for (int axisnum = 0; axisnum < 2; axisnum++)
{
device.add_item(
default_axis_name[axisnum],
input_item_id(ITEM_ID_XAXIS + axisnum),
generic_axis_get_state<LONG>,
&m_mouse.lX + axisnum);
}
// populate the buttons
for (int butnum = 0; butnum < 2; butnum++)
{
device.add_item(
default_button_name(butnum),
input_item_id(ITEM_ID_BUTTON1 + butnum),
generic_button_get_state<BYTE>,
&m_mouse.rgbButtons[butnum]);
}
}
protected:
win32_lightgun_device_base(
std::string &&name,
std::string &&id,
input_module &module) :
event_based_device(std::move(name), std::move(id), module),
m_mouse({ 0 })
{
}
mouse_state m_mouse;
};
//============================================================
// win32_lightgun_device
//============================================================
class win32_lightgun_device : public event_based_device<MouseButtonEventArgs>
class win32_lightgun_device : public win32_lightgun_device_base
{
private:
BOOL m_lightgun_shared_axis_mode;
int m_gun_index;
public:
mouse_state mouse;
win32_lightgun_device(running_machine& machine, std::string &&name, std::string &&id, input_module &module)
: event_based_device(machine, std::move(name), std::move(id), DEVICE_CLASS_LIGHTGUN, module),
m_lightgun_shared_axis_mode(FALSE),
m_gun_index(0),
mouse({0})
win32_lightgun_device(
std::string &&name,
std::string &&id,
input_module &module) :
win32_lightgun_device_base(std::move(name), std::move(id), module)
{
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
virtual void poll() override
{
event_based_device::poll();
int32_t 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
POINT mousepos;
GetCursorPos(&mousepos);
if (!osd_common_t::s_window_list.empty())
{
RECT client_rect;
// get the position relative to the window
HWND hwnd = std::static_pointer_cast<win_window_info>(osd_common_t::s_window_list.front())->platform_window();
HWND const hwnd = std::static_pointer_cast<win_window_info>(osd_common_t::s_window_list.front())->platform_window();
RECT client_rect;
GetClientRect(hwnd, &client_rect);
ScreenToClient(hwnd, &mousepos);
@ -292,91 +340,93 @@ public:
}
// update the X/Y positions
mouse.lX = xpos;
mouse.lY = ypos;
}
void reset() override
{
memset(&mouse, 0, sizeof(mouse));
m_mouse.lX = xpos;
m_mouse.lY = ypos;
}
protected:
void process_event(MouseButtonEventArgs &args) override
virtual void process_event(MouseButtonEventArgs const &args) override
{
// In non-shared axis mode, just update the button state
m_mouse.rgbButtons[args.button] = args.keydown ? 0x80 : 0x00;
}
};
//============================================================
// win32_dual_lightgun_device
//============================================================
class win32_dual_lightgun_device : public win32_lightgun_device_base
{
public:
win32_dual_lightgun_device(
std::string &&name,
std::string &&id,
input_module &module,
int index) :
win32_lightgun_device_base(std::move(name), std::move(id), module),
m_gun_index(index)
{
// 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)
protected:
virtual void process_event(MouseButtonEventArgs const &args) override
{
int button = args.button;
int const 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;
return; // We only handle the first four buttons in shared axis mode
else if (button >= 2 && m_gun_index == 0)
return; // First gun doesn't handle buttons 2 and 3
else if (button < 2 && m_gun_index == 1)
return; // Second gun doesn't handle buttons 0 and 1
// Adjust the button if we're the second lightgun
int logical_button = m_gun_index == 1 ? button - 2 : button;
int const logical_button = (m_gun_index == 1) ? (button - 2) : button;
// set the button state
mouse.rgbButtons[logical_button] = args.keydown ? 0x80 : 0x00;
m_mouse.rgbButtons[logical_button] = args.keydown ? 0x80 : 0x00;
if (args.keydown)
{
RECT client_rect;
POINT mousepos;
// get the position relative to the window
HWND hwnd = std::static_pointer_cast<win_window_info>(osd_common_t::s_window_list.front())->platform_window();
HWND const hwnd = std::static_pointer_cast<win_window_info>(osd_common_t::s_window_list.front())->platform_window();
RECT client_rect;
GetClientRect(hwnd, &client_rect);
POINT mousepos;
mousepos.x = args.xpos;
mousepos.y = args.ypos;
ScreenToClient(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);
m_mouse.lX = normalize_absolute_axis(mousepos.x, client_rect.left, client_rect.right);
m_mouse.lY = normalize_absolute_axis(mousepos.y, client_rect.top, client_rect.bottom);
}
}
private:
int const m_gun_index;
};
//============================================================
// lightgun_input_win32 - win32 lightgun input module
//============================================================
class lightgun_input_win32 : public wininput_module
class lightgun_input_win32 : public wininput_module<win32_lightgun_device_base>
{
public:
lightgun_input_win32()
: wininput_module(OSD_LIGHTGUNINPUT_PROVIDER, "win32")
lightgun_input_win32() : wininput_module<win32_lightgun_device_base>(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;
wininput_module<win32_lightgun_device_base>::input_init(machine);
bool const shared_axis_mode = dynamic_cast<windows_options const &>(*options()).dual_lightgun();
int const max_guns = shared_axis_mode ? 2 : 1;
// allocate the lightgun devices
for (int gunnum = 0; gunnum < max_guns; gunnum++)
@ -384,42 +434,22 @@ public:
static const char *const gun_names[] = { "Win32 Gun 1", "Win32 Gun 2" };
// allocate a device
auto &devinfo = devicelist().create_device<win32_lightgun_device>(machine, gun_names[gunnum], gun_names[gunnum], *this);
// populate the axes
for (int axisnum = 0; axisnum < 2; axisnum++)
{
devinfo.device()->add_item(
default_axis_name[axisnum],
static_cast<input_item_id>(ITEM_ID_XAXIS + axisnum),
generic_axis_get_state<LONG>,
&devinfo.mouse.lX + axisnum);
}
// populate the buttons
for (int butnum = 0; butnum < 2; butnum++)
{
devinfo.device()->add_item(
default_button_name(butnum),
static_cast<input_item_id>(ITEM_ID_BUTTON1 + butnum),
generic_button_get_state<BYTE>,
&devinfo.mouse.rgbButtons[butnum]);
}
if (shared_axis_mode)
create_device<win32_dual_lightgun_device>(DEVICE_CLASS_LIGHTGUN, gun_names[gunnum], gun_names[gunnum], gunnum);
else
create_device<win32_lightgun_device>(DEVICE_CLASS_LIGHTGUN, gun_names[gunnum], gun_names[gunnum]);
}
}
bool handle_input_event(input_event eventid, void* eventdata) override
virtual bool handle_input_event(input_event eventid, void *eventdata) override
{
if (!input_enabled() || !lightgun_enabled() || eventid != INPUT_EVENT_MOUSE_BUTTON)
// TODO: remove need for this downcast
if (!downcast<::input_manager &>(manager()).device_class(DEVICE_CLASS_LIGHTGUN).enabled() || eventid != INPUT_EVENT_MOUSE_BUTTON)
return false;
auto args = static_cast<MouseButtonEventArgs*>(eventdata);
devicelist().for_each_device([args](auto device)
{
auto lightgun = dynamic_cast<win32_lightgun_device*>(device);
if (lightgun != nullptr)
lightgun->queue_events(args, 1);
});
auto const *const args = static_cast<MouseButtonEventArgs *>(eventdata);
devicelist().for_each_device(
[args] (auto &device) { device.queue_events(args, 1); });
return true;
}
@ -427,14 +457,24 @@ public:
} // anonymous namespace
} // namespace osd
#else // defined(OSD_WINDOWS)
namespace osd {
namespace {
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")
} // anonymous namespace
} // namespace osd
#endif // defined(OSD_WINDOWS)
MODULE_DEFINITION(KEYBOARDINPUT_WIN32, keyboard_input_win32)
MODULE_DEFINITION(MOUSEINPUT_WIN32, mouse_input_win32)
MODULE_DEFINITION(LIGHTGUNINPUT_WIN32, lightgun_input_win32)
MODULE_DEFINITION(KEYBOARDINPUT_WIN32, osd::keyboard_input_win32)
MODULE_DEFINITION(MOUSEINPUT_WIN32, osd::mouse_input_win32)
MODULE_DEFINITION(LIGHTGUNINPUT_WIN32, osd::lightgun_input_win32)

View File

@ -0,0 +1,39 @@
// license:BSD-3-Clause
// copyright-holders:Aaron Giles
//============================================================
//
// input_wincommon.h - Common code used by Windows input modules
//
//============================================================
#ifndef MAME_OSD_INPUT_INPUT_WINCOMMON_H
#define MAME_OSD_INPUT_INPUT_WINCOMMON_H
#pragma once
#include "input_common.h"
#include <windows.h>
namespace osd {
// state information for a keyboard
struct keyboard_state
{
uint8_t state[MAX_KEYS];
int8_t oldkey[MAX_KEYS];
int8_t currkey[MAX_KEYS];
};
// state information for a mouse (matches DIMOUSESTATE exactly)
struct mouse_state
{
LONG lX;
LONG lY;
LONG lZ;
BYTE rgbButtons[8];
};
} // namespace osd
#endif // MAME_OSD_INPUT_INPUT_WINCOMMON_H

View File

@ -12,6 +12,7 @@
// MAME headers
#include "emu.h"
#include "inputdev.h"
#include "input_windows.h"
@ -25,51 +26,52 @@
bool windows_osd_interface::should_hide_mouse() const
{
bool hidemouse = false;
wininput_module *mod;
if (!winwindow_has_focus())
return false;
mod = dynamic_cast<wininput_module *>(m_keyboard_input);
if (mod) hidemouse |= mod->should_hide_mouse();
if (machine().paused())
return false;
mod = dynamic_cast<wininput_module *>(m_mouse_input);
if (mod) hidemouse |= mod->should_hide_mouse();
// track if mouse/lightgun is enabled, for mouse hiding purposes
bool const mouse_enabled = machine().input().device_class(DEVICE_CLASS_MOUSE).enabled();
bool const lightgun_enabled = machine().input().device_class(DEVICE_CLASS_LIGHTGUN).enabled();
if (!mouse_enabled && !lightgun_enabled)
return false;
mod = dynamic_cast<wininput_module *>(m_lightgun_input);
if (mod) hidemouse |= mod->should_hide_mouse();
mod = dynamic_cast<wininput_module *>(m_joystick_input);
if (mod) hidemouse |= mod->should_hide_mouse();
return hidemouse;
return true;
}
bool windows_osd_interface::handle_input_event(input_event eventid, void *eventdata) const
{
bool handled = false;
wininput_module *mod;
wininput_event_handler *mod;
mod = dynamic_cast<wininput_module *>(m_keyboard_input);
if (mod) handled |= mod->handle_input_event(eventid, eventdata);
mod = dynamic_cast<wininput_event_handler *>(m_keyboard_input);
if (mod)
handled |= mod->handle_input_event(eventid, eventdata);
mod = dynamic_cast<wininput_module *>(m_mouse_input);
if (mod) handled |= mod->handle_input_event(eventid, eventdata);
mod = dynamic_cast<wininput_event_handler *>(m_mouse_input);
if (mod)
handled |= mod->handle_input_event(eventid, eventdata);
mod = dynamic_cast<wininput_module *>(m_lightgun_input);
if (mod) handled |= mod->handle_input_event(eventid, eventdata);
mod = dynamic_cast<wininput_event_handler *>(m_lightgun_input);
if (mod)
handled |= mod->handle_input_event(eventid, eventdata);
mod = dynamic_cast<wininput_module *>(m_joystick_input);
if (mod) handled |= mod->handle_input_event(eventid, eventdata);
mod = dynamic_cast<wininput_event_handler *>(m_joystick_input);
if (mod)
handled |= mod->handle_input_event(eventid, eventdata);
return handled;
}
void windows_osd_interface::poll_input(running_machine &machine) const
{
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);
m_keyboard_input->poll_if_necessary();
m_mouse_input->poll_if_necessary();
m_lightgun_input->poll_if_necessary();
m_joystick_input->poll_if_necessary();
}
//============================================================

View File

@ -23,64 +23,26 @@
// TYPEDEFS
//============================================================
// state information for a keyboard
struct keyboard_state
{
uint8_t state[MAX_KEYS];
int8_t oldkey[MAX_KEYS];
int8_t 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
class wininput_event_handler
{
protected:
bool m_global_inputs_enabled = false;
wininput_event_handler() = default;
virtual ~wininput_event_handler() = default;
public:
wininput_module(const char *type, const char *name) : input_module_base(type, name) { }
virtual ~wininput_module() { }
virtual bool should_hide_mouse()
{
if (winwindow_has_focus() // has focus
&& (!video_config.windowed || !osd_common_t::s_window_list.front()->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)
virtual bool handle_input_event(input_event eventid, void *data)
{
return false;
}
};
template <typename Info>
class wininput_module : public input_module_impl<Info, osd_common_t>, public wininput_event_handler
{
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());
}
using input_module_impl<Info, osd_common_t>::input_module_impl;
};
#endif // MAME_OSD_INPUT_INPUT_WINDOWS_H

View File

@ -8,14 +8,11 @@
#include "modules/osdmodule.h"
#if defined(OSD_WINDOWS)
#include "emu.h"
#if defined(OSD_WINDOWS) || defined(SDLMAME_WIN32)
#include "input_dinput.h"
#include "input_xinput.h"
#include <list>
#include <vector>
#include <oleauto.h>
@ -26,8 +23,6 @@ namespace osd {
namespace {
using namespace Microsoft::WRL;
template <class TCom>
class ComArray
{
@ -44,7 +39,7 @@ public:
Release();
}
TCom** ReleaseAndGetAddressOf()
TCom **ReleaseAndGetAddressOf()
{
Release();
@ -52,7 +47,7 @@ public:
return &m_entries[0];
}
TCom* operator [] (int i)
TCom *operator[](int i)
{
return m_entries[i];
}
@ -66,7 +61,7 @@ public:
{
for (auto &entry : m_entries)
{
if (entry != nullptr)
if (entry)
{
entry->Release();
entry = nullptr;
@ -121,28 +116,25 @@ public:
typedef std::unique_ptr<OLECHAR, bstr_deleter> bstr_ptr;
//============================================================
// winhybrid_joystick_module
//============================================================
class winhybrid_joystick_module : public wininput_module, public device_enum_interface
class winhybrid_joystick_module : public input_module_impl<device_info, osd_common_t>, public device_enum_interface
{
private:
std::shared_ptr<xinput_api_helper> m_xinput_helper;
std::unique_ptr<xinput_api_helper> m_xinput_helper;
std::unique_ptr<dinput_api_helper> m_dinput_helper;
std::list<DWORD> m_xinput_deviceids;
bool m_xinput_detect_failed;
std::vector<DWORD> m_xinput_deviceids;
public:
winhybrid_joystick_module() :
wininput_module(OSD_JOYSTICKINPUT_PROVIDER, "winhybrid"),
m_xinput_helper(nullptr),
m_dinput_helper(nullptr),
m_xinput_detect_failed(false)
input_module_impl<device_info, osd_common_t>(OSD_JOYSTICKINPUT_PROVIDER, "winhybrid")
{
}
bool probe() override
virtual bool probe() override
{
int status = init_helpers();
if (status != 0)
@ -154,10 +146,12 @@ public:
return true;
}
int init(const osd_options &options) override
virtual int init(osd_interface &osd, const osd_options &options) override
{
int status;
// Call the base
int status = wininput_module::init(options);
status = input_module_impl<device_info, osd_common_t>::init(osd, options);
if (status != 0)
return status;
@ -172,89 +166,95 @@ public:
return 0;
}
BOOL device_enum_callback(LPCDIDEVICEINSTANCE instance, LPVOID ref) override
virtual BOOL device_enum_callback(LPCDIDEVICEINSTANCE instance) override
{
dinput_cooperative_level cooperative_level = dinput_cooperative_level::FOREGROUND;
running_machine &machine = *static_cast<running_machine *>(ref);
dinput_joystick_device *devinfo;
int result = 0;
// First check if this device is XInput Compatible. If so, don't add it here
// as it'll be picked up by Xinput
if (!m_xinput_detect_failed && is_xinput_device(&instance->guidProduct))
// First check if this device is XInput compatible.
// If so, don't add it here as it'll be picked up by Xinput.
if (is_xinput_device(instance->guidProduct))
{
osd_printf_verbose("Skipping DirectInput for XInput compatible joystick %S.\n", instance->tszInstanceName);
goto exit;
return DIENUM_CONTINUE;
}
if (!osd_common_t::s_window_list.empty() && osd_common_t::s_window_list.front()->win_has_menu())
cooperative_level = dinput_cooperative_level::BACKGROUND;
// allocate and link in a new device
devinfo = m_dinput_helper->create_device<dinput_joystick_device>(machine, *this, instance, &c_dfDIJoystick, nullptr, cooperative_level);
if (devinfo == nullptr)
goto exit;
auto devinfo = m_dinput_helper->create_device<dinput_joystick_device>(
*this,
instance,
&c_dfDIJoystick,
nullptr,
background_input() ? dinput_cooperative_level::BACKGROUND : dinput_cooperative_level::FOREGROUND,
[] (auto const &device, auto const &format) -> bool
{
// set absolute mode
HRESULT const result = dinput_api_helper::set_dword_property(
device,
DIPROP_AXISMODE,
0,
DIPH_DEVICE,
DIPROPAXISMODE_ABS);
if ((result != DI_OK) && (result != DI_PROPNOEFFECT))
{
osd_printf_error("DirectInput: Unable to set absolute mode for joystick.\n");
return false;
}
return true;
});
if (devinfo)
add_device(DEVICE_CLASS_JOYSTICK, std::move(devinfo));
result = devinfo->configure();
if (result != 0)
{
osd_printf_error("Failed to configure DI Joystick device. Error 0x%x\n", static_cast<unsigned int>(result));
}
exit:
return DIENUM_CONTINUE;
}
void exit() override
{
m_xinput_helper.reset();
m_dinput_helper.reset();
wininput_module::exit();
}
protected:
virtual void input_init(running_machine &machine) override
{
HRESULT result = get_xinput_devices(m_xinput_deviceids);
input_module_impl<device_info, osd_common_t>::input_init(machine);
bool xinput_detect_failed = false;
HRESULT result = get_xinput_devices();
if (result != 0)
{
m_xinput_detect_failed = true;
xinput_detect_failed = true;
m_xinput_deviceids.clear();
osd_printf_warning("XInput device detection failed. XInput won't be used. Error: 0x%X\n", uint32_t(result));
}
// Enumerate all the directinput joysticks and add them if they aren't xinput compatible
result = m_dinput_helper->enum_attached_devices(DI8DEVCLASS_GAMECTRL, this, &machine);
// Enumerate all the DirectInput joysticks and add them if they aren't XInput compatible
result = m_dinput_helper->enum_attached_devices(DI8DEVCLASS_GAMECTRL, *this);
if (result != DI_OK)
fatalerror("DirectInput: Unable to enumerate game controllers (result=%08X)\n", uint32_t(result));
fatalerror("DirectInput: Unable to enumerate game controllers (result=%08X).\n", uint32_t(result));
// now add all xinput devices
if (!m_xinput_detect_failed)
if (!xinput_detect_failed)
{
// Loop through each gamepad to determine if they are connected
for (UINT i = 0; i < XUSER_MAX_COUNT; i++)
{
XINPUT_STATE state = { 0 };
// allocate and link in a new device
if (m_xinput_helper->xinput_get_state(i, &state) == ERROR_SUCCESS)
m_xinput_helper->create_xinput_device(machine, i, *this);
auto devinfo = m_xinput_helper->create_xinput_device(i, *this);
if (devinfo)
add_device(DEVICE_CLASS_JOYSTICK, std::move(devinfo));
}
}
}
virtual void exit() override
{
input_module_impl<device_info, osd_common_t>::exit();
m_xinput_helper.reset();
m_dinput_helper.reset();
}
private:
int init_helpers()
{
int status = 0;
if (!m_xinput_helper)
{
m_xinput_helper = std::make_shared<xinput_api_helper>();
status = m_xinput_helper->initialize();
m_xinput_helper = std::make_unique<xinput_api_helper>();
int const status = m_xinput_helper->initialize();
if (status != 0)
{
osd_printf_verbose("xinput_api_helper failed to initialize! Error: %u\n", static_cast<unsigned int>(status));
osd_printf_verbose("Failed to initialize XInput API! Error: %u\n", static_cast<unsigned int>(status));
return -1;
}
}
@ -262,30 +262,28 @@ private:
if (!m_dinput_helper)
{
m_dinput_helper = std::make_unique<dinput_api_helper>();
status = m_dinput_helper->initialize();
int const status = m_dinput_helper->initialize();
if (status != DI_OK)
{
osd_printf_verbose("dinput_api_helper failed to initialize! Error: %u\n", static_cast<unsigned int>(status));
osd_printf_verbose("Failed to initialize DirectInput API! Error: %u\n", static_cast<unsigned int>(status));
return -1;
}
}
return status;
return 0;
}
//-----------------------------------------------------------------------------
// Returns true if the DirectInput device is also an XInput device.
//-----------------------------------------------------------------------------
bool is_xinput_device(const GUID* pGuidProductFromDirectInput)
bool is_xinput_device(GUID const &pGuidProductFromDirectInput) const
{
// Check each xinput device to see if this device's vid/pid matches
for (auto devid = m_xinput_deviceids.begin(); devid != m_xinput_deviceids.end(); ++devid)
{
if (*devid == pGuidProductFromDirectInput->Data1)
return true;
}
return false;
auto const found = std::find(
m_xinput_deviceids.begin(),
m_xinput_deviceids.end(),
pGuidProductFromDirectInput.Data1);
return m_xinput_deviceids.end() != found;
}
//-----------------------------------------------------------------------------
@ -295,54 +293,66 @@ private:
// Checking against a VID/PID of 0x028E/0x045E won't find 3rd party or future
// XInput devices.
//-----------------------------------------------------------------------------
HRESULT get_xinput_devices(std::list<DWORD> &xinput_id_list) const
HRESULT get_xinput_devices()
{
ComPtr<IWbemServices> pIWbemServices;
ComPtr<IEnumWbemClassObject> pEnumDevices;
ComPtr<IWbemLocator> pIWbemLocator;
ComArray<IWbemClassObject> pDevices(20);
bstr_ptr bstrDeviceID;
bstr_ptr bstrClassName;
bstr_ptr bstrNamespace;
DWORD uReturned = 0;
UINT iDevice;
variant_wrapper var;
HRESULT hr;
m_xinput_deviceids.clear();
// CoInit if needed
CoInitialize(nullptr);
class com_helper
{
public:
com_helper()
{
switch (CoInitialize(nullptr))
{
case S_OK:
case S_FALSE:
m_succeeded = true;
}
}
~com_helper()
{
if (m_succeeded)
CoUninitialize();
}
private:
bool m_succeeded = false;
};
com_helper cominit;
HRESULT hr;
// Create WMI
Microsoft::WRL::ComPtr<IWbemLocator> pIWbemLocator;
hr = CoCreateInstance(
__uuidof(WbemLocator),
nullptr,
CLSCTX_INPROC_SERVER,
__uuidof(IWbemLocator),
reinterpret_cast<void**>(pIWbemLocator.GetAddressOf()));
if (FAILED(hr) || pIWbemLocator == nullptr)
__uuidof(WbemLocator),
nullptr,
CLSCTX_INPROC_SERVER,
__uuidof(IWbemLocator),
reinterpret_cast<void **>(pIWbemLocator.GetAddressOf()));
if (FAILED(hr) || !pIWbemLocator)
{
osd_printf_error("Creating WbemLocator failed. Error: 0x%X\n", static_cast<unsigned int>(hr));
return hr;
}
// Create BSTRs for WMI
bstrNamespace = bstr_ptr(SysAllocString(L"\\\\.\\root\\cimv2"));
bstrDeviceID = bstr_ptr(SysAllocString(L"DeviceID"));
bstrClassName = bstr_ptr(SysAllocString(L"Win32_PNPEntity"));
bstr_ptr bstrNamespace = bstr_ptr(SysAllocString(L"\\\\.\\root\\cimv2"));
bstr_ptr bstrDeviceID = bstr_ptr(SysAllocString(L"DeviceID"));
bstr_ptr bstrClassName = bstr_ptr(SysAllocString(L"Win32_PNPEntity"));
// Connect to WMI
Microsoft::WRL::ComPtr<IWbemServices> pIWbemServices;
hr = pIWbemLocator->ConnectServer(
bstrNamespace.get(),
nullptr,
nullptr,
nullptr,
0L,
nullptr,
nullptr,
pIWbemServices.GetAddressOf());
if (FAILED(hr) || pIWbemServices == nullptr)
bstrNamespace.get(),
nullptr,
nullptr,
nullptr,
0L,
nullptr,
nullptr,
pIWbemServices.GetAddressOf());
if (FAILED(hr) || !pIWbemServices)
{
osd_printf_error("Connecting to WMI Server failed. Error: 0x%X\n", static_cast<unsigned int>(hr));
return hr;
@ -350,38 +360,41 @@ private:
// Switch security level to IMPERSONATE
(void)CoSetProxyBlanket(
pIWbemServices.Get(),
RPC_C_AUTHN_WINNT,
RPC_C_AUTHZ_NONE,
nullptr,
RPC_C_AUTHN_LEVEL_CALL,
RPC_C_IMP_LEVEL_IMPERSONATE,
nullptr,
0);
pIWbemServices.Get(),
RPC_C_AUTHN_WINNT,
RPC_C_AUTHZ_NONE,
nullptr,
RPC_C_AUTHN_LEVEL_CALL,
RPC_C_IMP_LEVEL_IMPERSONATE,
nullptr,
0);
// Get list of Win32_PNPEntity devices
Microsoft::WRL::ComPtr<IEnumWbemClassObject> pEnumDevices;
hr = pIWbemServices->CreateInstanceEnum(bstrClassName.get(), 0, nullptr, pEnumDevices.GetAddressOf());
if (FAILED(hr) || pEnumDevices == nullptr)
if (FAILED(hr) || !pEnumDevices)
{
osd_printf_error("Getting list of Win32_PNPEntity devices failed. Error: 0x%X\n", static_cast<unsigned int>(hr));
return hr;
}
// Loop over all devices
for (; ; )
ComArray<IWbemClassObject> pDevices(20);
variant_wrapper var;
for ( ; ; )
{
// Get a few at a time
DWORD uReturned = 0;
hr = pEnumDevices->Next(10000, pDevices.Size(), pDevices.ReleaseAndGetAddressOf(), &uReturned);
if (FAILED(hr))
{
osd_printf_error("Enumerating WMI classes failed. Error: 0x%X\n", static_cast<unsigned int>(hr));
return hr;
}
if (uReturned == 0)
break;
for (iDevice = 0; iDevice < uReturned; iDevice++)
for (UINT iDevice = 0; iDevice < uReturned; iDevice++)
{
if (!pDevices[iDevice])
continue;
@ -395,19 +408,18 @@ private:
if (wcsstr(var.Get().bstrVal, L"IG_"))
{
// If it does, then get the VID/PID from var.bstrVal
DWORD dwPid = 0, dwVid = 0;
WCHAR* strVid = wcsstr(var.Get().bstrVal, L"VID_");
DWORD dwVid = 0;
WCHAR const *const strVid = wcsstr(var.Get().bstrVal, L"VID_");
if (strVid && swscanf(strVid, L"VID_%4X", &dwVid) != 1)
dwVid = 0;
WCHAR* strPid = wcsstr(var.Get().bstrVal, L"PID_");
DWORD dwPid = 0;
WCHAR const *const strPid = wcsstr(var.Get().bstrVal, L"PID_");
if (strPid && swscanf(strPid, L"PID_%4X", &dwPid) != 1)
dwPid = 0;
DWORD dwVidPid = MAKELONG(dwVid, dwPid);
// Add the VID/PID to a linked list
xinput_id_list.push_back(dwVidPid);
// Add the VID/PID to a list
m_xinput_deviceids.push_back(MAKELONG(dwVid, dwPid));
}
}
}
@ -424,12 +436,12 @@ private:
} // namespace osd
#else // defined(OSD_WINDOWS)
#else // defined(OSD_WINDOWS) || defined(SDLMAME_WIN32)
#include "input_module.h"
namespace osd { MODULE_NOT_SUPPORTED(winhybrid_joystick_module, OSD_JOYSTICKINPUT_PROVIDER, "winhybrid") }
namespace osd { namespace { MODULE_NOT_SUPPORTED(winhybrid_joystick_module, OSD_JOYSTICKINPUT_PROVIDER, "winhybrid") } }
#endif // defined(OSD_WINDOWS)
#endif // defined(OSD_WINDOWS) || defined(SDLMAME_WIN32)
MODULE_DEFINITION(JOYSTICKINPUT_WINHYBRID, osd::winhybrid_joystick_module)

View File

@ -9,35 +9,39 @@
//============================================================
#include "input_module.h"
#include "modules/osdmodule.h"
#if defined(SDLMAME_SDL2) && !defined(SDLMAME_WIN32) && defined(USE_XINPUT) && USE_XINPUT
#include "input_common.h"
#include "sdl/osdsdl.h"
// MAME headers
#include "emu.h"
// standard SDL header
#include <SDL2/SDL.h>
// for X11 xinput
#include <X11/Xlib.h>
#include <X11/extensions/XInput.h>
#include <X11/Xutil.h>
// standard sdl header
#include <SDL2/SDL.h>
#include <algorithm>
#include <cctype>
#include <cstddef>
#include <mutex>
#include <cstdio>
#include <cstring>
#include <memory>
#include <mutex>
#include <queue>
#include <string>
#include <algorithm>
#include <unordered_map>
// 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"
namespace osd {
namespace {
@ -52,20 +56,6 @@ 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_t lX, lY;
int32_t buttons[MAX_BUTTONS];
};
struct x11_api_state
{
XID deviceid; // X11 device id
int32_t maxx, maxy;
int32_t minx, miny;
};
//============================================================
// DEBUG MACROS
//============================================================
@ -74,56 +64,64 @@ struct x11_api_state
#define XI_DBG(format, ...) osd_printf_verbose(format, __VA_ARGS__)
#define print_motion_event(motion) print_motion_event_impl(motion)
inline void print_motion_event_impl(XDeviceMotionEvent *motion)
inline void print_motion_event_impl(XDeviceMotionEvent const *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]
);
"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) {}
#define XI_DBG(format, ...) do { } while (false)
#define print_motion_event(motion) do { } while (false)
#endif
inline std::string remove_spaces(const char *s)
{
std::string output(s);
output.erase(std::remove_if(output.begin(), output.end(), isspace), output.end());
return output;
}
//============================================================
// lightgun helpers: copy-past from xinfo
//============================================================
@ -141,7 +139,7 @@ find_device_info(Display *display,
bool is_id = true;
XID id = static_cast<XID>(-1);
for(loop = 0; loop < len; loop++)
for (loop = 0; loop < len; loop++)
{
if (!isdigit(name[loop]))
{
@ -157,7 +155,7 @@ find_device_info(Display *display,
devices = XListInputDevices(display, &num_devices);
for(loop = 0; loop < num_devices; loop++)
for (loop = 0; loop < num_devices; loop++)
{
osd_printf_verbose("Evaluating device with name: %s\n", devices[loop].name);
@ -255,19 +253,64 @@ register_events(
return number;
}
struct device_map
{
static inline constexpr unsigned MAX_ENTRIES = 16;
struct {
std::string name;
int physical;
} map[MAX_ENTRIES];
int logical[MAX_ENTRIES];
int initialized;
void init(osd_options const &options, const char *opt, int max_devices, const char *label)
{
// initialize based on an input option prefix and max number of devices
char defname[20];
// The max devices the user specified, better not be bigger than the max the arrays can old
assert(max_devices <= MAX_ENTRIES);
// Initialize the map to default uninitialized values
for (int dev = 0; dev < MAX_ENTRIES; dev++)
{
map[dev].name.clear();
map[dev].physical = -1;
logical[dev] = -1;
}
initialized = 0;
// populate the device map up to the max number of devices
for (int 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 = 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
map[dev].name = remove_spaces(dev_name);
osd_printf_verbose("%s: Logical id %d: %s\n", label, dev + 1, map[dev].name);
initialized = 1;
}
}
}
};
//============================================================
// x11_event_manager
//============================================================
class x11_event_handler
{
public:
virtual ~x11_event_handler() {}
virtual void handle_event(XEvent &xevent) = 0;
};
class x11_event_manager : public event_manager_t<x11_event_handler>
class x11_event_manager : public event_subscription_manager<XEvent, int>
{
private:
struct x_cleanup
@ -288,14 +331,12 @@ private:
x_ptr<Display> m_display;
x11_event_manager() : event_manager_t()
{
}
x11_event_manager() = default;
public:
Display * display() const { return m_display.get(); }
Display *display() const { return m_display.get(); }
static x11_event_manager& instance()
static x11_event_manager &instance()
{
static x11_event_manager s_instance;
return s_instance;
@ -303,7 +344,7 @@ public:
int initialize()
{
std::lock_guard<std::mutex> scope_lock(m_lock);
std::lock_guard<std::mutex> scope_lock(subscription_mutex());
if (m_display)
return 0;
@ -325,31 +366,24 @@ public:
return 0;
}
void process_events(running_machine &machine) override
void process_events()
{
std::lock_guard<std::mutex> scope_lock(m_lock);
XEvent xevent;
std::lock_guard<std::mutex> scope_lock(subscription_mutex());
// If X11 has become invalid for some reason, XPending will crash. Assert instead.
assert(m_display);
//Get XInput events
// Get XInput events
while (XPending(m_display.get()) != 0)
{
XNextEvent(m_display.get(), &xevent);
// Find all subscribers for the event type
auto const subscribers = m_subscription_index.equal_range(xevent.type);
// Dispatch the events
std::for_each(
subscribers.first,
subscribers.second,
[&xevent] (auto &pair) { pair.second->handle_event(xevent); });
XEvent event;
XNextEvent(m_display.get(), &event);
dispatch_event(event.type, event);
}
}
};
//============================================================
// x11_input_device
//============================================================
@ -357,15 +391,23 @@ public:
class x11_input_device : public event_based_device<XEvent>
{
public:
x11_api_state x11_state;
x11_input_device(running_machine &machine, std::string &&name, std::string &&id, input_device_class devclass, input_module &module) :
event_based_device(machine, std::move(name), std::move(id), devclass, module),
x11_state({0})
x11_input_device(
std::string &&name,
std::string &&id,
input_module &module,
XDeviceInfo const *info) :
event_based_device(std::move(name), std::move(id), module),
m_device_id(info ? info->id : 0)
{
}
XID const &device_id() const { return m_device_id; }
protected:
XID const m_device_id; // X11 device ID
};
//============================================================
// x11_lightgun_device
//============================================================
@ -373,55 +415,124 @@ public:
class x11_lightgun_device : public x11_input_device
{
public:
lightgun_state lightgun;
x11_lightgun_device(running_machine &machine, std::string &&name, std::string &&id, input_module &module) :
x11_input_device(machine, std::move(name), std::move(id), DEVICE_CLASS_LIGHTGUN, module),
lightgun({0})
x11_lightgun_device(
std::string &&name,
std::string &&id,
input_module
&module,
XDeviceInfo *info) :
x11_input_device(std::move(name), std::move(id), module, info),
m_axis_count(0),
m_button_count(0),
m_maxx(0),
m_maxy(0),
m_minx(0),
m_miny(0),
m_lightgun({ 0 })
{
if (info && (info->num_classes > 0))
{
// Grab device info and translate to stuff MAME can use
XAnyClassPtr any = static_cast<XAnyClassPtr>(info->inputclassinfo);
for (int i = 0; i < info->num_classes; i++)
{
switch (any->c_class)
{
// Set the axis min/max ranges if we got them
case ValuatorClass:
{
auto const valuator_info = reinterpret_cast<XValuatorInfoPtr>(any);
auto axis_info = reinterpret_cast<XAxisInfoPtr>(reinterpret_cast<char *>(valuator_info) + sizeof(XValuatorInfo));
for (int j = 0; (j < valuator_info->num_axes) && (j < 2); j++, axis_info++)
{
if (j == 0)
{
XI_DBG("Set minx=%d, maxx=%d\n", axis_info->min_value, axis_info->max_value);
m_axis_count = 1;
m_maxx = axis_info->max_value;
m_minx = axis_info->min_value;
}
if (j == 1)
{
XI_DBG("Set miny=%d, maxy=%d\n", axis_info->min_value, axis_info->max_value);
m_axis_count = 2;
m_maxy = axis_info->max_value;
m_miny = axis_info->min_value;
}
}
}
break;
// Count the lightgun buttons based on what we read
case ButtonClass:
{
XButtonInfoPtr b = reinterpret_cast<XButtonInfoPtr>(any);
if (b->num_buttons < 0)
m_button_count = 0;
else if (b->num_buttons <= MAX_BUTTONS)
m_button_count = b->num_buttons;
else
m_button_count = MAX_BUTTONS;
}
break;
}
any = reinterpret_cast<XAnyClassPtr>(reinterpret_cast<char *>(any) + any->length);
}
}
}
void process_event(XEvent &xevent) override
virtual void reset() override
{
memset(&m_lightgun, 0, sizeof(m_lightgun));
}
virtual void configure(input_device &device) override
{
// Add buttons
for (int button = 0; button < m_button_count; button++)
{
input_item_id const itemid = input_item_id(ITEM_ID_BUTTON1 + button);
device.add_item(default_button_name(button), std::string_view(), itemid, generic_button_get_state<std::int32_t>, &m_lightgun.buttons[button]);
}
// Add X and Y axis
if (1 <= m_axis_count)
device.add_item("X", ITEM_ID_XAXIS, generic_axis_get_state<std::int32_t>, &m_lightgun.lX);
if (2 <= m_axis_count)
device.add_item("Y", ITEM_ID_YAXIS, generic_axis_get_state<std::int32_t>, &m_lightgun.lY);
}
virtual void process_event(XEvent const &xevent) override
{
if (xevent.type == motion_type)
{
XDeviceMotionEvent *motion = reinterpret_cast<XDeviceMotionEvent *>(&xevent);
auto const motion = reinterpret_cast<XDeviceMotionEvent const *>(&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.
*/
// We have to check with axis will start on array index 0.
// We also have 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.
*/
// Starting with x, check number of axes, 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);
}
}
m_lightgun.lX = normalize_absolute_axis(motion->axis_data[0], m_minx, m_maxx);
if (motion->axes_count >= 2)
m_lightgun.lY = normalize_absolute_axis(motion->axis_data[1], m_miny, m_maxy);
break;
/*
* Starting with y, ...
*/
// 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);
}
m_lightgun.lY = normalize_absolute_axis(motion->axis_data[0], m_miny, m_maxy);
break;
}
}
else if (xevent.type == button_press_type || xevent.type == button_release_type)
{
XDeviceButtonEvent *button = reinterpret_cast<XDeviceButtonEvent *>(&xevent);
auto const button = reinterpret_cast<XDeviceButtonEvent const *>(&xevent);
/*
* SDL/X11 Number the buttons 1,2,3, while windows and other parts of MAME
@ -429,37 +540,50 @@ public:
* -1 the button number to align the numbering schemes.
*/
int button_number = button->button;
switch (button_number)
if (button_number <= MAX_BUTTONS)
{
switch (button_number)
{
case 2:
button_number = 3;
break;
case 3:
button_number = 2;
button_number ^= 1;
break;
}
m_lightgun.buttons[button_number - 1] = (xevent.type == button_press_type) ? 0x80 : 0;
}
lightgun.buttons[button_number - 1] = (xevent.type == button_press_type) ? 0x80 : 0;
}
}
void reset() override
private:
struct lightgun_state
{
memset(&lightgun, 0, sizeof(lightgun));
}
int32_t lX, lY;
int32_t buttons[MAX_BUTTONS];
};
int m_axis_count;
int m_button_count;
int32_t m_maxx;
int32_t m_maxy;
int32_t m_minx;
int32_t m_miny;
lightgun_state m_lightgun;
};
//============================================================
// x11_lightgun_module
//============================================================
class x11_lightgun_module : public input_module_base, public x11_event_handler
class x11_lightgun_module : public input_module_impl<x11_input_device, osd_common_t>, public x11_event_manager::subscriber
{
private:
device_map_t m_lightgun_map;
Display * m_display;
device_map m_lightgun_map;
Display *m_display;
public:
x11_lightgun_module() :
input_module_base(OSD_LIGHTGUNINPUT_PROVIDER, "x11"),
input_module_impl<x11_input_device, osd_common_t>(OSD_LIGHTGUNINPUT_PROVIDER, "x11"),
m_display(nullptr)
{
}
@ -467,113 +591,109 @@ public:
virtual bool probe() override
{
// If there is no X server, X11 lightguns cannot be supported
if (!XOpenDisplay(nullptr))
{
Display *const display = XOpenDisplay(nullptr);
if (!display)
return false;
}
XCloseDisplay(display);
return true;
}
void input_init(running_machine &machine) override
virtual int init(osd_interface &osd, osd_options const &options) override
{
osd_printf_verbose("Lightgun: Begin initialization\n");
m_lightgun_map.init(machine, SDLOPTION_LIGHTGUNINDEX, 8, "Lightgun mapping");
// If the X server has become invalid, a crash can occur
x11_event_manager::instance().initialize();
m_display = x11_event_manager::instance().display();
if (!m_display)
return -1;
// If the X server has become invalid, a crash can occur
assert(m_display != nullptr);
return input_module_impl<x11_input_device, osd_common_t>::init(osd, options);
}
virtual void input_init(running_machine &machine) override
{
assert(m_display);
input_module_impl<x11_input_device, osd_common_t>::input_init(machine);
osd_printf_verbose("Lightgun: Begin initialization\n");
m_lightgun_map.init(*options(), SDLOPTION_LIGHTGUNINDEX, 8, "Lightgun mapping");
// Loop through all 8 possible devices
for (int index = 0; index < 8; index++)
{
XDeviceInfo *info;
// Skip if the name is empty
if (m_lightgun_map.map[index].name.length() == 0)
if (m_lightgun_map.map[index].name.empty())
continue;
std::string const &name = m_lightgun_map.map[index].name;
char defname[512];
// Register and add the device
auto *devinfo = create_lightgun_device(machine, index);
osd_printf_verbose("%i: %s\n", index, name);
// 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
std::string const &name = m_lightgun_map.map[index].name;
osd_printf_verbose("%i: %s\n", index, name);
XDeviceInfo *const info = find_device_info(m_display, name.c_str(), 0);
if (!info)
{
osd_printf_verbose("Can't find device %s!\n", name);
continue;
}
osd_printf_verbose("Lightgun: Can't find device %s!\n", name);
//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(static_cast<XAnyClassPtr>(info->inputclassinfo), info->num_classes, *devinfo);
// previously had code to use "NC%d" format if name was empty
// but that couldn't happen because device creation would be skipped
// Also, set the axix min/max ranges if we got them
set_lightgun_axis_props(static_cast<XAnyClassPtr>(info->inputclassinfo), info->num_classes, *devinfo);
}
// Add X and Y axis
sprintf(defname, "X %s", devinfo->name().c_str());
devinfo->device()->add_item(defname, ITEM_ID_XAXIS, generic_axis_get_state<std::int32_t>, &devinfo->lightgun.lX);
sprintf(defname, "Y %s", devinfo->name().c_str());
devinfo->device()->add_item(defname, ITEM_ID_YAXIS, generic_axis_get_state<std::int32_t>, &devinfo->lightgun.lY);
// Save the device id
devinfo->x11_state.deviceid = info->id;
// Register and add the device
create_device<x11_lightgun_device>(
DEVICE_CLASS_LIGHTGUN,
std::string(name),
std::string(name),
info);
// 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", static_cast<int>(info->id), events_registered);
// register ourself to handle events from event manager
int const 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, this);
if (info)
{
int const events_registered = register_events(m_display, info, 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 const 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);
subscribe(x11_event_manager::instance(), event_types);
osd_printf_verbose("Lightgun: End initialization\n");
}
bool should_poll_devices(running_machine &machine) override
virtual void exit() override
{
return sdl_event_manager::instance().has_focus();
// unsubscribe from events
unsubscribe();
input_module_impl<x11_input_device, osd_common_t>::exit();
}
void before_poll(running_machine &machine) override
virtual bool should_poll_devices() override
{
if (!should_poll_devices(machine))
return;
return osd().has_focus();
}
virtual void before_poll() override
{
// trigger the SDL event manager so it can process window events
input_module_impl<x11_input_device, osd_common_t>::before_poll();
// 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);
if (should_poll_devices())
x11_event_manager::instance().process_events();
}
void handle_event(XEvent &xevent) override
virtual void handle_event(XEvent const &xevent) override
{
XID deviceid;
if (xevent.type == motion_type)
{
XDeviceMotionEvent *motion = reinterpret_cast<XDeviceMotionEvent *>(&xevent);
auto const motion = reinterpret_cast<XDeviceMotionEvent const *>(&xevent);
deviceid = motion->deviceid;
}
else if (xevent.type == button_press_type || xevent.type == button_release_type)
{
XDeviceButtonEvent *button = reinterpret_cast<XDeviceButtonEvent *>(&xevent);
auto const button = reinterpret_cast<XDeviceButtonEvent const *>(&xevent);
deviceid = button->deviceid;
}
else
@ -582,102 +702,27 @@ public:
}
// Figure out which lightgun this event id destined for
auto target_device = std::find_if(devicelist().begin(), devicelist().end(), [deviceid](auto &device)
{
std::unique_ptr<device_info> &ptr = device;
return downcast<x11_input_device*>(ptr.get())->x11_state.deviceid == deviceid;
});
auto target_device = std::find_if(
devicelist().begin(),
devicelist().end(),
[&deviceid] (auto &device) { return device->device_id() == deviceid; });
// If we find a matching lightgun, dispatch the event to the lightgun
if (target_device != devicelist().end())
{
downcast<x11_input_device*>((*target_device).get())->queue_events(&xevent, 1);
}
}
private:
x11_lightgun_device *create_lightgun_device(running_machine &machine, int index)
{
if (m_lightgun_map.map[index].name.length() == 0)
{
if (m_lightgun_map.initialized)
{
char tempname[20];
snprintf(tempname, std::size(tempname), "NC%d", index);
return &devicelist().create_device<x11_lightgun_device>(machine, tempname, tempname, *this);
}
else
{
return nullptr;
}
}
return &devicelist().create_device<x11_lightgun_device>(machine, std::string(m_lightgun_map.map[index].name), std::string(m_lightgun_map.map[index].name), *this);
}
void add_lightgun_buttons(XAnyClassPtr first_info_class, int num_classes, x11_lightgun_device &devinfo) const
{
XAnyClassPtr any = first_info_class;
for (int i = 0; i < num_classes; i++)
{
switch (any->c_class)
{
case ButtonClass:
XButtonInfoPtr b = reinterpret_cast<XButtonInfoPtr>(any);
for (int button = 0; button < b->num_buttons; button++)
{
input_item_id itemid = static_cast<input_item_id>(ITEM_ID_BUTTON1 + button);
devinfo.device()->add_item(default_button_name(button), itemid, generic_button_get_state<std::int32_t>, &devinfo.lightgun.buttons[button]);
}
break;
}
any = reinterpret_cast<XAnyClassPtr>(reinterpret_cast<char *>(any) + any->length);
}
}
void set_lightgun_axis_props(XAnyClassPtr first_info_class, int num_classes, x11_lightgun_device &devinfo) const
{
XAnyClassPtr any = first_info_class;
for (int i = 0; i < num_classes; i++)
{
switch (any->c_class)
{
case ValuatorClass:
XValuatorInfoPtr valuator_info = reinterpret_cast<XValuatorInfoPtr>(any);
XAxisInfoPtr axis_info = reinterpret_cast<XAxisInfoPtr>(reinterpret_cast<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 = reinterpret_cast<XAnyClassPtr>(reinterpret_cast<char *>(any) + any->length);
}
(*target_device)->queue_events(&xevent, 1);
}
};
} // anonymous namespace
} // namespace osd
#else // defined(SDLMAME_SDL2) && !defined(SDLMAME_WIN32) && defined(USE_XINPUT) && USE_XINPUT
MODULE_NOT_SUPPORTED(x11_lightgun_module, OSD_LIGHTGUNINPUT_PROVIDER, "x11")
namespace osd { namespace { MODULE_NOT_SUPPORTED(x11_lightgun_module, OSD_LIGHTGUNINPUT_PROVIDER, "x11") } }
#endif // defined(SDLMAME_SDL2) && !defined(SDLMAME_WIN32) && defined(USE_XINPUT) && USE_XINPUT
MODULE_DEFINITION(LIGHTGUN_X11, x11_lightgun_module)
MODULE_DEFINITION(LIGHTGUN_X11, osd::x11_lightgun_module)

View File

@ -1,5 +1,5 @@
// license:BSD-3-Clause
// copyright-holders:Brad Hughes
// copyright-holders:Brad Hughes, Vas Crabb
//============================================================
//
// input_xinput.cpp - XInput API input support for Windows
@ -176,14 +176,19 @@ LSX 15 C
#include "modules/osdmodule.h"
#if defined(OSD_WINDOWS)
#include "emu.h"
#if defined(OSD_WINDOWS) || defined(SDLMAME_WIN32)
#include "input_xinput.h"
// standard windows headers
#include <windows.h>
#include "modules/lib/osdobj_common.h"
// emu
#include "emu.h"
// lib/util
#include "util/coretmpl.h"
#include "eminline.h"
#include <algorithm>
#include <cstdint>
@ -191,6 +196,9 @@ LSX 15 C
#include <tuple>
#include <utility>
// standard windows headers
#include <windows.h>
#define XINPUT_LIBRARIES { "xinput1_4.dll", "xinput9_1_0.dll" }
@ -201,6 +209,9 @@ namespace osd {
namespace {
using util::BIT;
char const *const AXIS_NAMES_GAMEPAD[]{
"LSX",
"LSY",
@ -325,18 +336,14 @@ char const *const BUTTON_NAMES_KEYBOARD[]{
class xinput_device_base : public device_info
{
public:
virtual void configure() = 0;
protected:
xinput_device_base(
running_machine &machine,
std::string &&name,
std::string &&id,
input_module &module,
u32 player,
XINPUT_CAPABILITIES const &caps,
std::shared_ptr<xinput_api_helper> const &helper);
xinput_api_helper const &helper);
// capabilities
BYTE device_type() const { return m_capabilities.Type; }
@ -370,19 +377,18 @@ private:
XINPUT_STATE m_xinput_state;
bool m_reset;
std::shared_ptr<xinput_api_helper> m_xinput_helper;
xinput_api_helper const &m_xinput_helper;
};
xinput_device_base::xinput_device_base(
running_machine &machine,
std::string &&name,
std::string &&id,
input_module &module,
u32 player,
XINPUT_CAPABILITIES const &caps,
std::shared_ptr<xinput_api_helper> const &helper) :
device_info(machine, std::move(name), std::move(id), DEVICE_CLASS_JOYSTICK, module),
xinput_api_helper const &helper) :
device_info(std::move(name), std::move(id), module),
m_player_index(player),
m_capabilities(caps),
m_xinput_state{ 0 },
@ -522,7 +528,7 @@ bool xinput_device_base::read_state()
{
// save previous packet number and try to read peripheral state
DWORD const prevpacket = m_xinput_state.dwPacketNumber;
HRESULT const result = m_xinput_helper->xinput_get_state(m_player_index, &m_xinput_state);
HRESULT const result = m_xinput_helper.xinput_get_state(m_player_index, &m_xinput_state);
// only update if it succeeded and the packed number changed
if (FAILED(result))
@ -593,18 +599,16 @@ class xinput_joystick_device : public xinput_device_base
{
public:
xinput_joystick_device(
running_machine &machine,
std::string &&name,
std::string &&id,
input_module &module,
u32 player,
XINPUT_CAPABILITIES const &caps,
std::shared_ptr<xinput_api_helper> const &helper);
xinput_api_helper const &helper);
virtual void poll() override;
virtual void reset() override;
virtual void configure() override;
virtual void configure(input_device &device) override;
private:
static inline constexpr USHORT SWITCH_BITS[] =
@ -677,14 +681,13 @@ private:
xinput_joystick_device::xinput_joystick_device(
running_machine &machine,
std::string &&name,
std::string &&id,
input_module &module,
u32 player,
XINPUT_CAPABILITIES const &caps,
std::shared_ptr<xinput_api_helper> const &helper) :
xinput_device_base(machine, std::move(name), std::move(id), module, player, caps, helper)
xinput_api_helper const &helper) :
xinput_device_base(std::move(name), std::move(id), module, player, caps, helper)
{
std::fill(std::begin(m_switches), std::end(m_switches), 0);
std::fill(std::begin(m_axes), std::end(m_axes), 0);
@ -735,7 +738,7 @@ void xinput_joystick_device::reset()
}
void xinput_joystick_device::configure()
void xinput_joystick_device::configure(input_device &device)
{
// TODO: proper support for dance mat controllers
@ -789,7 +792,7 @@ void xinput_joystick_device::configure()
{
if (axis_caps[i])
{
device()->add_item(
device.add_item(
axis_names[i],
axis_ids[i],
generic_axis_get_state<s32>,
@ -811,7 +814,7 @@ void xinput_joystick_device::configure()
{
if (hat_caps[i])
{
device()->add_item(
device.add_item(
hat_names[i],
input_item_id(ITEM_ID_HAT1UP + i), // matches up/down/left/right order
generic_button_get_state<u8>,
@ -837,7 +840,7 @@ void xinput_joystick_device::configure()
auto const [offset, supported] = button_caps[i];
if (supported)
{
device()->add_item(
device.add_item(
button_names[i],
button_id++,
generic_button_get_state<u8>,
@ -848,7 +851,7 @@ void xinput_joystick_device::configure()
// add start/back
if (has_button(XINPUT_GAMEPAD_START))
{
device()->add_item(
device.add_item(
"Start",
ITEM_ID_START,
generic_button_get_state<u8>,
@ -856,7 +859,7 @@ void xinput_joystick_device::configure()
}
if (has_button(XINPUT_GAMEPAD_BACK))
{
device()->add_item(
device.add_item(
"Back",
ITEM_ID_SELECT,
generic_button_get_state<u8>,
@ -870,7 +873,7 @@ void xinput_joystick_device::configure()
{
if (i ? has_trigger_right() : has_trigger_left())
{
device()->add_item(
device.add_item(
axis_names[4 + i],
axis_ids[4 + i],
generic_axis_get_state<s32>,
@ -890,18 +893,16 @@ class xinput_guitar_device : public xinput_device_base
{
public:
xinput_guitar_device(
running_machine &machine,
std::string &&name,
std::string &&id,
input_module &module,
u32 player,
XINPUT_CAPABILITIES const &caps,
std::shared_ptr<xinput_api_helper> const &helper);
xinput_api_helper const &helper);
virtual void poll() override;
virtual void reset() override;
virtual void configure() override;
virtual void configure(input_device &device) override;
private:
static inline constexpr USHORT SWITCH_BITS[] =
@ -965,14 +966,13 @@ private:
xinput_guitar_device::xinput_guitar_device(
running_machine &machine,
std::string &&name,
std::string &&id,
input_module &module,
u32 player,
XINPUT_CAPABILITIES const &caps,
std::shared_ptr<xinput_api_helper> const &helper) :
xinput_device_base(machine, std::move(name), std::move(id), module, player, caps, helper)
xinput_api_helper const &helper) :
xinput_device_base(std::move(name), std::move(id), module, player, caps, helper)
{
std::fill(std::begin(m_switches), std::end(m_switches), 0);
std::fill(std::begin(m_axes), std::end(m_axes), 0);
@ -1012,7 +1012,7 @@ void xinput_guitar_device::reset()
}
void xinput_guitar_device::configure()
void xinput_guitar_device::configure(input_device &device)
{
// TODO: does subtype 0x06 indicate digital neck orientation sensor or lack of three-axis accelerometer?
@ -1030,7 +1030,7 @@ void xinput_guitar_device::configure()
auto const [item, name, supported] = axis_caps[i];
if (supported)
{
device()->add_item(
device.add_item(
name,
item,
generic_axis_get_state<s32>,
@ -1043,7 +1043,7 @@ void xinput_guitar_device::configure()
{
if (has_button(SWITCH_BITS[SWITCH_DPAD_UP + i]))
{
device()->add_item(
device.add_item(
HAT_NAMES_GUITAR[i],
input_item_id(ITEM_ID_HAT1UP + i), // matches up/down/left/right order
generic_button_get_state<u8>,
@ -1057,7 +1057,7 @@ void xinput_guitar_device::configure()
{
if (has_button(SWITCH_BITS[i]))
{
device()->add_item(
device.add_item(
BUTTON_NAMES_GUITAR[i],
button_id++,
generic_button_get_state<u8>,
@ -1068,7 +1068,7 @@ void xinput_guitar_device::configure()
// add start/back
if (has_button(XINPUT_GAMEPAD_START))
{
device()->add_item(
device.add_item(
"Start",
ITEM_ID_START,
generic_button_get_state<u8>,
@ -1076,7 +1076,7 @@ void xinput_guitar_device::configure()
}
if (has_button(XINPUT_GAMEPAD_BACK))
{
device()->add_item(
device.add_item(
"Back",
ITEM_ID_SELECT,
generic_button_get_state<u8>,
@ -1094,18 +1094,16 @@ class xinput_drumkit_device : public xinput_device_base
{
public:
xinput_drumkit_device(
running_machine &machine,
std::string &&name,
std::string &&id,
input_module &module,
u32 player,
XINPUT_CAPABILITIES const &caps,
std::shared_ptr<xinput_api_helper> const &helper);
xinput_api_helper const &helper);
virtual void poll() override;
virtual void reset() override;
virtual void configure() override;
virtual void configure(input_device &device) override;
private:
static inline constexpr USHORT SWITCH_BITS[] =
@ -1166,14 +1164,13 @@ private:
xinput_drumkit_device::xinput_drumkit_device(
running_machine &machine,
std::string &&name,
std::string &&id,
input_module &module,
u32 player,
XINPUT_CAPABILITIES const &caps,
std::shared_ptr<xinput_api_helper> const &helper) :
xinput_device_base(machine, std::move(name), std::move(id), module, player, caps, helper)
xinput_api_helper const &helper) :
xinput_device_base(std::move(name), std::move(id), module, player, caps, helper)
{
std::fill(std::begin(m_switches), std::end(m_switches), 0);
std::fill(std::begin(m_axes), std::end(m_axes), 0);
@ -1208,7 +1205,7 @@ void xinput_drumkit_device::reset()
}
void xinput_drumkit_device::configure()
void xinput_drumkit_device::configure(input_device &device)
{
// add axes
std::tuple<input_item_id, char const *, bool> const axis_caps[]{
@ -1223,7 +1220,7 @@ void xinput_drumkit_device::configure()
auto const [item, name, supported] = axis_caps[i];
if (supported)
{
device()->add_item(
device.add_item(
name,
item,
generic_axis_get_state<s32>,
@ -1236,7 +1233,7 @@ void xinput_drumkit_device::configure()
{
if (has_button(SWITCH_BITS[SWITCH_DPAD_UP + i]))
{
device()->add_item(
device.add_item(
HAT_NAMES_GAMEPAD[i],
input_item_id(ITEM_ID_HAT1UP + i), // matches up/down/left/right order
generic_button_get_state<u8>,
@ -1250,7 +1247,7 @@ void xinput_drumkit_device::configure()
{
if (has_button(SWITCH_BITS[i]))
{
device()->add_item(
device.add_item(
BUTTON_NAMES_DRUMKIT[i],
button_id++,
generic_button_get_state<u8>,
@ -1261,7 +1258,7 @@ void xinput_drumkit_device::configure()
// add start/back
if (has_button(XINPUT_GAMEPAD_START))
{
device()->add_item(
device.add_item(
"Start",
ITEM_ID_START,
generic_button_get_state<u8>,
@ -1269,7 +1266,7 @@ void xinput_drumkit_device::configure()
}
if (has_button(XINPUT_GAMEPAD_BACK))
{
device()->add_item(
device.add_item(
"Back",
ITEM_ID_SELECT,
generic_button_get_state<u8>,
@ -1287,18 +1284,16 @@ class xinput_turntable_device : public xinput_device_base
{
public:
xinput_turntable_device(
running_machine &machine,
std::string &&name,
std::string &&id,
input_module &module,
u32 player,
XINPUT_CAPABILITIES const &caps,
std::shared_ptr<xinput_api_helper> const &helper);
xinput_api_helper const &helper);
virtual void poll() override;
virtual void reset() override;
virtual void configure() override;
virtual void configure(input_device &device) override;
private:
static inline constexpr USHORT SWITCH_BITS[] =
@ -1361,14 +1356,13 @@ private:
xinput_turntable_device::xinput_turntable_device(
running_machine &machine,
std::string &&name,
std::string &&id,
input_module &module,
u32 player,
XINPUT_CAPABILITIES const &caps,
std::shared_ptr<xinput_api_helper> const &helper) :
xinput_device_base(machine, std::move(name), std::move(id), module, player, caps, helper),
xinput_api_helper const &helper) :
xinput_device_base(std::move(name), std::move(id), module, player, caps, helper),
m_prev_effect(0)
{
std::fill(std::begin(m_switches), std::end(m_switches), 0);
@ -1423,20 +1417,20 @@ void xinput_turntable_device::reset()
}
void xinput_turntable_device::configure()
void xinput_turntable_device::configure(input_device &device)
{
// add axes
device()->add_item(
device.add_item(
"Turntable",
ITEM_ID_ADD_RELATIVE1,
generic_axis_get_state<s32>,
&m_axes[AXIS_TURNTABLE]);
device()->add_item(
device.add_item(
"Effect",
ITEM_ID_ADD_RELATIVE2,
generic_axis_get_state<s32>,
&m_axes[AXIS_EFFECT]);
device()->add_item(
device.add_item(
"Crossfade",
ITEM_ID_XAXIS,
generic_axis_get_state<s32>,
@ -1447,7 +1441,7 @@ void xinput_turntable_device::configure()
{
if (has_button(SWITCH_BITS[SWITCH_DPAD_UP + i]))
{
device()->add_item(
device.add_item(
HAT_NAMES_GAMEPAD[i],
input_item_id(ITEM_ID_HAT1UP + i), // matches up/down/left/right order
generic_button_get_state<u8>,
@ -1461,24 +1455,24 @@ void xinput_turntable_device::configure()
{
if (has_button(SWITCH_BITS[i]))
{
device()->add_item(
device.add_item(
BUTTON_NAMES_KEYBOARD[i],
button_id++,
generic_button_get_state<u8>,
&m_switches[SWITCH_A + i]);
}
}
device()->add_item(
device.add_item(
"Green",
button_id++,
generic_button_get_state<u8>,
&m_switches[SWITCH_GREEN]);
device()->add_item(
device.add_item(
"Red",
button_id++,
generic_button_get_state<u8>,
&m_switches[SWITCH_RED]);
device()->add_item(
device.add_item(
"Blue",
button_id++,
generic_button_get_state<u8>,
@ -1487,7 +1481,7 @@ void xinput_turntable_device::configure()
// add start/back
if (has_button(XINPUT_GAMEPAD_START))
{
device()->add_item(
device.add_item(
"Start",
ITEM_ID_START,
generic_button_get_state<u8>,
@ -1495,7 +1489,7 @@ void xinput_turntable_device::configure()
}
if (has_button(XINPUT_GAMEPAD_BACK))
{
device()->add_item(
device.add_item(
"Back",
ITEM_ID_SELECT,
generic_button_get_state<u8>,
@ -1513,18 +1507,16 @@ class xinput_keyboard_device : public xinput_device_base
{
public:
xinput_keyboard_device(
running_machine &machine,
std::string &&name,
std::string &&id,
input_module &module,
u32 player,
XINPUT_CAPABILITIES const &caps,
std::shared_ptr<xinput_api_helper> const &helper);
xinput_api_helper const &helper);
virtual void poll() override;
virtual void reset() override;
virtual void configure() override;
virtual void configure(input_device &device) override;
private:
static inline constexpr USHORT SWITCH_BITS[] =
@ -1584,14 +1576,13 @@ private:
xinput_keyboard_device::xinput_keyboard_device(
running_machine &machine,
std::string &&name,
std::string &&id,
input_module &module,
u32 player,
XINPUT_CAPABILITIES const &caps,
std::shared_ptr<xinput_api_helper> const &helper) :
xinput_device_base(machine, std::move(name), std::move(id), module, player, caps, helper)
xinput_api_helper const &helper) :
xinput_device_base(std::move(name), std::move(id), module, player, caps, helper)
{
std::fill(std::begin(m_switches), std::end(m_switches), 0);
std::fill(std::begin(m_axes), std::end(m_axes), 0);
@ -1634,15 +1625,15 @@ void xinput_keyboard_device::reset()
}
void xinput_keyboard_device::configure()
void xinput_keyboard_device::configure(input_device &device)
{
// add axes
device()->add_item(
device.add_item(
"Velocity",
ITEM_ID_SLIDER1,
generic_axis_get_state<s32>,
&m_axes[AXIS_VELOCITY]);
device()->add_item(
device.add_item(
"Pedal",
ITEM_ID_SLIDER2,
generic_axis_get_state<s32>,
@ -1653,7 +1644,7 @@ void xinput_keyboard_device::configure()
{
if (has_button(SWITCH_BITS[SWITCH_DPAD_UP + i]))
{
device()->add_item(
device.add_item(
HAT_NAMES_GAMEPAD[i],
input_item_id(ITEM_ID_HAT1UP + i), // matches up/down/left/right order
generic_button_get_state<u8>,
@ -1667,7 +1658,7 @@ void xinput_keyboard_device::configure()
{
if (has_button(SWITCH_BITS[i]))
{
device()->add_item(
device.add_item(
BUTTON_NAMES_KEYBOARD[i],
button_id++,
generic_button_get_state<u8>,
@ -1680,7 +1671,7 @@ void xinput_keyboard_device::configure()
"C %d", "C# %d", "D %d", "D# %d", "E %d", "F %d", "F# %d", "G %d", "G# %d", "A %d", "A# %d", "B %d" };
for (unsigned i = 0; (SWITCH_C3 - SWITCH_C1) >= i; ++i)
{
device()->add_item(
device.add_item(
util::string_format(key_formats[i % 12], (i / 12) + 1),
(ITEM_ID_BUTTON32 >= button_id) ? button_id++ : ITEM_ID_OTHER_SWITCH,
generic_button_get_state<u8>,
@ -1690,7 +1681,7 @@ void xinput_keyboard_device::configure()
// add start/back
if (has_button(XINPUT_GAMEPAD_START))
{
device()->add_item(
device.add_item(
"Start",
ITEM_ID_START,
generic_button_get_state<u8>,
@ -1698,7 +1689,7 @@ void xinput_keyboard_device::configure()
}
if (has_button(XINPUT_GAMEPAD_BACK))
{
device()->add_item(
device.add_item(
"Back",
ITEM_ID_SELECT,
generic_button_get_state<u8>,
@ -1712,22 +1703,24 @@ void xinput_keyboard_device::configure()
// XInput joystick module
//============================================================
class xinput_joystick_module : public wininput_module
class xinput_joystick_module : public input_module_impl<device_info, osd_common_t>
{
public:
xinput_joystick_module() : wininput_module(OSD_JOYSTICKINPUT_PROVIDER, "xinput")
xinput_joystick_module() : input_module_impl<device_info, osd_common_t>(OSD_JOYSTICKINPUT_PROVIDER, "xinput")
{
}
int init(const osd_options &options) override
virtual int init(osd_interface &osd, const osd_options &options) override
{
int status;
// Call the base
int status = wininput_module::init(options);
status = input_module_impl<device_info, osd_common_t>::init(osd, options);
if (status != 0)
return status;
// Create and initialize our helper
m_xinput_helper = std::make_shared<xinput_api_helper>();
m_xinput_helper = std::make_unique<xinput_api_helper>();
status = m_xinput_helper->initialize();
if (status != 0)
{
@ -1738,22 +1731,29 @@ public:
return 0;
}
protected:
virtual void input_init(running_machine &machine) override
{
input_module_impl<device_info, osd_common_t>::input_init(machine);
// Loop through each gamepad to determine if they are connected
for (UINT i = 0; i < XUSER_MAX_COUNT; i++)
{
XINPUT_STATE state{ 0 };
// allocate and link in a new device
if (m_xinput_helper->xinput_get_state(i, &state) == ERROR_SUCCESS)
m_xinput_helper->create_xinput_device(machine, i, *this);
auto devinfo = m_xinput_helper->create_xinput_device(i, *this);
if (devinfo)
add_device(DEVICE_CLASS_JOYSTICK, std::move(devinfo));
}
}
virtual void exit() override
{
input_module_impl<device_info, osd_common_t>::exit();
m_xinput_helper.reset();
}
private:
std::shared_ptr<xinput_api_helper> m_xinput_helper;
std::unique_ptr<xinput_api_helper> m_xinput_helper;
};
} // anonymous namespace
@ -1781,9 +1781,14 @@ int xinput_api_helper::initialize()
// create_xinput_device
//============================================================
device_info *xinput_api_helper::create_xinput_device(running_machine &machine, UINT index, wininput_module &module)
std::unique_ptr<device_info> xinput_api_helper::create_xinput_device(
UINT index,
input_module_base &module)
{
// If we can't get the capabilities skip this device
XINPUT_STATE state{ 0 };
if (xinput_get_state(index, &state) != ERROR_SUCCESS)
return nullptr;
XINPUT_CAPABILITIES caps{ 0 };
if (FAILED(xinput_get_capabilities(index, 0, &caps)))
return nullptr;
@ -1791,8 +1796,7 @@ device_info *xinput_api_helper::create_xinput_device(running_machine &machine, U
char device_name[16];
snprintf(device_name, sizeof(device_name), "XInput Player %u", index + 1);
// allocate the device object
xinput_device_base *devinfo;
// allocate specialised device objects
switch (caps.Type)
{
case XINPUT_DEVTYPE_GAMEPAD:
@ -1801,81 +1805,63 @@ device_info *xinput_api_helper::create_xinput_device(running_machine &machine, U
case XINPUT_DEVSUBTYPE_GUITAR:
case XINPUT_DEVSUBTYPE_GUITAR_ALTERNATE:
case XINPUT_DEVSUBTYPE_GUITAR_BASS:
devinfo = &module.devicelist().create_device<xinput_guitar_device>(
machine,
return std::make_unique<xinput_guitar_device>(
device_name,
device_name,
module,
index,
caps,
shared_from_this());
*this);
break;
case XINPUT_DEVSUBTYPE_DRUM_KIT:
devinfo = &module.devicelist().create_device<xinput_drumkit_device>(
machine,
return std::make_unique<xinput_drumkit_device>(
device_name,
device_name,
module,
index,
caps,
shared_from_this());
*this);
break;
case 0x0f:
devinfo = &module.devicelist().create_device<xinput_keyboard_device>(
machine,
return std::make_unique<xinput_keyboard_device>(
device_name,
device_name,
module,
index,
caps,
shared_from_this());
*this);
break;
case 0x17:
devinfo = &module.devicelist().create_device<xinput_turntable_device>(
machine,
return std::make_unique<xinput_turntable_device>(
device_name,
device_name,
module,
index,
caps,
shared_from_this());
*this);
break;
default:
devinfo = &module.devicelist().create_device<xinput_joystick_device>(
machine,
device_name,
device_name,
module,
index,
caps,
shared_from_this());
}
break;
default:
devinfo = &module.devicelist().create_device<xinput_joystick_device>(
machine,
device_name,
device_name,
module,
index,
caps,
shared_from_this());
}
// configure each controller to add buttons, axes, etc.
devinfo->configure();
return devinfo;
// create default general-purpose device
return std::make_unique<xinput_joystick_device>(
device_name,
device_name,
module,
index,
caps,
*this);
}
} // namespace osd
#else // defined(OSD_WINDOWS)
#else // defined(OSD_WINDOWS) || defined(SDLMAME_WIN32)
#include "input_module.h"
namespace osd { MODULE_NOT_SUPPORTED(xinput_joystick_module, OSD_JOYSTICKINPUT_PROVIDER, "xinput") }
namespace osd { namespace { MODULE_NOT_SUPPORTED(xinput_joystick_module, OSD_JOYSTICKINPUT_PROVIDER, "xinput") } }
#endif // defined(OSD_WINDOWS)
#endif // defined(OSD_WINDOWS) || defined(SDLMAME_WIN32)
MODULE_DEFINITION(JOYSTICKINPUT_XINPUT, osd::xinput_joystick_module)

View File

@ -1,26 +1,29 @@
// license:BSD-3-Clause
// copyright-holders:Brad Hughes, Vas Crabb
#ifndef MAME_OSD_INPUT_INPUT_XINPUT_H
#define MAME_OSD_INPUT_INPUT_XINPUT_H
#pragma once
#include "input_windows.h"
#include "input_common.h"
#include "modules/lib/osdlib.h"
#include <xinput.h>
#include <memory>
#include <xinput.h>
namespace osd {
class xinput_api_helper : public std::enable_shared_from_this<xinput_api_helper>
class xinput_api_helper
{
public:
xinput_api_helper() { }
int initialize();
device_info *create_xinput_device(running_machine &machine, UINT index, wininput_module &module);
std::unique_ptr<device_info> create_xinput_device(UINT index, input_module_base &module);
DWORD xinput_get_state(DWORD dwUserindex, XINPUT_STATE *pState) const
{

View File

@ -169,6 +169,9 @@ const options_entry osd_options::s_option_entries[] =
{ nullptr, nullptr, core_options::option_type::HEADER, "OSD MIDI OPTIONS" },
{ OSDOPTION_MIDI_PROVIDER, OSDOPTVAL_AUTO, core_options::option_type::STRING, "MIDI I/O method: " },
{ nullptr, nullptr, core_options::option_type::HEADER, "OSD EMULATED NETWORKING OPTIONS" },
{ OSDOPTION_NETWORK_PROVIDER, OSDOPTVAL_AUTO, core_options::option_type::STRING, "Emulated networking provider: " },
{ nullptr, nullptr, core_options::option_type::HEADER, "BGFX POST-PROCESSING OPTIONS" },
{ OSDOPTION_BGFX_PATH, "bgfx", core_options::option_type::PATH, "path to BGFX-related files" },
{ OSDOPTION_BGFX_BACKEND, "auto", core_options::option_type::STRING, "BGFX backend to use (d3d9, d3d11, d3d12, metal, opengl, gles, vulkan)" },
@ -312,6 +315,7 @@ void osd_common_t::register_options()
update_option(OSD_JOYSTICKINPUT_PROVIDER, m_mod_man.get_module_names(OSD_JOYSTICKINPUT_PROVIDER));
update_option(OSD_SOUND_PROVIDER, m_mod_man.get_module_names(OSD_SOUND_PROVIDER));
update_option(OSD_MIDI_PROVIDER, m_mod_man.get_module_names(OSD_MIDI_PROVIDER));
update_option(OSD_NETDEV_PROVIDER, m_mod_man.get_module_names(OSD_NETDEV_PROVIDER));
update_option(OSD_DEBUG_PROVIDER, m_mod_man.get_module_names(OSD_DEBUG_PROVIDER));
update_option(OSD_OUTPUT_PROVIDER, m_mod_man.get_module_names(OSD_OUTPUT_PROVIDER));
@ -575,7 +579,7 @@ bool osd_common_t::execute_command(const char *command)
if (om->probe())
{
om->init(options());
om->init(*this, options());
osd_list_network_adapters();
om->exit();
}
@ -589,7 +593,7 @@ bool osd_common_t::execute_command(const char *command)
if (om->probe())
{
om->init(options());
om->init(*this, options());
pm->list_midi_devices();
om->exit();
}
@ -610,7 +614,7 @@ void osd_common_t::init_subsystems()
// monitors have to be initialized before video init
m_monitor_module = select_module_options<monitor_module *>(options(), OSD_MONITOR_PROVIDER);
assert(m_monitor_module != nullptr);
m_monitor_module->init(options());
m_monitor_module->init(*this, options());
if (!video_init())
{
@ -641,12 +645,9 @@ void osd_common_t::init_subsystems()
m_output->set_machine(&machine());
machine().output().set_global_notifier(output_notifier_callback, this);
m_mod_man.init(options());
m_mod_man.init(*this, options());
input_init();
// we need pause callbacks
machine().add_notifier(MACHINE_NOTIFY_PAUSE, machine_notify_delegate(&osd_common_t::input_pause, this));
machine().add_notifier(MACHINE_NOTIFY_RESUME, machine_notify_delegate(&osd_common_t::input_resume, this));
}
bool osd_common_t::video_init()
@ -677,22 +678,6 @@ bool osd_common_t::input_init()
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();
}
void osd_common_t::exit_subsystems()
{
video_exit();

View File

@ -89,6 +89,8 @@
#define OSDOPTION_MIDI_PROVIDER "midiprovider"
#define OSDOPTION_NETWORK_PROVIDER "networkprovider"
#define OSDOPTION_BGFX_PATH "bgfx_path"
#define OSDOPTION_BGFX_BACKEND "bgfx_backend"
#define OSDOPTION_BGFX_DEBUG "bgfx_debug"
@ -251,8 +253,6 @@ public:
virtual void video_register();
virtual bool window_init();
virtual void input_resume();
virtual void exit_subsystems();
virtual void video_exit();
virtual void window_exit();
@ -270,11 +270,13 @@ public:
void notify(const char *outname, int32_t value) const { m_output->notify(outname, value); }
static std::list<std::shared_ptr<osd_window>> s_window_list;
virtual void process_events() = 0;
virtual bool has_focus() const = 0;
static std::list<std::shared_ptr<osd_window> > s_window_list;
protected:
virtual bool input_init();
virtual void input_pause();
virtual void build_slider_list() { }
virtual void update_slider_list() { }

View File

@ -10,7 +10,6 @@
#pragma once
#include "osdepend.h"
#include "modules/osdmodule.h"
#include <memory>
@ -24,7 +23,8 @@
class midi_module
{
public:
virtual ~midi_module() { }
virtual ~midi_module() = default;
// specific routines
virtual std::unique_ptr<osd_midi_device> create_midi_device() = 0;

View File

@ -8,10 +8,11 @@
***************************************************************************/
#include "osdcore.h"
#include "modules/osdmodule.h"
#include "midi_module.h"
#include "modules/osdmodule.h"
#include "osdcore.h"
#include <memory>
@ -36,7 +37,7 @@ class none_module : public osd_module, public midi_module
public:
none_module() : osd_module(OSD_MIDI_PROVIDER, "none"), midi_module() { }
virtual int init(const osd_options &options) override { return 0; }
virtual int init(osd_interface &osd, const osd_options &options) override { return 0; }
virtual void exit() override { }
virtual std::unique_ptr<osd_midi_device> create_midi_device() override;

View File

@ -33,7 +33,7 @@ public:
}
virtual ~pm_module() { }
virtual int init(const osd_options &options)override;
virtual int init(osd_interface &osd, const osd_options &options) override;
virtual void exit() override;
virtual std::unique_ptr<osd_midi_device> create_midi_device() override;
@ -73,7 +73,7 @@ std::unique_ptr<osd_midi_device> pm_module::create_midi_device()
}
int pm_module::init(const osd_options &options)
int pm_module::init(osd_interface &osd, const osd_options &options)
{
Pm_Initialize();
return 0;

View File

@ -96,7 +96,7 @@ float monitor_module_base::get_aspect(const char* defdata, const char* data, int
return float(num) / float(den);
}
int monitor_module_base::init(const osd_options& options)
int monitor_module_base::init(osd_interface &osd, const osd_options &options)
{
if (!m_initialized)
{

View File

@ -4,11 +4,17 @@
* monitor_common.h
*
*/
#ifndef __MONITOR_COMMON_H__
#define __MONITOR_COMMON_H__
#ifndef MAME_OSD_MONITOR_MONITOR_COMMON_H
#define MAME_OSD_MONITOR_MONITOR_COMMON_H
#pragma once
#include "monitor_module.h"
#include <cstdint>
#include <map>
#include <memory>
//============================================================
// monitor_module_base
@ -16,32 +22,30 @@
class monitor_module_base : public monitor_module
{
private:
std::map<std::uint64_t, std::shared_ptr<osd_monitor_info>> m_monitor_index;
protected:
bool m_initialized;
public:
monitor_module_base(const char* type, const char* name)
: monitor_module(type, name),
m_initialized(false)
monitor_module_base(const char* type, const char* name) :
monitor_module(type, name),
m_initialized(false)
{
}
std::shared_ptr<osd_monitor_info> pick_monitor(osd_options& options, int index) override;
std::shared_ptr<osd_monitor_info> monitor_from_handle(std::uint64_t handle) override;
int init(const osd_options& options) override;
int init(osd_interface &osd, const osd_options& options) override;
void exit() override;
protected:
virtual int init_internal(const osd_options& options) = 0;
virtual int init_internal(const osd_options &options) = 0;
void add_monitor(std::shared_ptr<osd_monitor_info> monitor);
bool m_initialized;
private:
std::shared_ptr<osd_monitor_info> pick_monitor_internal(osd_options& options, int index);
static float get_aspect(const char *defdata, const char *data, int report_error);
std::map<std::uint64_t, std::shared_ptr<osd_monitor_info> > m_monitor_index;
std::shared_ptr<osd_monitor_info> pick_monitor_internal(osd_options& options, int index);
};
#endif
#endif // MAME_OSD_MONITOR_MONITOR_COMMON_H

View File

@ -10,14 +10,19 @@
#if defined(OSD_SDL)
#include <algorithm>
#include <SDL2/SDL.h>
#include "modules/osdwindow.h"
#include "monitor_common.h"
#include "modules/lib/osdobj_common.h"
#include "modules/osdwindow.h"
#include "osdcore.h"
#include "window.h"
#include <SDL2/SDL.h>
#include <algorithm>
inline osd_rect SDL_Rect_to_osd_rect(const SDL_Rect &r)
{
return osd_rect(r.x, r.y, r.w, r.h);

View File

@ -4,25 +4,23 @@
* netdev_module.h
*
*/
#ifndef MAME_OSD_NETDEV_NETDEV_MODULE_H
#define MAME_OSD_NETDEV_NETDEV_MODULE_H
#ifndef NETDEV_MODULE_H_
#define NETDEV_MODULE_H_
#pragma once
#include "osdepend.h"
#include "modules/osdmodule.h"
//============================================================
// CONSTANTS
//============================================================
#define OSD_NETDEV_PROVIDER "netdevprovider"
#define OSD_NETDEV_PROVIDER "networkprovider"
class netdev_module
{
public:
virtual ~netdev_module() { }
virtual ~netdev_module() = default;
// no specific routines below ... may change
};
#endif /* NETDEV_MODULE_H_ */
#endif // MAME_OSD_NETDEV_NETDEV_MODULE_H

View File

@ -4,20 +4,28 @@
* none.c
*
*/
#include "netdev_module.h"
#include "modules/osdmodule.h"
namespace osd {
namespace {
class netdev_none : public osd_module, public netdev_module
{
public:
netdev_none()
: osd_module(OSD_NETDEV_PROVIDER, "none"), netdev_module()
netdev_none() : osd_module(OSD_NETDEV_PROVIDER, "none"), netdev_module()
{
}
virtual ~netdev_none() { }
virtual int init(const osd_options &options) override { return 0; }
virtual int init(osd_interface &osd, const osd_options &options) override { return 0; }
};
MODULE_DEFINITION(NETDEV_NONE, netdev_none)
} // anonymous namespace
} // namespace osd
MODULE_DEFINITION(NETDEV_NONE, osd::netdev_none)

View File

@ -1,13 +1,15 @@
// license:BSD-3-Clause
// copyright-holders:Carl
#include "netdev_module.h"
#include "modules/osdmodule.h"
#if defined(OSD_NET_USE_PCAP)
#include "emu.h"
#include "dinetwork.h"
#include "osdnet.h"
#include "netdev_module.h"
#include "modules/osdmodule.h"
#include "modules/lib/osdlib.h"
#if defined(SDLMAME_WIN32) || defined(OSD_WINDOWS)
@ -26,6 +28,10 @@
#include <pcap.h>
namespace osd {
namespace {
// Typedefs for dynamically loaded functions
typedef int (*pcap_findalldevs_fn)(pcap_if_t **, char *);
typedef pcap_t *(*pcap_open_live_fn)(const char *, int, int, int, char *);
@ -49,7 +55,7 @@ public:
virtual ~pcap_module() { }
virtual int init(const osd_options &options) override;
virtual int init(osd_interface &osd, const osd_options &options) override;
virtual void exit() override;
virtual bool probe() override
@ -255,7 +261,7 @@ static CREATE_NETDEV(create_pcap)
return dynamic_cast<osd_netdev *>(dev);
}
int pcap_module::init(const osd_options &options)
int pcap_module::init(osd_interface &osd, const osd_options &options)
{
pcap_if_t *devs;
char errbuf[PCAP_ERRBUF_SIZE];
@ -286,12 +292,15 @@ void pcap_module::exit()
clear_netdev();
}
#else
#include "modules/osdmodule.h"
#include "netdev_module.h"
} // anonymous namespace
} // namespace osd
#else
namespace osd { namespace { MODULE_NOT_SUPPORTED(pcap_module, OSD_NETDEV_PROVIDER, "pcap") } }
MODULE_NOT_SUPPORTED(pcap_module, OSD_NETDEV_PROVIDER, "pcap")
#endif
MODULE_DEFINITION(NETDEV_PCAP, pcap_module)
MODULE_DEFINITION(NETDEV_PCAP, osd::pcap_module)

View File

@ -1,5 +1,9 @@
// license:BSD-3-Clause
// copyright-holders:Carl
#include "netdev_module.h"
#include "modules/osdmodule.h"
#if defined(OSD_NET_USE_TAPTUN)
#if defined(_WIN32)
@ -16,8 +20,6 @@
#include "emu.h"
#include "dinetwork.h"
#include "osdnet.h"
#include "modules/osdmodule.h"
#include "netdev_module.h"
#include "unicode.h"
#ifdef __linux__
@ -32,6 +34,10 @@
#define PRODUCT_TAP_WIN_COMPONENT_ID "tap0901"
#endif
namespace osd {
namespace {
// Ethernet minimum frame length
static constexpr int ETHERNET_MIN_FRAME = 64;
@ -44,7 +50,7 @@ public:
}
virtual ~taptun_module() { }
virtual int init(const osd_options &options);
virtual int init(osd_interface &osd, const osd_options &options);
virtual void exit();
virtual bool probe() { return true; }
@ -343,7 +349,7 @@ static CREATE_NETDEV(create_tap)
return dynamic_cast<osd_netdev *>(dev);
}
int taptun_module::init(const osd_options &options)
int taptun_module::init(osd_interface &osd, const osd_options &options)
{
#if defined(_WIN32)
for (std::wstring &id : get_tap_adapters())
@ -359,13 +365,16 @@ void taptun_module::exit()
clear_netdev();
}
} // anonymous namespace
} // namespace osd
#else
#include "modules/osdmodule.h"
#include "netdev_module.h"
MODULE_NOT_SUPPORTED(taptun_module, OSD_NETDEV_PROVIDER, "taptun")
namespace osd { namespace { MODULE_NOT_SUPPORTED(taptun_module, OSD_NETDEV_PROVIDER, "taptun") } }
#endif
MODULE_DEFINITION(NETDEV_TAPTUN, taptun_module)
MODULE_DEFINITION(NETDEV_TAPTUN, osd::taptun_module)

View File

@ -58,10 +58,10 @@ osd_module *osd_module_manager::select_module(const char *type, const char *name
return m;
}
void osd_module_manager::init(const osd_options &options)
void osd_module_manager::init(osd_interface &osd, const osd_options &options)
{
for (osd_module &m : m_selected)
m.init(options);
m.init(osd, options);
}
void osd_module_manager::exit()

View File

@ -23,6 +23,7 @@
// TYPE DEFINITIONS
//============================================================
class osd_interface;
class osd_options;
@ -40,7 +41,7 @@ public:
virtual bool probe() { return true; }
virtual int init(const osd_options &options) = 0;
virtual int init(osd_interface &osd, const osd_options &options) = 0;
virtual void exit() { }
protected:
@ -86,7 +87,7 @@ public:
std::vector<std::string_view> get_module_names(const char *type) const;
void init(const osd_options &options);
void init(osd_interface &osd, const osd_options &options);
void exit();
@ -109,7 +110,7 @@ private:
public: \
mod_class () : osd_module(mod_type, mod_name) { } \
virtual ~mod_class() { } \
virtual int init(const osd_options &options) override { return -1; } \
virtual int init(osd_interface &osd, const osd_options &options) override { return -1; } \
virtual bool probe() override { return false; } \
};

View File

@ -8,8 +8,10 @@
#include "emu.h"
#include "osdwindow.h"
#include "modules/lib/osdobj_common.h"
#include "modules/monitor/monitor_module.h"
// osd/modules
#include "lib/osdobj_common.h"
#include "monitor/monitor_module.h"
#include "render/drawnone.h"
#include "render/drawbgfx.h"
@ -24,6 +26,10 @@
#include "render/drawsdl.h"
#endif
// emu
#include "main.h"
osd_window::osd_window(running_machine &machine, int index, std::shared_ptr<osd_monitor_info> monitor, const osd_window_config &config) :
#ifdef OSD_WINDOWS
m_dc(nullptr), m_resize_state(0),

View File

@ -20,11 +20,6 @@
#include <mmsystem.h>
#endif
#ifdef OSD_SDL
// forward declaration
struct SDL_Window;
#endif
//============================================================
// TYPE DEFINITIONS
//============================================================
@ -114,10 +109,6 @@ public:
virtual void update() = 0;
virtual void complete_destroy() = 0;
#if defined(OSD_WINDOWS)
virtual bool win_has_menu() = 0;
#endif
private:
void set_starting_view(int index, const char *defview, const char *view);

View File

@ -9,20 +9,23 @@
*******************************************************************c********/
#include "output_module.h"
#include "modules/osdmodule.h"
#include "modules/osdmodule.h"
#include "osdcore.h"
namespace osd {
namespace {
class output_console : public osd_module, public output_module
{
public:
output_console()
: osd_module(OSD_OUTPUT_PROVIDER, "console"), output_module()
output_console() : osd_module(OSD_OUTPUT_PROVIDER, "console")
{
}
virtual ~output_console() { }
virtual int init(const osd_options &options) override { return 0; }
virtual int init(osd_interface &osd, const osd_options &options) override { return 0; }
virtual void exit() override { }
// output_module
@ -31,4 +34,9 @@ public:
};
MODULE_DEFINITION(OUTPUT_CONSOLE, output_console)
} // anonymous namespace
} // namespace osd
MODULE_DEFINITION(OUTPUT_CONSOLE, osd::output_console)

View File

@ -9,8 +9,8 @@
***************************************************************************/
#include "output_module.h"
#include "modules/osdmodule.h"
#include "modules/lib/osdobj_common.h"
#include "emu.h"
@ -19,181 +19,182 @@
#define ASIO_HAS_EPOLL
#endif
#include <thread>
#include <set>
#include "asio.h"
#include <memory>
#include <set>
#include <thread>
namespace osd {
namespace {
class output_client
{
public:
virtual ~output_client() {}
virtual void deliver(std::string &msg) = 0;
virtual ~output_client() { }
virtual void deliver(std::string &msg) = 0;
};
using output_client_ptr = std::shared_ptr<output_client>;
using client_set = std::set<output_client_ptr>;
class output_session : public output_client,
public std::enable_shared_from_this<output_session>
class output_session : public output_client, public std::enable_shared_from_this<output_session>
{
public:
output_session(asio::ip::tcp::socket socket, client_set *clients) :
m_socket(std::move(socket)),
m_clients(clients)
{
}
output_session(asio::ip::tcp::socket socket, client_set *clients) :
m_socket(std::move(socket)),
m_clients(clients)
{
}
void start(running_machine &machine)
{
m_machine = &machine;
m_clients->insert(shared_from_this());
// now send "mame_start = rom" to the newly connected client
std::snprintf(m_data, max_length, "mame_start = %s\r", machine.system().name);
do_write(std::strlen(m_data));
do_read();
}
void start(running_machine &machine)
{
m_machine = &machine;
m_clients->insert(shared_from_this());
// now send "mame_start = rom" to the newly connected client
std::snprintf(m_data, max_length, "mame_start = %s\r", machine.system().name);
do_write(std::strlen(m_data));
do_read();
}
private:
void deliver(std::string &msg)
{
std::strncpy(m_data, msg.c_str(), max_length);
do_write(msg.size());
}
void handle_message(char *msg)
{
const char *equals_delimiter = " = ";
char *msg_name = strtok(msg, equals_delimiter);
char *msg_value = strtok(NULL, equals_delimiter);
//printf("handle_message: msg_name [%s] msg_value [%s]\n", msg_name, msg_value);
if (std::strcmp(msg_name, "mame_message") == 0)
void deliver(std::string &msg)
{
const char *comma_delimiter = ",";
msg_name = strtok(msg_value, comma_delimiter);
msg_value = strtok(NULL, comma_delimiter);
int id = atoi(msg_name);
int value = atoi(msg_value);
std::strncpy(m_data, msg.c_str(), max_length);
do_write(msg.size());
}
switch(id)
void handle_message(char *msg)
{
const char *equals_delimiter = " = ";
char *msg_name = strtok(msg, equals_delimiter);
char *msg_value = strtok(NULL, equals_delimiter);
//printf("handle_message: msg_name [%s] msg_value [%s]\n", msg_name, msg_value);
if (std::strcmp(msg_name, "mame_message") == 0)
{
case IM_MAME_PAUSE:
if (value == 1 && !machine().paused())
const char *comma_delimiter = ",";
msg_name = strtok(msg_value, comma_delimiter);
msg_value = strtok(NULL, comma_delimiter);
int id = atoi(msg_name);
int value = atoi(msg_value);
switch(id)
{
machine().pause();
case output_module::IM_MAME_PAUSE:
if (value == 1 && !machine().paused())
machine().pause();
else if (value == 0 && machine().paused())
machine().resume();
break;
case output_module::IM_MAME_SAVESTATE:
if (value == 0)
machine().schedule_load("auto");
else if (value == 1)
machine().schedule_save("auto");
break;
}
else if (value == 0 && machine().paused())
{
machine().resume();
}
break;
case IM_MAME_SAVESTATE:
if (value == 0)
{
machine().schedule_load("auto");
}
else if (value == 1)
{
machine().schedule_save("auto");
}
break;
}
}
}
}
void do_read()
{
auto self(shared_from_this());
m_socket.async_read_some(asio::buffer(m_input_m_data, max_length),
[this, self](std::error_code ec, std::size_t length)
{
if (!ec)
{
if (length > 0)
void do_read()
{
auto self(shared_from_this());
m_socket.async_read_some(
asio::buffer(m_input_m_data, max_length),
[this, self] (std::error_code ec, std::size_t length)
{
m_input_m_data[length] = '\0';
handle_message(m_input_m_data);
}
do_read();
}
else
{
m_clients->erase(shared_from_this());
}
});
}
if (!ec)
{
if (length > 0)
{
m_input_m_data[length] = '\0';
handle_message(m_input_m_data);
}
do_read();
}
else
{
m_clients->erase(shared_from_this());
}
});
}
void do_write(std::size_t length)
{
auto self(shared_from_this());
asio::async_write(m_socket, asio::buffer(m_data, length),
[this, self](std::error_code ec, std::size_t /*length*/)
{
if (ec)
{
m_clients->erase(shared_from_this());
}
});
}
void do_write(std::size_t length)
{
auto self(shared_from_this());
asio::async_write(
m_socket,
asio::buffer(m_data, length),
[this, self] (std::error_code ec, std::size_t /*length*/)
{
if (ec)
{
m_clients->erase(shared_from_this());
}
});
}
running_machine &machine() const { return *m_machine; }
running_machine &machine() const { return *m_machine; }
asio::ip::tcp::socket m_socket;
enum { max_length = 1024 };
char m_data[max_length];
char m_input_m_data[max_length];
client_set *m_clients;
running_machine *m_machine;
asio::ip::tcp::socket m_socket;
enum { max_length = 1024 };
char m_data[max_length];
char m_input_m_data[max_length];
client_set *m_clients;
running_machine *m_machine;
};
class output_network_server
{
public:
output_network_server(asio::io_context& io_context, short port, running_machine &machine) :
m_acceptor(io_context, asio::ip::tcp::endpoint(asio::ip::tcp::v4(), port))
{
m_machine = &machine;
do_accept();
}
output_network_server(asio::io_context& io_context, short port, running_machine &machine) :
m_acceptor(io_context, asio::ip::tcp::endpoint(asio::ip::tcp::v4(), port))
{
m_machine = &machine;
do_accept();
}
void deliver_to_all(std::string msg)
{
for (const auto &client: m_clients)
client->deliver(msg);
}
void deliver_to_all(std::string msg)
{
for (const auto &client: m_clients)
client->deliver(msg);
}
private:
void do_accept()
{
m_acceptor.async_accept(
[this](std::error_code ec, asio::ip::tcp::socket socket)
{
if (!ec)
{
std::make_shared<output_session>(std::move(socket),&m_clients)->start(machine());
}
void do_accept()
{
m_acceptor.async_accept(
[this] (std::error_code ec, asio::ip::tcp::socket socket)
{
if (!ec)
{
std::make_shared<output_session>(std::move(socket),&m_clients)->start(machine());
}
do_accept();
});
}
do_accept();
});
}
running_machine &machine() const { return *m_machine; }
running_machine &machine() const { return *m_machine; }
asio::ip::tcp::acceptor m_acceptor;
client_set m_clients;
running_machine *m_machine;
asio::ip::tcp::acceptor m_acceptor;
client_set m_clients;
running_machine *m_machine;
};
class output_network : public osd_module, public output_module
{
public:
output_network()
: osd_module(OSD_OUTPUT_PROVIDER, "network"),
output_module(),
m_io_context(nullptr), m_server(nullptr)
output_network() :
osd_module(OSD_OUTPUT_PROVIDER, "network"),
output_module(),
m_io_context(nullptr),
m_server(nullptr)
{
}
@ -201,9 +202,9 @@ public:
{
}
virtual int init(const osd_options &options) override
virtual int init(osd_interface &osd, const osd_options &options) override
{
m_working_thread = std::thread([](output_network* self) { self->process_output(); }, this);
m_working_thread = std::thread([] (output_network* self) { self->process_output(); }, this);
return 0;
}
@ -240,4 +241,8 @@ private:
output_network_server *m_server;
};
MODULE_DEFINITION(OUTPUT_NETWORK, output_network)
} // anonymous namespace
} // namespace osd
MODULE_DEFINITION(OUTPUT_NETWORK, osd::output_network)

View File

@ -24,7 +24,7 @@ public:
}
virtual ~output_none() { }
virtual int init(const osd_options &options) override { return 0; }
virtual int init(osd_interface &osd, const osd_options &options) override { return 0; }
virtual void exit() override { }
// output_module

View File

@ -4,12 +4,15 @@
* outpout_module.h
*
*/
#ifndef MAME_OSD_OUTPUT_OUTPUT_MODULE_H
#define MAME_OSD_OUTPUT_OUTPUT_MODULE_H
#ifndef OUTPUT_MODULE_H_
#define OUTPUT_MODULE_H_
#pragma once
#include "osdepend.h"
#include "modules/osdmodule.h"
#include <cstdint>
//============================================================
// CONSTANTS
@ -17,22 +20,23 @@
#define OSD_OUTPUT_PROVIDER "output"
#define IM_MAME_PAUSE 0
#define IM_MAME_SAVESTATE 1
class output_module
{
public:
static inline constexpr unsigned IM_MAME_PAUSE = 0;
static inline constexpr unsigned IM_MAME_SAVESTATE = 1;
output_module(): m_machine(nullptr) { }
virtual ~output_module() { }
virtual ~output_module() = default;
virtual void notify(const char *outname, int32_t value) = 0;
void set_machine(running_machine *machine) { m_machine = machine; }
running_machine &machine() const { return *m_machine; }
private:
running_machine *m_machine;
};
#endif /* OUTPUT_MODULE_H_ */
#endif // MAME_OSD_OUTPUT_OUTPUT_MODULE_H

View File

@ -7,21 +7,26 @@
//============================================================
#include "output_module.h"
#include "modules/osdmodule.h"
#include "modules/lib/osdobj_common.h"
#if defined(OSD_WINDOWS)
#include "win32_output.h"
// MAME headers
#include "emu.h"
#include "winmain.h"
#include "winutil.h"
// standard windows headers
#include <windows.h>
// MAME headers
#include "emu.h"
#include "winmain.h"
#include "winutil.h"
#include "win32_output.h"
namespace osd {
namespace {
//============================================================
// CONSTANTS
@ -71,7 +76,7 @@ public:
}
virtual ~output_win32() { }
virtual int init(const osd_options &options) override;
virtual int init(osd_interface &osd, const osd_options &options) override;
virtual void exit() override;
// output_module
@ -97,7 +102,7 @@ private:
// output_init
//============================================================
int output_win32::init(const osd_options &options)
int output_win32::init(osd_interface &osd, const osd_options &options)
{
int result;
@ -226,13 +231,13 @@ static LRESULT CALLBACK output_window_proc(HWND wnd, UINT message, WPARAM wparam
{
switch(wparam)
{
case IM_MAME_PAUSE:
case output_module::IM_MAME_PAUSE:
if (lparam == 1 && !output.machine().paused())
output.machine().pause();
else if (lparam == 0 && output.machine().paused())
output.machine().resume();
break;
case IM_MAME_SAVESTATE:
case output_module::IM_MAME_SAVESTATE:
if (lparam == 0)
output.machine().schedule_load("auto");
else if (lparam == 1)
@ -352,10 +357,15 @@ void output_win32::notify(const char *outname, int32_t value)
PostMessage(client->hwnd, om_mame_update_state, client->machine->output().name_to_id(outname), value);
}
} // anonymous namespace
} // namespace osd
#else
MODULE_NOT_SUPPORTED(output_win32, OSD_OUTPUT_PROVIDER, "windows")
namespace osd { namespace { MODULE_NOT_SUPPORTED(output_win32, OSD_OUTPUT_PROVIDER, "windows") } }
#endif
MODULE_DEFINITION(OUTPUT_WIN32, output_win32)
MODULE_DEFINITION(OUTPUT_WIN32, osd::output_win32)

View File

@ -2,12 +2,14 @@
// copyright-holders:Aaron Giles
//============================================================
//
// output.h - Win32 implementation of MAME output routines
// win32_output.h - Win32 implementation of MAME output routines
//
//============================================================
#ifndef __WINDOWS_OUTPUT_H__
#define __WINDOWS_OUTPUT_H__
#ifndef MAME_OSD_OUTPUT_WIN32_OUTPUT_H
#define MAME_OSD_OUTPUT_WIN32_OUTPUT_H
#pragma once
//============================================================
@ -83,8 +85,8 @@
struct copydata_id_string
{
uint32_t id; // ID that was requested
uint32_t id; // ID that was requested
char string[1]; // string array containing the data
};
#endif /* __WINDOWS_OUTPUT_H__ */
#endif // MAME_OSD_OUTPUT_WIN32_OUTPUT_H

View File

@ -10,23 +10,20 @@
//
//============================================================
#include "emu.h"
#include "draw13.h"
// OSD headers
#include "sdlopts.h"
#include "window.h"
// lib/util
#include "options.h"
// standard C headers
#include <cmath>
#include <cstdio>
// MAME headers
#include "emu.h"
#include "options.h"
// OSD headers
#include "osdsdl.h"
#include "window.h"
#include "draw13.h"
//============================================================
// DEBUGGING
//============================================================
//============================================================
// CONSTANTS

View File

@ -15,7 +15,6 @@
// OSD headers
#ifndef OSD_WINDOWS
#include "osdsdl.h"
#include "window.h"
#else
#include "../windows/window.h"

View File

@ -746,7 +746,7 @@ void renderer_d3d9::update_presentation_parameters()
m_presentation.MultiSampleType = D3DMULTISAMPLE_NONE;
m_presentation.SwapEffect = D3DSWAPEFFECT_DISCARD;
m_presentation.hDeviceWindow = std::static_pointer_cast<win_window_info>(win)->platform_window();
m_presentation.Windowed = !win->fullscreen() || win->win_has_menu();
m_presentation.Windowed = !win->fullscreen();
m_presentation.EnableAutoDepthStencil = FALSE;
m_presentation.AutoDepthStencilFormat = D3DFMT_D16;
m_presentation.Flags = 0;
@ -1193,7 +1193,7 @@ int renderer_d3d9::config_adapter_mode()
auto win = assert_window();
// choose a resolution: window mode case
if (!win->fullscreen() || !video_config.switchres || win->win_has_menu())
if (!win->fullscreen() || !video_config.switchres)
{
RECT client;

View File

@ -10,24 +10,21 @@
//
//============================================================
#include "drawsdl.h"
// MAME headers
#include "emucore.h"
#include "rendersw.hxx"
#include "ui/uimain.h"
// osd headers
#include "modules/monitor/monitor_module.h"
// standard C headers
#include <cmath>
#include <cstdio>
// MAME headers
#include "emucore.h"
#include "ui/uimain.h"
#include "rendersw.hxx"
// standard SDL headers
#include <SDL2/SDL.h>
// OSD headers
#include "osdsdl.h"
#include "window.h"
#include "drawsdl.h"
#include "modules/monitor/monitor_module.h"
//============================================================
// DEBUGGING

View File

@ -15,8 +15,14 @@
#pragma once
// OSD headers
#include "window.h"
#include <SDL2/SDL.h>
#include <memory>
/* renderer_sdl1 is the information about SDL for the current screen */
class renderer_sdl1 : public osd_renderer
{

View File

@ -52,7 +52,7 @@ public:
{
}
virtual int init(osd_options const &options) override;
virtual int init(osd_interface &osd, osd_options const &options) override;
virtual void exit() override;
// sound_module
@ -179,7 +179,7 @@ private:
};
int sound_coreaudio::init(const osd_options &options)
int sound_coreaudio::init(osd_interface &osd, const osd_options &options)
{
OSStatus err;

View File

@ -12,14 +12,16 @@
#if defined(OSD_WINDOWS) || defined(SDLMAME_WIN32)
// MAME headers
#include "osdcore.h"
#include "osdepend.h"
#include "emuopts.h"
// osd headers
#include "osdepend.h"
#include "osdcore.h"
#ifdef SDLMAME_WIN32
#include "../../sdl/osdsdl.h"
#include "modules/lib/osdobj_common.h"
#include "sdl/window.h"
#include <SDL2/SDL_syswm.h>
#include "../../sdl/window.h"
#else
#include "winmain.h"
#include "window.h"
@ -48,6 +50,8 @@
#define LOG(...) do { if (LOG_SOUND) osd_printf_verbose(__VA_ARGS__); } while(0)
namespace osd {
namespace {
class buffer_base
@ -217,7 +221,7 @@ public:
}
virtual ~sound_direct_sound() { }
virtual int init(osd_options const &options) override;
virtual int init(osd_interface &osd, osd_options const &options) override;
virtual void exit() override;
// sound_module
@ -251,9 +255,9 @@ private:
// init
//============================================================
int sound_direct_sound::init(osd_options const &options)
int sound_direct_sound::init(osd_interface &osd, osd_options const &options)
{
// attempt to initialize directsound
// attempt to initialize DirectSound
// don't make it fatal if we can't -- we'll just run without sound
dsound_init();
m_buffer_underflows = m_buffer_overflows = 0;
@ -554,9 +558,13 @@ void sound_direct_sound::destroy_buffers()
} // anonymous namespace
} // namespace osd
#else // defined(OSD_WINDOWS) || defined(SDLMAME_WIN32)
MODULE_NOT_SUPPORTED(sound_direct_sound, OSD_SOUND_PROVIDER, "dsound")
namespace osd { namespace { MODULE_NOT_SUPPORTED(sound_direct_sound, OSD_SOUND_PROVIDER, "dsound") } }
#endif // defined(OSD_WINDOWS) || defined(SDLMAME_WIN32)
MODULE_DEFINITION(SOUND_DSOUND, sound_direct_sound)
MODULE_DEFINITION(SOUND_DSOUND, osd::sound_direct_sound)

View File

@ -25,7 +25,7 @@ public:
}
virtual ~sound_js() { }
virtual int init(const osd_options &options) { return 0; }
virtual int init(osd_interface &osd, const osd_options &options) { return 0; }
virtual void exit() { }
// sound_module

View File

@ -25,7 +25,7 @@ public:
}
virtual ~sound_none() { }
virtual int init(const osd_options &options) override { return 0; }
virtual int init(osd_interface &osd, const osd_options &options) override { return 0; }
virtual void exit() override { }
// sound_module

View File

@ -47,7 +47,7 @@ public:
}
virtual ~sound_pa() { }
virtual int init(osd_options const &options) override;
virtual int init(osd_interface &osd, osd_options const &options) override;
virtual void exit() override;
// sound_module
@ -177,7 +177,7 @@ private:
#endif
};
int sound_pa::init(osd_options const &options)
int sound_pa::init(osd_interface &osd, osd_options const &options)
{
PaStreamParameters stream_params;
const PaStreamInfo* stream_info;

View File

@ -38,7 +38,7 @@ public:
}
virtual ~sound_pulse() { }
virtual int init(osd_options const &options) override;
virtual int init(osd_interface &osd, osd_options const &options) override;
virtual void exit() override;
virtual void update_audio_stream(bool is_throttled, const s16 *buffer, int samples_this_frame) override;
virtual void set_mastervolume(int attenuation) override;
@ -273,7 +273,7 @@ void sound_pulse::stop_mainloop(int err)
pa_mainloop_quit(m_mainloop, err);
}
int sound_pulse::init(osd_options const &options)
int sound_pulse::init(osd_interface &osd, osd_options const &options)
{
m_last_sample = 0;
m_setting_volume = false;

View File

@ -14,14 +14,10 @@
#if (defined(OSD_SDL) || defined(USE_SDL_SOUND))
// standard sdl header
#include <SDL2/SDL.h>
// MAME headers
#include "emuopts.h"
#include "osdcore.h"
#include "../../sdl/osdsdl.h"
// standard sdl header
#include <SDL2/SDL.h>
#include <algorithm>
#include <fstream>
@ -36,7 +32,10 @@ namespace {
// DEBUGGING
//============================================================
#define LOG_SOUND 0
#define LOG_SOUND 0
#define SDLMAME_SOUND_LOG "sound.log"
//============================================================
// CLASS
@ -58,7 +57,7 @@ public:
}
virtual ~sound_sdl() { }
virtual int init(const osd_options &options) override;
virtual int init(osd_interface &osd, const osd_options &options) override;
virtual void exit() override;
// sound_module
@ -336,7 +335,7 @@ void sound_sdl::sdl_callback(void *userdata, Uint8 *stream, int len)
// sound_sdl::init
//============================================================
int sound_sdl::init(const osd_options &options)
int sound_sdl::init(osd_interface &osd, const osd_options &options)
{
int n_channels = 2;
int audio_latency;

View File

@ -7,10 +7,25 @@
//====================================================================
#include "sound_module.h"
#include "modules/osdmodule.h"
#if defined(OSD_WINDOWS)
// MAME headers
#include "winutil.h"
#include "modules/lib/osdlib.h"
#include "osdcore.h"
#include "osdepend.h"
// stdlib includes
#include <algorithm>
#include <chrono>
#include <mutex>
#include <queue>
#include <thread>
// standard windows headers
#include <windows.h>
@ -21,20 +36,10 @@
#undef interface
// stdlib includes
#include <algorithm>
#include <chrono>
#include <mutex>
#include <queue>
#include <thread>
// MAME headers
#include "osdcore.h"
#include "osdepend.h"
namespace osd {
#include "winutil.h"
#include "modules/lib/osdlib.h"
namespace {
//============================================================
// Constants
@ -230,7 +235,7 @@ public:
virtual ~sound_xaudio2() { }
bool probe() override;
int init(osd_options const &options) override;
int init(osd_interface &osd, osd_options const &options) override;
void exit() override;
// sound_module
@ -269,7 +274,7 @@ bool sound_xaudio2::probe()
// init
//============================================================
int sound_xaudio2::init(osd_options const &options)
int sound_xaudio2::init(osd_interface &osd, osd_options const &options)
{
HRESULT result;
WAVEFORMATEX format = {0};
@ -695,9 +700,15 @@ void sound_xaudio2::roll_buffer()
}
}
} // anonymous namespace
} // namespace osd
#else
MODULE_NOT_SUPPORTED(sound_xaudio2, OSD_SOUND_PROVIDER, "xaudio2")
namespace osd { namespace { MODULE_NOT_SUPPORTED(sound_xaudio2, OSD_SOUND_PROVIDER, "xaudio2") } }
#endif
MODULE_DEFINITION(SOUND_XAUDIO2, sound_xaudio2)
MODULE_DEFINITION(SOUND_XAUDIO2, osd::sound_xaudio2)

754
src/osd/sdl/osdsdl.cpp Normal file
View File

@ -0,0 +1,754 @@
// license:BSD-3-Clause
// copyright-holders:Olivier Galibert, R. Belmont
#include "osdsdl.h"
#include "modules/input/input_common.h"
#include "modules/lib/osdlib.h"
#include "window.h"
#include "util/language.h"
#include "util/unicode.h"
// TODO: reduce dependence on concrete emu classes
#include "emu.h"
#include "main.h"
#include "uiinput.h"
#include "ui/uimain.h"
#include <SDL2/SDL.h>
#include <cstdio>
#include <cstring>
namespace {
//============================================================
// defines_verbose
//============================================================
#define MAC_EXPAND_STR(_m) #_m
#define MACRO_VERBOSE(_mac) \
do { \
if (strcmp(MAC_EXPAND_STR(_mac), #_mac) != 0) \
osd_printf_verbose("%s=%s ", #_mac, MAC_EXPAND_STR(_mac)); \
} while (0)
void defines_verbose()
{
osd_printf_verbose("Build version: %s\n", emulator_info::get_build_version());
osd_printf_verbose("Build architecure: ");
MACRO_VERBOSE(SDLMAME_ARCH);
osd_printf_verbose("\n");
osd_printf_verbose("Build defines 1: ");
MACRO_VERBOSE(SDLMAME_UNIX);
MACRO_VERBOSE(SDLMAME_X11);
MACRO_VERBOSE(SDLMAME_WIN32);
MACRO_VERBOSE(SDLMAME_MACOSX);
MACRO_VERBOSE(SDLMAME_DARWIN);
MACRO_VERBOSE(SDLMAME_LINUX);
MACRO_VERBOSE(SDLMAME_SOLARIS);
MACRO_VERBOSE(SDLMAME_IRIX);
MACRO_VERBOSE(SDLMAME_BSD);
osd_printf_verbose("\n");
osd_printf_verbose("Build defines 1: ");
MACRO_VERBOSE(LSB_FIRST);
MACRO_VERBOSE(PTR64);
MACRO_VERBOSE(MAME_NOASM);
MACRO_VERBOSE(MAME_DEBUG);
MACRO_VERBOSE(BIGENDIAN);
MACRO_VERBOSE(CPP_COMPILE);
MACRO_VERBOSE(SYNC_IMPLEMENTATION);
osd_printf_verbose("\n");
osd_printf_verbose("SDL/OpenGL defines: ");
osd_printf_verbose("SDL_COMPILEDVERSION=%d ", SDL_COMPILEDVERSION);
MACRO_VERBOSE(USE_OPENGL);
MACRO_VERBOSE(USE_DISPATCH_GL);
osd_printf_verbose("\n");
osd_printf_verbose("Compiler defines A: ");
MACRO_VERBOSE(__GNUC__);
MACRO_VERBOSE(__GNUC_MINOR__);
MACRO_VERBOSE(__GNUC_PATCHLEVEL__);
MACRO_VERBOSE(__VERSION__);
osd_printf_verbose("\n");
osd_printf_verbose("Compiler defines B: ");
MACRO_VERBOSE(__amd64__);
MACRO_VERBOSE(__x86_64__);
MACRO_VERBOSE(__unix__);
MACRO_VERBOSE(__i386__);
MACRO_VERBOSE(__ppc__);
MACRO_VERBOSE(__ppc64__);
osd_printf_verbose("\n");
osd_printf_verbose("Compiler defines C: ");
MACRO_VERBOSE(_FORTIFY_SOURCE);
MACRO_VERBOSE(__USE_FORTIFY_LEVEL);
osd_printf_verbose("\n");
}
//============================================================
// osd_sdl_info
//============================================================
void osd_sdl_info()
{
int num = SDL_GetNumVideoDrivers();
osd_printf_verbose("Available videodrivers: ");
for (int i = 0; i < num; i++)
{
const char *name = SDL_GetVideoDriver(i);
osd_printf_verbose("%s ", name);
}
osd_printf_verbose("\n");
osd_printf_verbose("Current Videodriver: %s\n", SDL_GetCurrentVideoDriver());
num = SDL_GetNumVideoDisplays();
for (int i = 0; i < num; i++)
{
SDL_DisplayMode mode;
osd_printf_verbose("\tDisplay #%d\n", i);
if (SDL_GetDesktopDisplayMode(i, &mode))
osd_printf_verbose("\t\tDesktop Mode: %dx%d-%d@%d\n", mode.w, mode.h, SDL_BITSPERPIXEL(mode.format), mode.refresh_rate);
if (SDL_GetCurrentDisplayMode(i, &mode))
osd_printf_verbose("\t\tCurrent Display Mode: %dx%d-%d@%d\n", mode.w, mode.h, SDL_BITSPERPIXEL(mode.format), mode.refresh_rate);
osd_printf_verbose("\t\tRenderdrivers:\n");
for (int j = 0; j < SDL_GetNumRenderDrivers(); j++)
{
SDL_RendererInfo info;
SDL_GetRenderDriverInfo(j, &info);
osd_printf_verbose("\t\t\t%10s (%dx%d)\n", info.name, info.max_texture_width, info.max_texture_height);
}
}
osd_printf_verbose("Available audio drivers: \n");
num = SDL_GetNumAudioDrivers();
for (int i = 0; i < num; i++)
{
osd_printf_verbose("\t%-20s\n", SDL_GetAudioDriver(i));
}
}
std::shared_ptr<sdl_window_info> window_from_id(Uint32 id)
{
SDL_Window const *const sdl_window = SDL_GetWindowFromID(id);
auto &windows = osd_common_t::s_window_list;
auto const window = std::find_if(
windows.begin(),
windows.end(),
[sdl_window] (std::shared_ptr<osd_window> w)
{
return std::static_pointer_cast<sdl_window_info>(w)->platform_window() == sdl_window;
});
if (window == windows.end())
return nullptr;
return std::static_pointer_cast<sdl_window_info>(*window);
}
} // anonymous namespace
//============================================================
// SDL OSD interface
//============================================================
sdl_osd_interface::sdl_osd_interface(sdl_options &options) :
osd_common_t(options),
m_options(options),
m_focus_window(),
m_mouse_over_window(0),
m_modifier_keys(0),
m_last_click_time(std::chrono::steady_clock::time_point::min()),
m_last_click_x(0),
m_last_click_y(0)
{
}
sdl_osd_interface::~sdl_osd_interface()
{
}
void sdl_osd_interface::init(running_machine &machine)
{
// call our parent
osd_common_t::init(machine);
const char *stemp;
// determine if we are benchmarking, and adjust options appropriately
int bench = options().bench();
if (bench > 0)
{
options().set_value(OPTION_SLEEP, false, OPTION_PRIORITY_MAXIMUM);
options().set_value(OPTION_THROTTLE, false, OPTION_PRIORITY_MAXIMUM);
options().set_value(OSDOPTION_SOUND, "none", OPTION_PRIORITY_MAXIMUM);
options().set_value(OSDOPTION_VIDEO, "none", OPTION_PRIORITY_MAXIMUM);
options().set_value(OPTION_SECONDS_TO_RUN, bench, OPTION_PRIORITY_MAXIMUM);
}
// Some driver options - must be before audio init!
stemp = options().audio_driver();
if (stemp != nullptr && strcmp(stemp, OSDOPTVAL_AUTO) != 0)
{
osd_printf_verbose("Setting SDL audiodriver '%s' ...\n", stemp);
osd_setenv(SDLENV_AUDIODRIVER, stemp, 1);
}
stemp = options().video_driver();
if (stemp != nullptr && strcmp(stemp, OSDOPTVAL_AUTO) != 0)
{
osd_printf_verbose("Setting SDL videodriver '%s' ...\n", stemp);
osd_setenv(SDLENV_VIDEODRIVER, stemp, 1);
}
stemp = options().render_driver();
if (stemp != nullptr)
{
if (strcmp(stemp, OSDOPTVAL_AUTO) != 0)
{
osd_printf_verbose("Setting SDL renderdriver '%s' ...\n", stemp);
//osd_setenv(SDLENV_RENDERDRIVER, stemp, 1);
SDL_SetHint(SDL_HINT_RENDER_DRIVER, stemp);
}
else
{
#if defined(SDLMAME_WIN32)
// OpenGL renderer has less issues with mode switching on windows
osd_printf_verbose("Setting SDL renderdriver '%s' ...\n", "opengl");
//osd_setenv(SDLENV_RENDERDRIVER, stemp, 1);
SDL_SetHint(SDL_HINT_RENDER_DRIVER, "opengl");
#endif
}
}
/* Set the SDL environment variable for drivers wanting to load the
* lib at startup.
*/
#if USE_OPENGL
/* FIXME: move lib loading code from drawogl.c here */
stemp = options().gl_lib();
if (stemp != nullptr && strcmp(stemp, OSDOPTVAL_AUTO) != 0)
{
osd_setenv("SDL_VIDEO_GL_DRIVER", stemp, 1);
osd_printf_verbose("Setting SDL_VIDEO_GL_DRIVER = '%s' ...\n", stemp);
}
#endif
/* get number of processors */
stemp = options().numprocessors();
osd_num_processors = 0;
if (strcmp(stemp, "auto") != 0)
{
osd_num_processors = atoi(stemp);
if (osd_num_processors < 1)
{
osd_printf_warning("numprocessors < 1 doesn't make much sense. Assuming auto ...\n");
osd_num_processors = 0;
}
}
/* Initialize SDL */
if (SDL_InitSubSystem(SDL_INIT_VIDEO))
{
osd_printf_error("Could not initialize SDL %s\n", SDL_GetError());
exit(-1);
}
// bgfx does not work with wayland
if ((strcmp(SDL_GetCurrentVideoDriver(), "wayland") == 0) && ((strcmp(options().video(), "auto") == 0) || (strcmp(options().video(), "bgfx") == 0)))
fatalerror("Error: BGFX video does not work with wayland videodriver. Please change either of the options.");
osd_sdl_info();
defines_verbose();
osd_common_t::init_subsystems();
if (options().oslog())
{
using namespace std::placeholders;
machine.add_logerror_callback(std::bind(&sdl_osd_interface::output_oslog, this, _1));
}
#ifdef SDLMAME_EMSCRIPTEN
SDL_EventState(SDL_TEXTINPUT, SDL_FALSE);
#else
SDL_EventState(SDL_TEXTINPUT, SDL_TRUE);
#endif
}
void sdl_osd_interface::input_update()
{
process_events_buf();
poll_inputs();
check_osd_inputs();
}
void sdl_osd_interface::customize_input_type_list(std::vector<input_type_entry> &typelist)
{
// loop over the defaults
for (input_type_entry &entry : typelist)
{
switch (entry.type())
{
// configurable UI mode switch
case IPT_UI_TOGGLE_UI:
{
char const *const uimode = options().ui_mode_key();
input_item_id mameid_code = ITEM_ID_INVALID;
if (!uimode || !*uimode || !strcmp(uimode, "auto"))
{
#if defined(__APPLE__) && defined(__MACH__)
mameid_code = keyboard_trans_table::instance().lookup_mame_code("ITEM_ID_INSERT");
#endif
}
else
{
std::string fullmode("ITEM_ID_");
fullmode.append(uimode);
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", N_p("input-name", "Toggle Fullscreen"));
entry.defseq(SEQ_TYPE_STANDARD).set(KEYCODE_ENTER, 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.
// 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;
// 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", N_p("input-name", "Toggle Filter"));
entry.defseq(SEQ_TYPE_STANDARD).set(KEYCODE_F5, KEYCODE_LCONTROL);
break;
// LCTRL-F6 to decrease OpenGL prescaling
case IPT_OSD_6:
entry.configure_osd("DECREASE_PRESCALE", N_p("input-name", "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", N_p("input-name", "Increase Prescaling"));
entry.defseq(SEQ_TYPE_STANDARD).set(KEYCODE_F7, KEYCODE_LCONTROL);
break;
// lshift-lalt-F12 for fullscreen video (BGFX)
case IPT_OSD_8:
entry.configure_osd("RENDER_AVI", N_p("input-name", "Record Rendered Video"));
entry.defseq(SEQ_TYPE_STANDARD).set(KEYCODE_F12, KEYCODE_LSHIFT, KEYCODE_LALT);
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;
#if defined(__APPLE__) && defined(__MACH__)
// 78-key Apple MacBook & Bluetooth keyboards have no right control key
case IPT_MAHJONG_SCORE:
if (entry.player() == 0)
entry.defseq(SEQ_TYPE_STANDARD).set(KEYCODE_SLASH);
break;
#endif
// leave everything else alone
default:
break;
}
}
}
void sdl_osd_interface::video_register()
{
video_options_add("soft", nullptr);
video_options_add("accel", nullptr);
#if USE_OPENGL
video_options_add("opengl", nullptr);
#endif
video_options_add("bgfx", nullptr);
//video_options_add("auto", nullptr); // making d3d video default one
}
void sdl_osd_interface::poll_inputs()
{
m_keyboard_input->poll_if_necessary();
m_mouse_input->poll_if_necessary();
m_lightgun_input->poll_if_necessary();
m_joystick_input->poll_if_necessary();
}
void sdl_osd_interface::release_keys()
{
auto const keybd = dynamic_cast<input_module_base *>(m_keyboard_input);
if (keybd)
keybd->reset_devices();
}
bool sdl_osd_interface::should_hide_mouse()
{
// if we are paused, no
if (machine().paused())
return false;
// if neither mice nor lightguns are enabled in the core, then no
if (!options().mouse() && !options().lightgun())
return false;
if (!mouse_over_window())
return false;
// otherwise, yes
return true;
}
void sdl_osd_interface::process_events_buf()
{
SDL_PumpEvents();
}
void sdl_osd_interface::process_events()
{
std::lock_guard<std::mutex> lock(subscription_mutex());
SDL_Event event;
while (SDL_PollEvent(&event))
{
// handle UI events
switch (event.type)
{
case SDL_WINDOWEVENT:
process_window_event(event);
break;
case SDL_KEYDOWN:
if (event.key.keysym.scancode == SDL_SCANCODE_LCTRL)
m_modifier_keys |= MODIFIER_KEY_LCTRL;
else if (event.key.keysym.scancode == SDL_SCANCODE_RCTRL)
m_modifier_keys |= MODIFIER_KEY_RCTRL;
else if (event.key.keysym.scancode == SDL_SCANCODE_LSHIFT)
m_modifier_keys |= MODIFIER_KEY_LSHIFT;
else if (event.key.keysym.scancode == SDL_SCANCODE_RSHIFT)
m_modifier_keys |= MODIFIER_KEY_RSHIFT;
if (event.key.keysym.sym < 0x20)
{
// push control characters - they don't arrive as text input events
machine().ui_input().push_char_event(osd_common_t::s_window_list.front()->target(), event.key.keysym.sym);
}
else if (m_modifier_keys & MODIFIER_KEY_CTRL)
{
// SDL filters out control characters for text input, so they are decoded here
if (event.key.keysym.sym >= 0x40 && event.key.keysym.sym < 0x7f)
{
machine().ui_input().push_char_event(osd_common_t::s_window_list.front()->target(), event.key.keysym.sym & 0x1f);
}
else if (m_modifier_keys & MODIFIER_KEY_SHIFT)
{
if (event.key.keysym.sym == SDLK_6) // Ctrl-^ (RS)
machine().ui_input().push_char_event(osd_common_t::s_window_list.front()->target(), 0x1e);
else if (event.key.keysym.sym == SDLK_MINUS) // Ctrl-_ (US)
machine().ui_input().push_char_event(osd_common_t::s_window_list.front()->target(), 0x1f);
}
}
break;
case SDL_KEYUP:
if (event.key.keysym.scancode == SDL_SCANCODE_LCTRL)
m_modifier_keys &= ~MODIFIER_KEY_LCTRL;
else if (event.key.keysym.scancode == SDL_SCANCODE_RCTRL)
m_modifier_keys &= ~MODIFIER_KEY_RCTRL;
else if (event.key.keysym.scancode == SDL_SCANCODE_LSHIFT)
m_modifier_keys &= ~MODIFIER_KEY_LSHIFT;
else if (event.key.keysym.scancode == SDL_SCANCODE_RSHIFT)
m_modifier_keys &= ~MODIFIER_KEY_RSHIFT;
break;
case SDL_TEXTINPUT:
process_textinput_event(event);
break;
case SDL_MOUSEMOTION:
{
int cx, cy;
auto const window = focus_window(event.motion);
if (window && window->xy_to_render_target(event.motion.x, event.motion.y, &cx, &cy))
machine().ui_input().push_mouse_move_event(window->target(), cx, cy);
}
break;
case SDL_MOUSEBUTTONDOWN:
//printf("But down %d %d %d %d %s\n", event.button.which, event.button.button, event.button.x, event.button.y, devinfo->name.c_str());
if (event.button.button == 1)
{
int cx, cy;
auto const window = focus_window(event.button);
if (window && window->xy_to_render_target(event.button.x, event.button.y, &cx, &cy))
{
auto const double_click_speed = std::chrono::milliseconds(250);
auto const click = std::chrono::steady_clock::now();
machine().ui_input().push_mouse_down_event(window->target(), cx, cy);
// avoid overflow with std::chrono::time_point::min() by adding rather than subtracting
if (click < (m_last_click_time + double_click_speed)
&& (cx >= (m_last_click_x - 4) && cx <= (m_last_click_x + 4))
&& (cy >= (m_last_click_y - 4) && cy <= (m_last_click_y + 4)))
{
m_last_click_time = std::chrono::time_point<std::chrono::steady_clock>::min();
machine().ui_input().push_mouse_double_click_event(window->target(), cx, cy);
}
else
{
m_last_click_time = click;
m_last_click_x = cx;
m_last_click_y = cy;
}
}
}
else if (event.button.button == 3)
{
int cx, cy;
auto const window = focus_window(event.button);
if (window != nullptr && window->xy_to_render_target(event.button.x, event.button.y, &cx, &cy))
machine().ui_input().push_mouse_rdown_event(window->target(), cx, cy);
}
break;
case SDL_MOUSEBUTTONUP:
//printf("But up %d %d %d %d\n", event.button.which, event.button.button, event.button.x, event.button.y);
if (event.button.button == 1)
{
int cx, cy;
auto const window = focus_window(event.button);
if (window && window->xy_to_render_target(event.button.x, event.button.y, &cx, &cy))
machine().ui_input().push_mouse_up_event(window->target(), cx, cy);
}
else if (event.button.button == 3)
{
int cx, cy;
auto window = focus_window(event.button);
if (window && window->xy_to_render_target(event.button.x, event.button.y, &cx, &cy))
machine().ui_input().push_mouse_rup_event(window->target(), cx, cy);
}
break;
case SDL_MOUSEWHEEL:
{
auto const window = focus_window(event.wheel);
if (window)
machine().ui_input().push_mouse_wheel_event(window->target(), 0, 0, event.wheel.y, 3);
}
break;
}
// let input modules do their thing
dispatch_event(event.type, event);
}
}
void sdl_osd_interface::osd_exit()
{
osd_common_t::osd_exit();
SDL_QuitSubSystem(SDL_INIT_VIDEO);
}
void sdl_osd_interface::output_oslog(const char *buffer)
{
fputs(buffer, stderr);
}
void sdl_osd_interface::process_window_event(SDL_Event const &event)
{
auto const window = window_from_id(event.window.windowID);
if (!window)
{
// This condition may occur when the fullscreen toggle is used
osd_printf_verbose("Skipped window event due to missing window param from SDL\n");
return;
}
switch (event.window.event)
{
case SDL_WINDOWEVENT_MOVED:
window->notify_changed();
m_focus_window = window;
break;
case SDL_WINDOWEVENT_RESIZED:
#ifdef SDLMAME_LINUX
/* FIXME: SDL2 sends some spurious resize events on Ubuntu
* while in fullscreen mode. Ignore them for now.
*/
if (!window->fullscreen())
#endif
{
//printf("event data1,data2 %d x %d %ld\n", event.window.data1, event.window.data2, sizeof(SDL_Event));
window->resize(event.window.data1, event.window.data2);
}
break;
case SDL_WINDOWEVENT_ENTER:
m_mouse_over_window = 1;
break;
case SDL_WINDOWEVENT_LEAVE:
machine().ui_input().push_mouse_leave_event(window->target());
m_mouse_over_window = 0;
break;
case SDL_WINDOWEVENT_FOCUS_GAINED:
m_focus_window = window;
machine().ui_input().push_window_focus_event(window->target());
break;
case SDL_WINDOWEVENT_FOCUS_LOST:
machine().ui_input().push_window_defocus_event(window->target());
break;
case SDL_WINDOWEVENT_CLOSE:
machine().schedule_exit();
break;
}
}
void sdl_osd_interface::process_textinput_event(SDL_Event const &event)
{
if (*event.text.text)
{
auto const window = focus_window(event.text);
//printf("Focus window is %p - wl %p\n", window, osd_common_t::s_window_list);
if (window != nullptr)
{
auto ptr = event.text.text;
auto len = std::strlen(event.text.text);
while (len)
{
char32_t ch;
auto chlen = uchar_from_utf8(&ch, ptr, len);
if (0 > chlen)
{
ch = 0x0fffd;
chlen = 1;
}
ptr += chlen;
len -= chlen;
machine().ui_input().push_char_event(window->target(), ch);
}
}
}
}
void sdl_osd_interface::check_osd_inputs()
{
// check for toggling fullscreen mode
if (machine().ui_input().pressed(IPT_OSD_1))
{
for (auto curwin : osd_common_t::s_window_list)
std::static_pointer_cast<sdl_window_info>(curwin)->toggle_full_screen();
}
auto window = osd_common_t::s_window_list.front();
if (USE_OPENGL)
{
//FIXME: on a per window basis
if (machine().ui_input().pressed(IPT_OSD_5))
{
video_config.filter = !video_config.filter;
machine().ui().popup_time(1, "Filter %s", video_config.filter? "enabled" : "disabled");
}
}
if (machine().ui_input().pressed(IPT_OSD_6))
std::static_pointer_cast<sdl_window_info>(window)->modify_prescale(-1);
if (machine().ui_input().pressed(IPT_OSD_7))
std::static_pointer_cast<sdl_window_info>(window)->modify_prescale(1);
if (machine().ui_input().pressed(IPT_OSD_8))
window->renderer().record();
}
template <typename T>
sdl_window_info *sdl_osd_interface::focus_window(T const &event) const
{
// FIXME: SDL does not properly report the window for certain OS.
if (false)
return window_from_id(event.windowID).get();
else
return m_focus_window.get();
}

View File

@ -5,43 +5,24 @@
#pragma once
#include "sdlopts.h"
#include "modules/lib/osdobj_common.h"
#include "modules/osdmodule.h"
#include "modules/font/font_module.h"
#include <cassert>
#include <chrono>
#include <memory>
#include <mutex>
#include <unordered_map>
#include <string>
#include <vector>
//============================================================
// Defines
//============================================================
#define SDLOPTION_INIPATH "inipath"
#define SDLOPTION_SDLVIDEOFPS "sdlvideofps"
#define SDLOPTION_USEALLHEADS "useallheads"
#define SDLOPTION_ATTACH_WINDOW "attach_window"
#define SDLOPTION_CENTERH "centerh"
#define SDLOPTION_CENTERV "centerv"
#define SDLOPTION_SCALEMODE "scalemode"
#define SDLOPTION_WAITVSYNC "waitvsync"
#define SDLOPTION_SYNCREFRESH "syncrefresh"
#define SDLOPTION_KEYMAP "keymap"
#define SDLOPTION_KEYMAP_FILE "keymap_file"
#define SDLOPTION_SIXAXIS "sixaxis"
#if (USE_XINPUT)
#define SDLOPTION_LIGHTGUNINDEX "lightgun_index"
#endif
#define SDLOPTION_AUDIODRIVER "audiodriver"
#define SDLOPTION_VIDEODRIVER "videodriver"
#define SDLOPTION_RENDERDRIVER "renderdriver"
#define SDLOPTION_GL_LIB "gl_lib"
#define SDLOPTVAL_OPENGL "opengl"
#define SDLOPTVAL_SOFT "soft"
#define SDLOPTVAL_SDL2ACCEL "accel"
#define SDLOPTVAL_BGFX "bgfx"
#define SDLMAME_LED(x) "led" #x
// read by sdlmame
@ -56,60 +37,105 @@
#define SDLENV_AUDIODRIVER "SDL_AUDIODRIVER"
#define SDLENV_RENDERDRIVER "SDL_VIDEO_RENDERER"
#define SDLMAME_SOUND_LOG "sound.log"
#ifdef SDLMAME_MACOSX
/* Vas Crabb: Default GL-lib for MACOSX */
#define SDLOPTVAL_GLLIB "/System/Library/Frameworks/OpenGL.framework/Libraries/libGL.dylib"
#else
#define SDLOPTVAL_GLLIB OSDOPTVAL_AUTO
#endif
//============================================================
// TYPE DEFINITIONS
//============================================================
class sdl_options : public osd_options
template <typename EventRecord, typename EventType>
class event_subscription_manager
{
public:
// construction/destruction
sdl_options();
// performance options
bool video_fps() const { return bool_value(SDLOPTION_SDLVIDEOFPS); }
// video options
bool centerh() const { return bool_value(SDLOPTION_CENTERH); }
bool centerv() const { return bool_value(SDLOPTION_CENTERV); }
const char *scale_mode() const { return value(SDLOPTION_SCALEMODE); }
// full screen options
#ifdef SDLMAME_X11
bool use_all_heads() const { return bool_value(SDLOPTION_USEALLHEADS); }
const char *attach_window() const { return value(SDLOPTION_ATTACH_WINDOW); }
#endif // SDLMAME_X11
// keyboard mapping
bool keymap() const { return bool_value(SDLOPTION_KEYMAP); }
const char *keymap_file() const { return value(SDLOPTION_KEYMAP_FILE); }
// joystick mapping
bool sixaxis() const { return bool_value(SDLOPTION_SIXAXIS); }
const char *video_driver() const { return value(SDLOPTION_VIDEODRIVER); }
const char *render_driver() const { return value(SDLOPTION_RENDERDRIVER); }
const char *audio_driver() const { return value(SDLOPTION_AUDIODRIVER); }
#if USE_OPENGL
const char *gl_lib() const { return value(SDLOPTION_GL_LIB); }
#endif
public: // need extra public section for forward declaration
class subscriber;
private:
static const options_entry s_option_entries[];
class impl
{
public:
std::mutex m_mutex;
std::unordered_multimap<EventType, subscriber *> m_subs;
};
std::shared_ptr<impl> m_impl;
protected:
event_subscription_manager() : m_impl(new impl)
{
}
~event_subscription_manager() = default;
std::mutex &subscription_mutex()
{
return m_impl->m_mutex;
}
void dispatch_event(EventType const &type, EventRecord const &event)
{
auto const matches = m_impl->m_subs.equal_range(type);
for (auto it = matches.first; matches.second != it; ++it)
it->second->handle_event(event);
}
public:
class subscriber
{
public:
virtual void handle_event(EventRecord const &event) = 0;
protected:
subscriber() = default;
virtual ~subscriber()
{
unsubscribe();
}
template <typename T>
void subscribe(event_subscription_manager &host, T &&types)
{
assert(!m_host.lock());
assert(host.m_impl);
m_host = host.m_impl;
std::lock_guard<std::mutex> lock(host.m_impl->m_mutex);
for (auto const &t : types)
host.m_impl->m_subs.emplace(t, this);
}
void unsubscribe()
{
auto const host(m_host.lock());
m_host.reset();
if (host)
{
std::lock_guard<std::mutex> lock(host->m_mutex);
auto it = host->m_subs.begin();
while (host->m_subs.end() != it)
{
if (it->second == this)
it = host->m_subs.erase(it);
else
++it;
}
}
}
private:
std::weak_ptr<impl> m_host;
};
};
class sdl_osd_interface : public osd_common_t
union SDL_Event;
using sdl_event_manager = event_subscription_manager<SDL_Event, uint32_t>;
class sdl_window_info;
class sdl_osd_interface : public osd_common_t, public sdl_event_manager
{
public:
// construction/destruction
@ -132,25 +158,54 @@ public:
virtual void video_exit() override;
virtual void window_exit() override;
// sdl specific
void poll_inputs(running_machine &machine);
// SDL-specific
virtual bool has_focus() const override { return bool(m_focus_window); }
void poll_inputs();
void release_keys();
bool should_hide_mouse();
void process_events_buf();
virtual sdl_options &options() override { return m_options; }
virtual void process_events() override;
protected:
virtual void build_slider_list() override;
virtual void update_slider_list() override;
private:
enum
{
MODIFIER_KEY_LCTRL = 0x01,
MODIFIER_KEY_RCTRL = 0x02,
MODIFIER_KEY_LSHIFT = 0x04,
MODIFIER_KEY_RSHIFT = 0x08,
MODIFIER_KEY_CTRL = MODIFIER_KEY_LCTRL | MODIFIER_KEY_RCTRL,
MODIFIER_KEY_SHIFT = MODIFIER_KEY_LSHIFT | MODIFIER_KEY_RSHIFT
};
virtual void osd_exit() override;
void extract_video_config();
void output_oslog(const char *buffer);
void process_window_event(SDL_Event const &event);
void process_textinput_event(SDL_Event const &event);
void check_osd_inputs();
bool mouse_over_window() const { return m_mouse_over_window > 0; }
template <typename T> sdl_window_info *focus_window(T const &event) const;
sdl_options &m_options;
std::shared_ptr<sdl_window_info> m_focus_window;
int m_mouse_over_window;
uint8_t m_modifier_keys;
std::chrono::steady_clock::time_point m_last_click_time;
int m_last_click_x;
int m_last_click_y;
};
//============================================================

View File

@ -2,12 +2,30 @@
// copyright-holders:Olivier Galibert, R. Belmont
//============================================================
//
// sdlmain.c - main file for SDLMAME.
// sdlmain.cpp - main file for SDLMAME.
//
// SDLMAME by Olivier Galibert and R. Belmont
//
//============================================================
// OSD headers
#include "osdsdl.h"
#include "modules/lib/osdlib.h"
#include "modules/diagnostics/diagnostics_module.h"
// MAME headers
#include "emu.h"
#include "emuopts.h"
#include "main.h"
#include "video.h"
#include "corestr.h"
#include "osdepend.h"
#include "strconv.h"
#include <SDL2/SDL.h>
// only for oslog callback
#include <functional>
@ -28,40 +46,6 @@
#include <unistd.h>
#endif
// only for strconv.h
#if defined(SDLMAME_WIN32)
#include <windows.h>
#endif
#include <SDL2/SDL.h>
// MAME headers
#include "corestr.h"
#include "osdepend.h"
#include "emu.h"
#include "emuopts.h"
#include "strconv.h"
// OSD headers
#include "video.h"
#include "osdsdl.h"
#include "modules/lib/osdlib.h"
#include "modules/diagnostics/diagnostics_module.h"
//============================================================
// OPTIONS
//============================================================
#ifndef INI_PATH
#if defined(SDLMAME_WIN32)
#define INI_PATH ".;ini;ini/presets"
#elif defined(SDLMAME_MACOSX)
#define INI_PATH "$HOME/Library/Application Support/APP_NAME;$HOME/.APP_NAME;.;ini"
#else
#define INI_PATH "$HOME/.APP_NAME;.;ini"
#endif // MACOSX
#endif // INI_PATH
//============================================================
// Global variables
@ -71,80 +55,6 @@
int sdl_entered_debugger;
#endif
//============================================================
// Local variables
//============================================================
const options_entry sdl_options::s_option_entries[] =
{
{ SDLOPTION_INIPATH, INI_PATH, core_options::option_type::MULTIPATH, "path to ini files" },
// performance options
{ nullptr, nullptr, core_options::option_type::HEADER, "SDL PERFORMANCE OPTIONS" },
{ SDLOPTION_SDLVIDEOFPS, "0", core_options::option_type::BOOLEAN, "show sdl video performance" },
// video options
{ nullptr, nullptr, core_options::option_type::HEADER, "SDL VIDEO OPTIONS" },
// OS X can be trusted to have working hardware OpenGL, so default to it on for the best user experience
{ SDLOPTION_CENTERH, "1", core_options::option_type::BOOLEAN, "center horizontally within the view area" },
{ SDLOPTION_CENTERV, "1", core_options::option_type::BOOLEAN, "center vertically within the view area" },
{ SDLOPTION_SCALEMODE ";sm", OSDOPTVAL_NONE, core_options::option_type::STRING, "Scale mode: none, hwblit, hwbest, yv12, yuy2, yv12x2, yuy2x2 (-video soft only)" },
// full screen options
#ifdef SDLMAME_X11
{ nullptr, nullptr, core_options::option_type::HEADER, "SDL FULL SCREEN OPTIONS" },
{ SDLOPTION_USEALLHEADS, "0", core_options::option_type::BOOLEAN, "split full screen image across monitors" },
{ SDLOPTION_ATTACH_WINDOW, "", core_options::option_type::STRING, "attach to arbitrary window" },
#endif // SDLMAME_X11
// keyboard mapping
{ nullptr, nullptr, core_options::option_type::HEADER, "SDL KEYBOARD MAPPING" },
{ SDLOPTION_KEYMAP, "0", core_options::option_type::BOOLEAN, "enable keymap" },
{ SDLOPTION_KEYMAP_FILE, "keymap.dat", core_options::option_type::PATH, "keymap filename" },
// joystick mapping
{ nullptr, nullptr, core_options::option_type::HEADER, "SDL JOYSTICK MAPPING" },
{ SDLOPTION_SIXAXIS, "0", core_options::option_type::BOOLEAN, "use special handling for PS3 Sixaxis controllers" },
#if (USE_XINPUT)
// lightgun mapping
{ nullptr, nullptr, core_options::option_type::HEADER, "SDL LIGHTGUN MAPPING" },
{ SDLOPTION_LIGHTGUNINDEX "1", OSDOPTVAL_AUTO, core_options::option_type::STRING, "name of lightgun mapped to lightgun #1" },
{ SDLOPTION_LIGHTGUNINDEX "2", OSDOPTVAL_AUTO, core_options::option_type::STRING, "name of lightgun mapped to lightgun #2" },
{ SDLOPTION_LIGHTGUNINDEX "3", OSDOPTVAL_AUTO, core_options::option_type::STRING, "name of lightgun mapped to lightgun #3" },
{ SDLOPTION_LIGHTGUNINDEX "4", OSDOPTVAL_AUTO, core_options::option_type::STRING, "name of lightgun mapped to lightgun #4" },
{ SDLOPTION_LIGHTGUNINDEX "5", OSDOPTVAL_AUTO, core_options::option_type::STRING, "name of lightgun mapped to lightgun #5" },
{ SDLOPTION_LIGHTGUNINDEX "6", OSDOPTVAL_AUTO, core_options::option_type::STRING, "name of lightgun mapped to lightgun #6" },
{ SDLOPTION_LIGHTGUNINDEX "7", OSDOPTVAL_AUTO, core_options::option_type::STRING, "name of lightgun mapped to lightgun #7" },
{ SDLOPTION_LIGHTGUNINDEX "8", OSDOPTVAL_AUTO, core_options::option_type::STRING, "name of lightgun mapped to lightgun #8" },
#endif
// SDL low level driver options
{ nullptr, nullptr, core_options::option_type::HEADER, "SDL LOW-LEVEL DRIVER OPTIONS" },
{ SDLOPTION_VIDEODRIVER ";vd", OSDOPTVAL_AUTO, core_options::option_type::STRING, "SDL video driver to use ('x11', 'directfb', ... or 'auto' for SDL default" },
{ SDLOPTION_RENDERDRIVER ";rd", OSDOPTVAL_AUTO, core_options::option_type::STRING, "SDL render driver to use ('software', 'opengl', 'directfb' ... or 'auto' for SDL default" },
{ SDLOPTION_AUDIODRIVER ";ad", OSDOPTVAL_AUTO, core_options::option_type::STRING, "SDL audio driver to use ('alsa', 'arts', ... or 'auto' for SDL default" },
#if USE_OPENGL
{ SDLOPTION_GL_LIB, SDLOPTVAL_GLLIB, core_options::option_type::STRING, "alternative libGL.so to use; 'auto' for system default" },
#endif
// End of list
{ nullptr }
};
//============================================================
// sdl_options
//============================================================
sdl_options::sdl_options() : osd_options()
{
#if defined (SDLMAME_ANDROID)
chdir (SDL_AndroidGetExternalStoragePath());
#endif
std::string ini_path(INI_PATH);
add_entries(sdl_options::s_option_entries);
strreplace(ini_path, "APP_NAME", emulator_info::get_appname_lower());
set_default_value(SDLOPTION_INIPATH, std::move(ini_path));
}
//============================================================
// main
@ -201,297 +111,3 @@ int main(int argc, char** argv)
exit(res);
}
//============================================================
// constructor
//============================================================
sdl_osd_interface::sdl_osd_interface(sdl_options &options)
: osd_common_t(options), m_options(options)
{
}
//============================================================
// destructor
//============================================================
sdl_osd_interface::~sdl_osd_interface()
{
}
//============================================================
// osd_exit
//============================================================
void sdl_osd_interface::osd_exit()
{
osd_common_t::osd_exit();
SDL_QuitSubSystem(SDL_INIT_VIDEO);
}
//============================================================
// defines_verbose
//============================================================
#define MAC_EXPAND_STR(_m) #_m
#define MACRO_VERBOSE(_mac) \
do { \
if (strcmp(MAC_EXPAND_STR(_mac), #_mac) != 0) \
osd_printf_verbose("%s=%s ", #_mac, MAC_EXPAND_STR(_mac)); \
} while (0)
#define _SDL_VER #SDL_MAJOR_VERSION "." #SDL_MINOR_VERSION "." #SDL_PATCHLEVEL
static void defines_verbose(void)
{
osd_printf_verbose("Build version: %s\n", emulator_info::get_build_version());
osd_printf_verbose("Build architecure: ");
MACRO_VERBOSE(SDLMAME_ARCH);
osd_printf_verbose("\n");
osd_printf_verbose("Build defines 1: ");
MACRO_VERBOSE(SDLMAME_UNIX);
MACRO_VERBOSE(SDLMAME_X11);
MACRO_VERBOSE(SDLMAME_WIN32);
MACRO_VERBOSE(SDLMAME_MACOSX);
MACRO_VERBOSE(SDLMAME_DARWIN);
MACRO_VERBOSE(SDLMAME_LINUX);
MACRO_VERBOSE(SDLMAME_SOLARIS);
MACRO_VERBOSE(SDLMAME_IRIX);
MACRO_VERBOSE(SDLMAME_BSD);
osd_printf_verbose("\n");
osd_printf_verbose("Build defines 1: ");
MACRO_VERBOSE(LSB_FIRST);
MACRO_VERBOSE(PTR64);
MACRO_VERBOSE(MAME_NOASM);
MACRO_VERBOSE(MAME_DEBUG);
MACRO_VERBOSE(BIGENDIAN);
MACRO_VERBOSE(CPP_COMPILE);
MACRO_VERBOSE(SYNC_IMPLEMENTATION);
osd_printf_verbose("\n");
osd_printf_verbose("SDL/OpenGL defines: ");
osd_printf_verbose("SDL_COMPILEDVERSION=%d ", SDL_COMPILEDVERSION);
MACRO_VERBOSE(USE_OPENGL);
MACRO_VERBOSE(USE_DISPATCH_GL);
osd_printf_verbose("\n");
osd_printf_verbose("Compiler defines A: ");
MACRO_VERBOSE(__GNUC__);
MACRO_VERBOSE(__GNUC_MINOR__);
MACRO_VERBOSE(__GNUC_PATCHLEVEL__);
MACRO_VERBOSE(__VERSION__);
osd_printf_verbose("\n");
osd_printf_verbose("Compiler defines B: ");
MACRO_VERBOSE(__amd64__);
MACRO_VERBOSE(__x86_64__);
MACRO_VERBOSE(__unix__);
MACRO_VERBOSE(__i386__);
MACRO_VERBOSE(__ppc__);
MACRO_VERBOSE(__ppc64__);
osd_printf_verbose("\n");
osd_printf_verbose("Compiler defines C: ");
MACRO_VERBOSE(_FORTIFY_SOURCE);
MACRO_VERBOSE(__USE_FORTIFY_LEVEL);
osd_printf_verbose("\n");
}
//============================================================
// osd_sdl_info
//============================================================
static void osd_sdl_info(void)
{
int i, num = SDL_GetNumVideoDrivers();
osd_printf_verbose("Available videodrivers: ");
for (i=0;i<num;i++)
{
const char *name = SDL_GetVideoDriver(i);
osd_printf_verbose("%s ", name);
}
osd_printf_verbose("\n");
osd_printf_verbose("Current Videodriver: %s\n", SDL_GetCurrentVideoDriver());
num = SDL_GetNumVideoDisplays();
for (i=0;i<num;i++)
{
SDL_DisplayMode mode;
int j;
osd_printf_verbose("\tDisplay #%d\n", i);
if (SDL_GetDesktopDisplayMode(i, &mode))
osd_printf_verbose("\t\tDesktop Mode: %dx%d-%d@%d\n", mode.w, mode.h, SDL_BITSPERPIXEL(mode.format), mode.refresh_rate);
if (SDL_GetCurrentDisplayMode(i, &mode))
osd_printf_verbose("\t\tCurrent Display Mode: %dx%d-%d@%d\n", mode.w, mode.h, SDL_BITSPERPIXEL(mode.format), mode.refresh_rate);
osd_printf_verbose("\t\tRenderdrivers:\n");
for (j=0; j<SDL_GetNumRenderDrivers(); j++)
{
SDL_RendererInfo info;
SDL_GetRenderDriverInfo(j, &info);
osd_printf_verbose("\t\t\t%10s (%dx%d)\n", info.name, info.max_texture_width, info.max_texture_height);
}
}
osd_printf_verbose("Available audio drivers: \n");
num = SDL_GetNumAudioDrivers();
for (i=0;i<num;i++)
{
osd_printf_verbose("\t%-20s\n", SDL_GetAudioDriver(i));
}
}
//============================================================
// video_register
//============================================================
void sdl_osd_interface::video_register()
{
video_options_add("soft", nullptr);
video_options_add("accel", nullptr);
#if USE_OPENGL
video_options_add("opengl", nullptr);
#endif
video_options_add("bgfx", nullptr);
//video_options_add("auto", nullptr); // making d3d video default one
}
//============================================================
// output_oslog
//============================================================
void sdl_osd_interface::output_oslog(const char *buffer)
{
fputs(buffer, stderr);
}
//============================================================
// osd_setup_osd_specific_emu_options
//============================================================
void osd_setup_osd_specific_emu_options(emu_options &opts)
{
opts.add_entries(osd_options::s_option_entries);
}
//============================================================
// init
//============================================================
void sdl_osd_interface::init(running_machine &machine)
{
// call our parent
osd_common_t::init(machine);
const char *stemp;
// determine if we are benchmarking, and adjust options appropriately
int bench = options().bench();
if (bench > 0)
{
options().set_value(OPTION_SLEEP, false, OPTION_PRIORITY_MAXIMUM);
options().set_value(OPTION_THROTTLE, false, OPTION_PRIORITY_MAXIMUM);
options().set_value(OSDOPTION_SOUND, "none", OPTION_PRIORITY_MAXIMUM);
options().set_value(OSDOPTION_VIDEO, "none", OPTION_PRIORITY_MAXIMUM);
options().set_value(OPTION_SECONDS_TO_RUN, bench, OPTION_PRIORITY_MAXIMUM);
}
// Some driver options - must be before audio init!
stemp = options().audio_driver();
if (stemp != nullptr && strcmp(stemp, OSDOPTVAL_AUTO) != 0)
{
osd_printf_verbose("Setting SDL audiodriver '%s' ...\n", stemp);
osd_setenv(SDLENV_AUDIODRIVER, stemp, 1);
}
stemp = options().video_driver();
if (stemp != nullptr && strcmp(stemp, OSDOPTVAL_AUTO) != 0)
{
osd_printf_verbose("Setting SDL videodriver '%s' ...\n", stemp);
osd_setenv(SDLENV_VIDEODRIVER, stemp, 1);
}
stemp = options().render_driver();
if (stemp != nullptr)
{
if (strcmp(stemp, OSDOPTVAL_AUTO) != 0)
{
osd_printf_verbose("Setting SDL renderdriver '%s' ...\n", stemp);
//osd_setenv(SDLENV_RENDERDRIVER, stemp, 1);
SDL_SetHint(SDL_HINT_RENDER_DRIVER, stemp);
}
else
{
#if defined(SDLMAME_WIN32)
// OpenGL renderer has less issues with mode switching on windows
osd_printf_verbose("Setting SDL renderdriver '%s' ...\n", "opengl");
//osd_setenv(SDLENV_RENDERDRIVER, stemp, 1);
SDL_SetHint(SDL_HINT_RENDER_DRIVER, "opengl");
#endif
}
}
/* Set the SDL environment variable for drivers wanting to load the
* lib at startup.
*/
#if USE_OPENGL
/* FIXME: move lib loading code from drawogl.c here */
stemp = options().gl_lib();
if (stemp != nullptr && strcmp(stemp, OSDOPTVAL_AUTO) != 0)
{
osd_setenv("SDL_VIDEO_GL_DRIVER", stemp, 1);
osd_printf_verbose("Setting SDL_VIDEO_GL_DRIVER = '%s' ...\n", stemp);
}
#endif
/* get number of processors */
stemp = options().numprocessors();
osd_num_processors = 0;
if (strcmp(stemp, "auto") != 0)
{
osd_num_processors = atoi(stemp);
if (osd_num_processors < 1)
{
osd_printf_warning("numprocessors < 1 doesn't make much sense. Assuming auto ...\n");
osd_num_processors = 0;
}
}
/* Initialize SDL */
if (SDL_InitSubSystem(SDL_INIT_VIDEO))
{
osd_printf_error("Could not initialize SDL %s\n", SDL_GetError());
exit(-1);
}
// bgfx does not work with wayland
if ((strcmp(SDL_GetCurrentVideoDriver(), "wayland") == 0) && ((strcmp(options().video(), "auto") == 0) || (strcmp(options().video(), "bgfx") == 0)))
fatalerror("Error: BGFX video does not work with wayland videodriver. Please change either of the options.");
osd_sdl_info();
defines_verbose();
osd_common_t::init_subsystems();
if (options().oslog())
{
using namespace std::placeholders;
machine.add_logerror_callback(std::bind(&sdl_osd_interface::output_oslog, this, _1));
}
#ifdef SDLMAME_EMSCRIPTEN
SDL_EventState(SDL_TEXTINPUT, SDL_FALSE);
#else
SDL_EventState(SDL_TEXTINPUT, SDL_TRUE);
#endif
}

126
src/osd/sdl/sdlopts.cpp Normal file
View File

@ -0,0 +1,126 @@
// license:BSD-3-Clause
// copyright-holders:Olivier Galibert, R. Belmont
#include "sdlopts.h"
// emu
#include "emu.h"
#include "main.h"
// lib/util
#include "util/corestr.h"
#include <SDL2/SDL.h>
#include <string>
#if defined(SDLMAME_ANDROID)
#include "unistd.h"
#endif
namespace {
//============================================================
// OPTIONS
//============================================================
#ifndef INI_PATH
#if defined(SDLMAME_WIN32)
#define INI_PATH ".;ini;ini/presets"
#elif defined(SDLMAME_MACOSX)
#define INI_PATH "$HOME/Library/Application Support/APP_NAME;$HOME/.APP_NAME;.;ini"
#else
#define INI_PATH "$HOME/.APP_NAME;.;ini"
#endif // MACOSX
#endif // INI_PATH
//============================================================
// Local variables
//============================================================
const options_entry f_sdl_option_entries[] =
{
{ SDLOPTION_INIPATH, INI_PATH, core_options::option_type::MULTIPATH, "path to ini files" },
// performance options
{ nullptr, nullptr, core_options::option_type::HEADER, "SDL PERFORMANCE OPTIONS" },
{ SDLOPTION_SDLVIDEOFPS, "0", core_options::option_type::BOOLEAN, "show sdl video performance" },
// video options
{ nullptr, nullptr, core_options::option_type::HEADER, "SDL VIDEO OPTIONS" },
// OS X can be trusted to have working hardware OpenGL, so default to it on for the best user experience
{ SDLOPTION_CENTERH, "1", core_options::option_type::BOOLEAN, "center horizontally within the view area" },
{ SDLOPTION_CENTERV, "1", core_options::option_type::BOOLEAN, "center vertically within the view area" },
{ SDLOPTION_SCALEMODE ";sm", OSDOPTVAL_NONE, core_options::option_type::STRING, "Scale mode: none, hwblit, hwbest, yv12, yuy2, yv12x2, yuy2x2 (-video soft only)" },
// full screen options
#ifdef SDLMAME_X11
{ nullptr, nullptr, core_options::option_type::HEADER, "SDL FULL SCREEN OPTIONS" },
{ SDLOPTION_USEALLHEADS, "0", core_options::option_type::BOOLEAN, "split full screen image across monitors" },
{ SDLOPTION_ATTACH_WINDOW, "", core_options::option_type::STRING, "attach to arbitrary window" },
#endif // SDLMAME_X11
// keyboard mapping
{ nullptr, nullptr, core_options::option_type::HEADER, "SDL KEYBOARD MAPPING" },
{ SDLOPTION_KEYMAP, "0", core_options::option_type::BOOLEAN, "enable keymap" },
{ SDLOPTION_KEYMAP_FILE, "keymap.dat", core_options::option_type::PATH, "keymap filename" },
// joystick mapping
{ nullptr, nullptr, core_options::option_type::HEADER, "SDL JOYSTICK MAPPING" },
{ SDLOPTION_SIXAXIS, "0", core_options::option_type::BOOLEAN, "use special handling for PS3 Sixaxis controllers" },
#if (USE_XINPUT)
// lightgun mapping
{ nullptr, nullptr, core_options::option_type::HEADER, "SDL LIGHTGUN MAPPING" },
{ SDLOPTION_LIGHTGUNINDEX "1", OSDOPTVAL_AUTO, core_options::option_type::STRING, "name of lightgun mapped to lightgun #1" },
{ SDLOPTION_LIGHTGUNINDEX "2", OSDOPTVAL_AUTO, core_options::option_type::STRING, "name of lightgun mapped to lightgun #2" },
{ SDLOPTION_LIGHTGUNINDEX "3", OSDOPTVAL_AUTO, core_options::option_type::STRING, "name of lightgun mapped to lightgun #3" },
{ SDLOPTION_LIGHTGUNINDEX "4", OSDOPTVAL_AUTO, core_options::option_type::STRING, "name of lightgun mapped to lightgun #4" },
{ SDLOPTION_LIGHTGUNINDEX "5", OSDOPTVAL_AUTO, core_options::option_type::STRING, "name of lightgun mapped to lightgun #5" },
{ SDLOPTION_LIGHTGUNINDEX "6", OSDOPTVAL_AUTO, core_options::option_type::STRING, "name of lightgun mapped to lightgun #6" },
{ SDLOPTION_LIGHTGUNINDEX "7", OSDOPTVAL_AUTO, core_options::option_type::STRING, "name of lightgun mapped to lightgun #7" },
{ SDLOPTION_LIGHTGUNINDEX "8", OSDOPTVAL_AUTO, core_options::option_type::STRING, "name of lightgun mapped to lightgun #8" },
#endif
// SDL low level driver options
{ nullptr, nullptr, core_options::option_type::HEADER, "SDL LOW-LEVEL DRIVER OPTIONS" },
{ SDLOPTION_VIDEODRIVER ";vd", OSDOPTVAL_AUTO, core_options::option_type::STRING, "SDL video driver to use ('x11', 'directfb', ... or 'auto' for SDL default" },
{ SDLOPTION_RENDERDRIVER ";rd", OSDOPTVAL_AUTO, core_options::option_type::STRING, "SDL render driver to use ('software', 'opengl', 'directfb' ... or 'auto' for SDL default" },
{ SDLOPTION_AUDIODRIVER ";ad", OSDOPTVAL_AUTO, core_options::option_type::STRING, "SDL audio driver to use ('alsa', 'arts', ... or 'auto' for SDL default" },
#if USE_OPENGL
{ SDLOPTION_GL_LIB, SDLOPTVAL_GLLIB, core_options::option_type::STRING, "alternative libGL.so to use; 'auto' for system default" },
#endif
// End of list
{ nullptr }
};
} // anonymous namespace
//============================================================
// sdl_options
//============================================================
sdl_options::sdl_options() : osd_options()
{
#if defined(SDLMAME_ANDROID)
chdir(SDL_AndroidGetExternalStoragePath()); // FIXME: why is this here of all places?
#endif
std::string ini_path(INI_PATH);
add_entries(f_sdl_option_entries);
strreplace(ini_path, "APP_NAME", emulator_info::get_appname_lower());
set_default_value(SDLOPTION_INIPATH, std::move(ini_path));
}
//============================================================
// osd_setup_osd_specific_emu_options
//============================================================
void osd_setup_osd_specific_emu_options(emu_options &opts)
{
opts.add_entries(osd_options::s_option_entries);
opts.add_entries(f_sdl_option_entries);
}

96
src/osd/sdl/sdlopts.h Normal file
View File

@ -0,0 +1,96 @@
// license:BSD-3-Clause
// copyright-holders:Olivier Galibert, R. Belmont
#ifndef MAME_OSD_SDL_SDLOPTS_H
#define MAME_OSD_SDL_SDLOPTS_H
#pragma once
#include "modules/lib/osdobj_common.h"
//============================================================
// Option identifiers
//============================================================
#define SDLOPTION_INIPATH "inipath"
#define SDLOPTION_SDLVIDEOFPS "sdlvideofps"
#define SDLOPTION_USEALLHEADS "useallheads"
#define SDLOPTION_ATTACH_WINDOW "attach_window"
#define SDLOPTION_CENTERH "centerh"
#define SDLOPTION_CENTERV "centerv"
#define SDLOPTION_SCALEMODE "scalemode"
#define SDLOPTION_WAITVSYNC "waitvsync"
#define SDLOPTION_SYNCREFRESH "syncrefresh"
#define SDLOPTION_KEYMAP "keymap"
#define SDLOPTION_KEYMAP_FILE "keymap_file"
#define SDLOPTION_SIXAXIS "sixaxis"
#if defined(USE_XINPUT) && USE_XINPUT
#define SDLOPTION_LIGHTGUNINDEX "lightgun_index"
#endif
#define SDLOPTION_AUDIODRIVER "audiodriver"
#define SDLOPTION_VIDEODRIVER "videodriver"
#define SDLOPTION_RENDERDRIVER "renderdriver"
#define SDLOPTION_GL_LIB "gl_lib"
//============================================================
// Option values
//============================================================
#define SDLOPTVAL_OPENGL "opengl"
#define SDLOPTVAL_SOFT "soft"
#define SDLOPTVAL_SDL2ACCEL "accel"
#define SDLOPTVAL_BGFX "bgfx"
#ifdef SDLMAME_MACOSX
/* Vas Crabb: Default GL-lib for MACOSX */
#define SDLOPTVAL_GLLIB "/System/Library/Frameworks/OpenGL.framework/Libraries/libGL.dylib"
#else
#define SDLOPTVAL_GLLIB OSDOPTVAL_AUTO
#endif
//============================================================
// TYPE DEFINITIONS
//============================================================
class sdl_options : public osd_options
{
public:
// construction/destruction
sdl_options();
// performance options
bool video_fps() const { return bool_value(SDLOPTION_SDLVIDEOFPS); }
// video options
bool centerh() const { return bool_value(SDLOPTION_CENTERH); }
bool centerv() const { return bool_value(SDLOPTION_CENTERV); }
const char *scale_mode() const { return value(SDLOPTION_SCALEMODE); }
// full screen options
#if defined(SDLMAME_X11)
bool use_all_heads() const { return bool_value(SDLOPTION_USEALLHEADS); }
const char *attach_window() const { return value(SDLOPTION_ATTACH_WINDOW); }
#endif // SDLMAME_X11
// keyboard mapping
bool keymap() const { return bool_value(SDLOPTION_KEYMAP); }
const char *keymap_file() const { return value(SDLOPTION_KEYMAP_FILE); }
// joystick mapping
bool sixaxis() const { return bool_value(SDLOPTION_SIXAXIS); }
const char *video_driver() const { return value(SDLOPTION_VIDEODRIVER); }
const char *render_driver() const { return value(SDLOPTION_RENDERDRIVER); }
const char *audio_driver() const { return value(SDLOPTION_AUDIODRIVER); }
#if USE_OPENGL
const char *gl_lib() const { return value(SDLOPTION_GL_LIB); }
#endif
};
#endif // MAME_OSD_SDL_SDLOPTS_H

Some files were not shown because too many files have changed in this diff Show More