diff options
author | 2016-11-14 21:06:42 -0500 | |
---|---|---|
committer | 2016-11-14 21:06:42 -0500 | |
commit | 0f060802b5308bf79edd34b78063548c34e57df4 (patch) | |
tree | 13eb69261b19080a14a99db8277615a640508360 | |
parent | 00cb2804918480d288e7ca02961698d5a15e76bb (diff) |
UWP: Enable gamepad support and update keyboard support (nw)
-rw-r--r-- | src/osd/modules/input/input_common.cpp | 14 | ||||
-rw-r--r-- | src/osd/modules/input/input_common.h | 22 | ||||
-rw-r--r-- | src/osd/modules/input/input_uwp.cpp | 565 | ||||
-rw-r--r-- | src/osd/modules/lib/osdobj_common.cpp | 1 |
4 files changed, 530 insertions, 72 deletions
diff --git a/src/osd/modules/input/input_common.cpp b/src/osd/modules/input/input_common.cpp index e9844d99291..50500aea82e 100644 --- a/src/osd/modules/input/input_common.cpp +++ b/src/osd/modules/input/input_common.cpp @@ -37,8 +37,8 @@ #define KEY_TRANS_ENTRY0(mame, sdlsc, sdlkey, disc, virtual, uwp, ascii, UI) { ITEM_ID_##mame, SDL_SCANCODE_ ## sdlsc, SDLK_ ## sdlkey, ascii, "ITEM_ID_"#mame, (char *) UI } #define KEY_TRANS_ENTRY1(mame, sdlsc, sdlkey, disc, virtual, uwp, ascii) { ITEM_ID_##mame, SDL_SCANCODE_ ## sdlsc, SDLK_ ## sdlkey, ascii, "ITEM_ID_"#mame, (char*) #mame } #elif defined(OSD_UWP) -#define KEY_TRANS_ENTRY0(mame, sdlsc, sdlkey, disc, virtual, uwp, ascii, UI) { ITEM_ID_##mame, Windows::System::VirtualKey:: ## uwp, ascii, "ITEM_ID_"#mame, (char *) UI } -#define KEY_TRANS_ENTRY1(mame, sdlsc, sdlkey, disc, virtual, uwp, ascii) { ITEM_ID_##mame, Windows::System::VirtualKey:: ## uwp, ascii, "ITEM_ID_"#mame, (char*) #mame } +#define KEY_TRANS_ENTRY0(mame, sdlsc, sdlkey, disc, virtual, uwp, ascii, UI) { ITEM_ID_##mame, KEY_ ## disc, Windows::System::VirtualKey:: ## uwp, ascii, "ITEM_ID_"#mame, (char *) UI } +#define KEY_TRANS_ENTRY1(mame, sdlsc, sdlkey, disc, virtual, uwp, ascii) { ITEM_ID_##mame, KEY_ ## disc, Windows::System::VirtualKey:: ## uwp, ascii, "ITEM_ID_"#mame, (char*) #mame } #else // osd mini #endif @@ -227,7 +227,7 @@ 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(OSD_UWP) input_item_id keyboard_trans_table::map_di_scancode_to_itemid(int scancode) const { @@ -242,6 +242,10 @@ input_item_id keyboard_trans_table::map_di_scancode_to_itemid(int scancode) cons return ITEM_ID_OTHER_SWITCH; } +#endif + +#if defined(OSD_WINDOWS) + //============================================================ // wininput_vkey_for_mame_code //============================================================ @@ -262,7 +266,9 @@ int keyboard_trans_table::vkey_for_mame_code(input_code code) const return 0; } -#elif defined(OSD_UWP) +#endif + +#if defined(OSD_UWP) input_item_id keyboard_trans_table::map_vkey_to_itemid(Windows::System::VirtualKey vkey) const { diff --git a/src/osd/modules/input/input_common.h b/src/osd/modules/input/input_common.h index e2df2593b2d..10dbf85d023 100644 --- a/src/osd/modules/input/input_common.h +++ b/src/osd/modules/input/input_common.h @@ -337,6 +337,12 @@ public: // allocate the device object auto devinfo = std::make_unique<TActual>(machine, name, id, module, std::forward<TArgs>(args)...); + return add_device(machine, std::move(devinfo)); + } + + template <typename TActual> + TActual* add_device(running_machine &machine, std::unique_ptr<TActual> devinfo) + { // Add the device to the machine devinfo->m_device = machine.input().device_class(devinfo->deviceclass()).add_device(devinfo->name(), devinfo->id(), devinfo.get()); @@ -359,6 +365,7 @@ struct key_trans_entry { int scan_code; unsigned char virtual_key; #elif defined(OSD_UWP) + int scan_code; Windows::System::VirtualKey virtual_key; #endif @@ -394,6 +401,7 @@ public: input_item_id map_di_scancode_to_itemid(int di_scancode) const; int vkey_for_mame_code(input_code code) const; #elif defined(OSD_UWP) + input_item_id map_di_scancode_to_itemid(int di_scancode) const; input_item_id map_vkey_to_itemid(Windows::System::VirtualKey vkey) const; #endif @@ -564,26 +572,26 @@ const char *const default_axis_name[] = "RY", "RZ", "SL1", "SL2" }; -inline static int32_t normalize_absolute_axis(int32_t raw, int32_t rawmin, int32_t rawmax) +inline static int32_t normalize_absolute_axis(double raw, double rawmin, double rawmax) { - int32_t center = (rawmax + rawmin) / 2; + double center = (rawmax + rawmin) / 2.0; // make sure we have valid data if (rawmin >= rawmax) - return raw; + return int32_t(raw); // above center if (raw >= center) { - int32_t result = (int64_t)(raw - center) * (int64_t)INPUT_ABSOLUTE_MAX / (int64_t)(rawmax - center); - return std::min(result, INPUT_ABSOLUTE_MAX); + double result = (raw - center) * INPUT_ABSOLUTE_MAX / (rawmax - center); + return std::min(result, (double)INPUT_ABSOLUTE_MAX); } // below center else { - int32_t result = -((int64_t)(center - raw) * (int64_t)-INPUT_ABSOLUTE_MIN / (int64_t)(center - rawmin)); - return std::max(result, INPUT_ABSOLUTE_MIN); + double result = -((center - raw) * (double)-INPUT_ABSOLUTE_MIN / (center - rawmin)); + return std::max(result, (double)INPUT_ABSOLUTE_MIN); } } diff --git a/src/osd/modules/input/input_uwp.cpp b/src/osd/modules/input/input_uwp.cpp index 7291e3e2a71..bee9e2367ee 100644 --- a/src/osd/modules/input/input_uwp.cpp +++ b/src/osd/modules/input/input_uwp.cpp @@ -21,141 +21,584 @@ // MAME headers #include "emu.h" #include "uiinput.h" +#include "strconv.h" // MAMEOS headers #include "winmain.h" #include "input_common.h" #include "input_windows.h" +#define UWP_BUTTON_COUNT 32 + using namespace concurrency; using namespace Windows::UI::Core; using namespace Windows::Foundation; using namespace Windows::Foundation::Collections; +using namespace Windows::Gaming::Input; + +//============================================================ +// UWP Base device/module implementation +//============================================================ + +//============================================================ +// UwpInputDevice - base class for implementing an input +// device in C++/CX. To be used with uwp_input_device +//============================================================ -// This device is purely event driven so the implementation is in the module -class uwp_keyboard_device : public event_based_device<KeyPressEventArgs> +private ref class UwpInputDevice { +private: + running_machine & m_machine; + std::string m_name; + std::string m_id; + input_device_class m_devclass; + input_module & m_module; + input_device *m_inputdevice; + +internal: + UwpInputDevice(running_machine &machine, const char *name, const char *id, input_device_class deviceclass, input_module &module) + : m_machine(machine), + m_name(name), + m_id(id), + m_devclass(deviceclass), + m_module(module), + m_inputdevice(nullptr) + { + } + + property running_machine & Machine + { + running_machine & get() { return m_machine; } + } + + property const std::string & Name + { + const std::string & get() { return m_name; } + } + + property const std::string & Id + { + const std::string & get() { return m_id; } + } + + property input_device_class DeviceClass + { + input_device_class get() { return m_devclass; } + } + + property input_module & Module + { + input_module & get() { return m_module; } + } + + property input_device* InputDevice + { + input_device* get() { return m_inputdevice; } + void set(input_device* value) { m_inputdevice = value; } + } + + virtual void Poll() + { + } + + virtual void Reset() + { + } +}; + +//============================================================ +// uwp_input_device - a device that can be used to wrap a +// C++/CX ref class for an input device implementation +//============================================================ + +class uwp_input_device : public device_info +{ +private: + UwpInputDevice ^m_wrapped_device; + public: - keyboard_state keyboard; + uwp_input_device(UwpInputDevice ^device) + : device_info(device->Machine, device->Name.c_str(), device->Id.c_str(), device->DeviceClass, device->Module), + m_wrapped_device(device) + { + } - uwp_keyboard_device(running_machine& machine, const char *name, const char *id, input_module &module) - : event_based_device(machine, name, id, DEVICE_CLASS_KEYBOARD, module), - keyboard({{0}}) + void poll() override { + m_wrapped_device->Poll(); } void reset() override { - memset(&keyboard, 0, sizeof(keyboard)); + m_wrapped_device->Reset(); } +}; -protected: - void process_event(KeyPressEventArgs &args) override +//============================================================ +// UwpInputModule - a base class that can be used to +// implement an input module with a C++/CX class. +// normally used with uwp_wininput_module +//============================================================ + +class uwp_input_module; + +private ref class UwpInputModule +{ +private: + const std::string m_type; + const std::string m_name; + uwp_input_module *m_module; + +internal: + UwpInputModule(const char *type, const char *name) + : m_type(type), + m_name(name), + m_module(nullptr) + { + } + + property const std::string & Type + { + const std::string & get() { return m_type; } + } + + property const std::string & Name + { + const std::string & get() { return m_name; } + } + + property uwp_input_module * NativeModule + { + uwp_input_module * get() { return m_module; } + void set(uwp_input_module * value) { m_module = value; } + } + + virtual void input_init(running_machine &machine) + { + } +}; + +//============================================================ +// uwp_input_module - an input module that can be +// used to create an input module with a C++/CX ref class +//============================================================ + +class uwp_input_module : public wininput_module +{ +private: + UwpInputModule^ m_refmodule; + +public: + uwp_input_module(UwpInputModule^ refmodule) + : wininput_module(refmodule->Type.c_str(), refmodule->Name.c_str()), + m_refmodule(refmodule) + { + refmodule->NativeModule = this; + } + + void input_init(running_machine &machine) override { - keyboard.state[args.vkey] = args.event_id == INPUT_EVENT_KEYDOWN ? 0x80 : 0x00; + m_refmodule->input_init(machine); } }; -private ref class key_processor sealed +//============================================================ +// UWP Keyboard Implementation +//============================================================ + +//============================================================ +// UwpKeyboardDevice +//============================================================ + +private ref class UwpKeyboardDevice : public UwpInputDevice { private: - Platform::Agile<CoreWindow^> m_window; - input_device_list &m_devicelist; - running_machine &m_machine; + keyboard_state keyboard; + Platform::Agile<CoreWindow> m_coreWindow; internal: - key_processor(CoreWindow^ window, input_device_list &devicelist, running_machine &machine) - : m_window(window), - m_devicelist(devicelist), - m_machine(machine) + UwpKeyboardDevice(CoreWindow ^coreWindow, running_machine& machine, char *name, const char *id, input_module &module) + : UwpInputDevice(machine, name, id, DEVICE_CLASS_KEYBOARD, module), + keyboard({{0}}), + m_coreWindow(coreWindow) { - m_window->KeyDown += ref new TypedEventHandler<CoreWindow^, KeyEventArgs^>(this, &key_processor::OnKeyDown); - m_window->KeyUp += ref new TypedEventHandler<CoreWindow^, KeyEventArgs^>(this, &key_processor::OnKeyUp); - m_window->CharacterReceived += ref new TypedEventHandler<CoreWindow^, CharacterReceivedEventArgs^>(this, &key_processor::OnCharacterReceived); + coreWindow->KeyDown += ref new TypedEventHandler<CoreWindow^, KeyEventArgs^>(this, &UwpKeyboardDevice::OnKeyDown); + coreWindow->KeyUp += ref new TypedEventHandler<CoreWindow^, KeyEventArgs^>(this, &UwpKeyboardDevice::OnKeyUp); + coreWindow->CharacterReceived += ref new TypedEventHandler<CoreWindow^, CharacterReceivedEventArgs^>(this, &UwpKeyboardDevice::OnCharacterReceived); } - void OnKeyDown(CoreWindow^ win, KeyEventArgs^ args) + void Reset() override { - auto &table = keyboard_trans_table::instance(); + memset(&keyboard, 0, sizeof(keyboard)); + } - //if (args->VirtualKey < Windows::System::VirtualKey::Space) - // m_machine.ui_input().push_char_event(osd_common_t::s_window_list.front()->target(), static_cast<char32_t>(args->VirtualKey)); + void Configure() + { + keyboard_trans_table &table = keyboard_trans_table::instance(); + + char keyname[256]; - KeyPressEventArgs tmp; - tmp.event_id = INPUT_EVENT_KEYDOWN; - tmp.vkey = uint8_t(args->VirtualKey); - m_devicelist.for_each_device([&tmp](device_info *device) + // populate it + for (int keynum = 0; keynum < MAX_KEYS; keynum++) { - static_cast<uwp_keyboard_device*>(device)->queue_events(&tmp, 1); - }); + input_item_id itemid = table.map_di_scancode_to_itemid(keynum); + + //if (GetKeyNameTextA(((keynum & 0x7f) << 16) | ((keynum & 0x80) << 17), keyname, ARRAY_LENGTH(keyname)) == 0) + snprintf(keyname, ARRAY_LENGTH(keyname), "Scan%03d", keynum); + + // add the item to the device + this->InputDevice->add_item(keyname, itemid, generic_button_get_state<std::uint8_t>, &keyboard.state[keynum]); + } + } + + void OnKeyDown(CoreWindow^ win, KeyEventArgs^ args) + { + CorePhysicalKeyStatus status = args->KeyStatus; + int discancode = (status.ScanCode & 0x7f) | (status.IsExtendedKey ? 0x80 : 0x00); + keyboard.state[discancode] = 0x80; } void OnKeyUp(CoreWindow^ win, KeyEventArgs^ args) { - KeyPressEventArgs tmp; - tmp.event_id = INPUT_EVENT_KEYUP; - tmp.vkey = uint8_t(args->VirtualKey); - m_devicelist.for_each_device([&tmp](device_info *device) - { - static_cast<uwp_keyboard_device*>(device)->queue_events(&tmp, 1); - }); + CorePhysicalKeyStatus status = args->KeyStatus; + int discancode = (status.ScanCode & 0x7f) | (status.IsExtendedKey ? 0x80 : 0x00); + keyboard.state[discancode] = 0; } void OnCharacterReceived(CoreWindow ^sender, CharacterReceivedEventArgs ^args) { - m_machine.ui_input().push_char_event(osd_common_t::s_window_list.front()->target(), args->KeyCode); + this->Machine.ui_input().push_char_event(osd_common_t::s_window_list.front()->target(), args->KeyCode); } }; //============================================================ -// uwp_keyboard_module +// UwpKeyboardModule //============================================================ -class uwp_keyboard_module : public wininput_module +private ref class UwpKeyboardModule : public UwpInputModule { private: - key_processor^ m_key_processor; + running_machine *m_machine; -public: - uwp_keyboard_module() - : wininput_module(OSD_KEYBOARDINPUT_PROVIDER, "uwp"), - m_key_processor(nullptr) +internal: + UwpKeyboardModule() + : UwpInputModule(OSD_KEYBOARDINPUT_PROVIDER, "uwp") { } - virtual void input_init(running_machine &machine) override + void input_init(running_machine &machine) override { auto first_window = std::static_pointer_cast<uwp_window_info>(osd_common_t::s_window_list.front()); - m_key_processor = ref new key_processor(first_window->uwp_window(), *devicelist(), machine); + CoreWindow ^coreWindow = first_window->uwp_window(); - // Add a single UWP keyboard device - uwp_keyboard_device *devinfo = devicelist()->create_device<uwp_keyboard_device>(machine, "UWP Keyboard 1", "UWP Keyboard 1", *this); + uwp_input_device *devinfo; - keyboard_trans_table &table = keyboard_trans_table::instance(); + // allocate the UWP implementation of the device object + UwpKeyboardDevice ^refdevice = ref new UwpKeyboardDevice(coreWindow, machine, "UWP Keyboard 1", "UWP Keyboard 1", *this->NativeModule); - // populate it - for (int keynum = 0; keynum < MAX_KEYS; keynum++) + // Allocate the wrapper and add it to the list + auto created_devinfo = std::make_unique<uwp_input_device>(refdevice); + devinfo = NativeModule->devicelist()->add_device<uwp_input_device>(machine, std::move(created_devinfo)); + + // Give the UWP implementation a handle to the input_device + refdevice->InputDevice = devinfo->device(); + + // Configure the device + refdevice->Configure(); + } +}; + +//============================================================ +// uwp_keyboard_module +//============================================================ + +class uwp_keyboard_module : public uwp_input_module +{ +public: + uwp_keyboard_module() + : uwp_input_module(ref new UwpKeyboardModule()) + { + } +}; + +// default axis names +static const char *const uwp_axis_name[] = +{ + "LSX", + "LSY", + "RSX", + "RSY" +}; + +static const input_item_id uwp_axis_ids[] = +{ + ITEM_ID_XAXIS, + ITEM_ID_YAXIS, + ITEM_ID_RXAXIS, + ITEM_ID_RYAXIS +}; + +struct gamepad_state +{ + BYTE buttons[UWP_BUTTON_COUNT]; + LONG left_trigger; + LONG right_trigger; + LONG left_thumb_x; + LONG left_thumb_y; + LONG right_thumb_x; + LONG right_thumb_y; +}; + +// Maps different UWP GameControllerButtonLabels to a halfway-sane input_item_id in many cases +static input_item_id buttonlabel_to_itemid[] = +{ + input_item_id::ITEM_ID_INVALID, // GameControllerButtonLabel::None + input_item_id::ITEM_ID_SELECT, // GameControllerButtonLabel::XboxBack + input_item_id::ITEM_ID_START, // GameControllerButtonLabel::XboxStart + input_item_id::ITEM_ID_START, // GameControllerButtonLabel::XboxMenu + input_item_id::ITEM_ID_SELECT, // GameControllerButtonLabel::XboxView + input_item_id::ITEM_ID_HAT1UP, // GameControllerButtonLabel::XboxUp + input_item_id::ITEM_ID_HAT1DOWN, // GameControllerButtonLabel::XboxDown + input_item_id::ITEM_ID_HAT1LEFT, // GameControllerButtonLabel::XboxLeft + input_item_id::ITEM_ID_HAT1RIGHT, // GameControllerButtonLabel::XboxRight + input_item_id::ITEM_ID_BUTTON1, // GameControllerButtonLabel::XboxA + input_item_id::ITEM_ID_BUTTON2, // GameControllerButtonLabel::XboxB + input_item_id::ITEM_ID_BUTTON3, // GameControllerButtonLabel::XboxX + input_item_id::ITEM_ID_BUTTON4, // GameControllerButtonLabel::XboxY + input_item_id::ITEM_ID_BUTTON5, // GameControllerButtonLabel::XboxLeftBumper + input_item_id::ITEM_ID_ZAXIS, // GameControllerButtonLabel::XboxLeftTrigger + input_item_id::ITEM_ID_BUTTON7, // GameControllerButtonLabel::XboxLeftStickButton + input_item_id::ITEM_ID_BUTTON6, // GameControllerButtonLabel::XboxRightBumper + input_item_id::ITEM_ID_RZAXIS, // GameControllerButtonLabel::XboxRightTrigger + input_item_id::ITEM_ID_BUTTON8, // GameControllerButtonLabel::XboxRightStickButton + input_item_id::ITEM_ID_BUTTON9, // GameControllerButtonLabel::XboxPaddle1 + input_item_id::ITEM_ID_BUTTON10, // GameControllerButtonLabel::XboxPaddle2 + input_item_id::ITEM_ID_BUTTON11, // GameControllerButtonLabel::XboxPaddle3 + input_item_id::ITEM_ID_BUTTON12, // GameControllerButtonLabel::XboxPaddle4 + input_item_id::ITEM_ID_INVALID, // GameControllerButtonLabel_Mode + input_item_id::ITEM_ID_SELECT, // GameControllerButtonLabel_Select + input_item_id::ITEM_ID_START, // GameControllerButtonLabel_Menu + input_item_id::ITEM_ID_SELECT, // GameControllerButtonLabel_View + input_item_id::ITEM_ID_SELECT, // GameControllerButtonLabel_Back + input_item_id::ITEM_ID_START, // GameControllerButtonLabel_Start + input_item_id::ITEM_ID_OTHER_SWITCH, // GameControllerButtonLabel_Options + input_item_id::ITEM_ID_OTHER_SWITCH, // GameControllerButtonLabel_Share + input_item_id::ITEM_ID_OTHER_SWITCH, // GameControllerButtonLabel_Up + input_item_id::ITEM_ID_OTHER_SWITCH, // GameControllerButtonLabel_Down + input_item_id::ITEM_ID_OTHER_SWITCH, // GameControllerButtonLabel_Left + input_item_id::ITEM_ID_OTHER_SWITCH, // GameControllerButtonLabel_Right + input_item_id::ITEM_ID_BUTTON1, // GameControllerButtonLabel_LetterA + input_item_id::ITEM_ID_BUTTON2, // GameControllerButtonLabel_LetterB + input_item_id::ITEM_ID_OTHER_SWITCH, // GameControllerButtonLabel_LetterC + input_item_id::ITEM_ID_OTHER_SWITCH, // GameControllerButtonLabel_LetterL + input_item_id::ITEM_ID_OTHER_SWITCH, // GameControllerButtonLabel_LetterR + input_item_id::ITEM_ID_BUTTON3, // GameControllerButtonLabel_LetterX + input_item_id::ITEM_ID_BUTTON4, // GameControllerButtonLabel_LetterY + input_item_id::ITEM_ID_OTHER_SWITCH, // GameControllerButtonLabel_LetterZ + input_item_id::ITEM_ID_OTHER_SWITCH, // GameControllerButtonLabel_Cross + input_item_id::ITEM_ID_OTHER_SWITCH, // GameControllerButtonLabel_Circle + input_item_id::ITEM_ID_OTHER_SWITCH, // GameControllerButtonLabel_Square + input_item_id::ITEM_ID_OTHER_SWITCH, // GameControllerButtonLabel_Triangle + input_item_id::ITEM_ID_BUTTON5, // GameControllerButtonLabel_LeftBumper + input_item_id::ITEM_ID_ZAXIS, // GameControllerButtonLabel_LeftTrigger + input_item_id::ITEM_ID_BUTTON7, // GameControllerButtonLabel_LeftStickButton + input_item_id::ITEM_ID_OTHER_SWITCH, // GameControllerButtonLabel_Left1 + input_item_id::ITEM_ID_OTHER_SWITCH, // GameControllerButtonLabel_Left2 + input_item_id::ITEM_ID_OTHER_SWITCH, // GameControllerButtonLabel_Left3 + input_item_id::ITEM_ID_BUTTON6, // GameControllerButtonLabel_RightBumper + input_item_id::ITEM_ID_RZAXIS, // GameControllerButtonLabel_RightTrigger + input_item_id::ITEM_ID_BUTTON8, // GameControllerButtonLabel_RightStickButton + input_item_id::ITEM_ID_OTHER_SWITCH, // GameControllerButtonLabel_Right1 + input_item_id::ITEM_ID_OTHER_SWITCH, // GameControllerButtonLabel_Right2 + input_item_id::ITEM_ID_OTHER_SWITCH, // GameControllerButtonLabel_Right3 + input_item_id::ITEM_ID_BUTTON9, // GameControllerButtonLabel_Paddle1 + input_item_id::ITEM_ID_BUTTON10, // GameControllerButtonLabel_Paddle2 + input_item_id::ITEM_ID_BUTTON11, // GameControllerButtonLabel_Paddle3 + input_item_id::ITEM_ID_BUTTON12, // GameControllerButtonLabel_Paddle4 + input_item_id::ITEM_ID_OTHER_SWITCH, // GameControllerButtonLabel_Plus + input_item_id::ITEM_ID_OTHER_SWITCH, // GameControllerButtonLabel_Minus + input_item_id::ITEM_ID_OTHER_SWITCH, // GameControllerButtonLabel_DownLeftArrow + input_item_id::ITEM_ID_OTHER_SWITCH, // GameControllerButtonLabel_DialLeft + input_item_id::ITEM_ID_OTHER_SWITCH, // GameControllerButtonLabel_DialRight + input_item_id::ITEM_ID_OTHER_SWITCH, // GameControllerButtonLabel_Suspension +}; + +//============================================================ +// UwpJoystickDevice +//============================================================ + +private ref class UwpJoystickDevice : public UwpInputDevice +{ +private: + Gamepad ^m_pad; + bool m_configured; + gamepad_state state; + +internal: + UwpJoystickDevice(Gamepad^ pad, running_machine &machine, const char *name, const char *id, input_module &module) + : UwpInputDevice(machine, name, id, DEVICE_CLASS_JOYSTICK, module), + m_pad(pad), + m_configured(false), + state({0}) + {} + + void Poll() override + { + // If the device hasn't been configured, don't poll + if (!m_configured) + return; + + GamepadReading reading = m_pad->GetCurrentReading(); + + for (int butnum = 0; butnum < UWP_BUTTON_COUNT; butnum++) { - input_item_id itemid = table.map_vkey_to_itemid(Windows::System::VirtualKey(keynum)); - char name[20]; + GamepadButtons currentButton = GamepadButtons(1 << butnum); + state.buttons[butnum] = (reading.Buttons & currentButton) != GamepadButtons::None ? 0xFF : 0; + } - // generate/fetch the name - _snprintf(name, ARRAY_LENGTH(name), "Scan%03d", keynum); + // Now grab the axis values + // Each of the thumbstick axis members is a signed value between -32768 and 32767 describing the position of the thumbstick + // However, the Y axis values are inverted from what MAME expects, so negate the value + state.left_thumb_x = normalize_absolute_axis(reading.LeftThumbstickX, -1, 1); + state.left_thumb_y = -normalize_absolute_axis(reading.LeftThumbstickY, -1, 1); + state.right_thumb_x = normalize_absolute_axis(reading.RightThumbstickX, -1, 1); + state.right_thumb_y = -normalize_absolute_axis(reading.RightThumbstickY, -1, 1); - // add the item to the device - devinfo->device()->add_item(name, itemid, generic_button_get_state<std::uint8_t>, &devinfo->keyboard.state[keynum]); + // Get the trigger values + state.left_trigger = normalize_absolute_axis(reading.LeftTrigger, 0.0, 1.0); + state.right_trigger = normalize_absolute_axis(reading.RightTrigger, 0.0, 1.0); + } + + void Configure() + { + // If the device has already been configured, don't do it again + if (m_configured) + return; + + GamepadReading r = m_pad->GetCurrentReading(); + + // Add the axes + for (int axisnum = 0; axisnum < 4; axisnum++) + { + this->InputDevice->add_item( + uwp_axis_name[axisnum], + uwp_axis_ids[axisnum], + generic_axis_get_state<LONG>, + &state.left_thumb_x + axisnum); + } + + // populate the buttons + for (int butnum = 0; butnum < UWP_BUTTON_COUNT; butnum++) + { + GamepadButtons button = GamepadButtons(1 << butnum); + auto label = m_pad->GetButtonLabel(button); + if (label != GameControllerButtonLabel::None) + { + std::string desc = osd::text::from_wstring(label.ToString()->Data()); + this->InputDevice->add_item( + desc.c_str(), + buttonlabel_to_itemid[static_cast<int>(label)], + generic_button_get_state<BYTE>, + &state.buttons[butnum]); + } } + + this->InputDevice->add_item( + "Left Trigger", + ITEM_ID_ZAXIS, + generic_axis_get_state<LONG>, + &state.left_trigger); + + this->InputDevice->add_item( + "Right Trigger", + ITEM_ID_RZAXIS, + generic_axis_get_state<LONG>, + &state.right_trigger); + + m_configured = true; + } +}; + +//============================================================ +// UwpJoystickModule +//============================================================ + +private ref class UwpJoystickModule : public UwpInputModule +{ +internal: + UwpJoystickModule() + : UwpInputModule(OSD_JOYSTICKINPUT_PROVIDER, "uwp") + { + } + + void input_init(running_machine &machine) override + { + PerformGamepadDiscovery(); + + auto pads = Gamepad::Gamepads; + + int padindex = 0; + std::for_each(begin(pads), end(pads), [&](Gamepad^ pad) + { + uwp_input_device *devinfo; + + std::ostringstream namestream; + namestream << "UWP Gamepad " << (padindex + 1); + + auto name = namestream.str(); + + // allocate the UWP implementation of the device object + UwpJoystickDevice ^refdevice = ref new UwpJoystickDevice(pad, machine, name.c_str(), name.c_str(), *this->NativeModule); + + // Allocate the wrapper and add it to the list + auto created_devinfo = std::make_unique<uwp_input_device>(refdevice); + devinfo = NativeModule->devicelist()->add_device<uwp_input_device>(machine, std::move(created_devinfo)); + + // Give the UWP implementation a handle to the input_device + refdevice->InputDevice = devinfo->device(); + + // Configure the device + refdevice->Configure(); + + padindex++; + }); } - void exit() override +private: + void PerformGamepadDiscovery() + { + Gamepad::GamepadAdded += ref new EventHandler<Gamepad ^>(this, &UwpJoystickModule::OnGamepadAdded); + auto start = std::chrono::system_clock::now(); + + // We need to pause a bit and pump events so gamepads get discovered + while (std::chrono::system_clock::now() - start < std::chrono::milliseconds(500)) + CoreWindow::GetForCurrentThread()->Dispatcher->ProcessEvents(CoreProcessEventsOption::ProcessAllIfPresent); + } + + void OnGamepadAdded(Platform::Object ^sender, Gamepad ^pad) + { + osd_printf_verbose("Input: UWP Compatible %s gamepad discovered.\n", pad->IsWireless ? "Wireless" : "Wired"); + } +}; + +//============================================================ +// uwp_joystick_module +//============================================================ + +class uwp_joystick_module : public uwp_input_module +{ +public: + uwp_joystick_module() + : uwp_input_module(ref new UwpJoystickModule()) { - m_key_processor = nullptr; } }; #else MODULE_NOT_SUPPORTED(uwp_keyboard_module, OSD_KEYBOARDINPUT_PROVIDER, "uwp") +MODULE_NOT_SUPPORTED(uwp_joystick_module, OSD_JOYSTICKINPUT_PROVIDER, "uwp") #endif MODULE_DEFINITION(KEYBOARDINPUT_UWP, uwp_keyboard_module) +MODULE_DEFINITION(JOYSTICKINPUT_UWP, uwp_joystick_module) diff --git a/src/osd/modules/lib/osdobj_common.cpp b/src/osd/modules/lib/osdobj_common.cpp index 04af8085514..d462e946587 100644 --- a/src/osd/modules/lib/osdobj_common.cpp +++ b/src/osd/modules/lib/osdobj_common.cpp @@ -260,6 +260,7 @@ void osd_common_t::register_options() REGISTER_MODULE(m_mod_man, JOYSTICKINPUT_WINHYBRID); REGISTER_MODULE(m_mod_man, JOYSTICKINPUT_DINPUT); REGISTER_MODULE(m_mod_man, JOYSTICKINPUT_XINPUT); + REGISTER_MODULE(m_mod_man, JOYSTICKINPUT_UWP); REGISTER_MODULE(m_mod_man, JOYSTICK_NONE); REGISTER_MODULE(m_mod_man, OUTPUT_NONE); |