From 94f346a1e0dfa585cffb9c8e5652f598cbee6943 Mon Sep 17 00:00:00 2001 From: flyinghead Date: Thu, 21 Feb 2019 17:57:51 +0100 Subject: [PATCH] win32: use new input system --- core/input/gamepad_device.cpp | 6 +- core/input/gamepad_device.h | 2 +- core/linux-dist/evdev_gamepad.h | 1 - core/rend/gui.cpp | 29 +++++--- core/windows/winmain.cpp | 40 ++-------- core/windows/xinput_gamepad.h | 127 ++++++++++++++++++++++++++++++++ 6 files changed, 155 insertions(+), 50 deletions(-) create mode 100644 core/windows/xinput_gamepad.h diff --git a/core/input/gamepad_device.cpp b/core/input/gamepad_device.cpp index 9b4b58620..49cdceaf8 100644 --- a/core/input/gamepad_device.cpp +++ b/core/input/gamepad_device.cpp @@ -55,10 +55,12 @@ bool GamepadDevice::gamepad_btn_input(u32 code, bool pressed) switch (key) { case EMU_BTN_ESCAPE: - dc_stop(); + if (pressed) + dc_stop(); break; case EMU_BTN_MENU: - gui_open_settings(); + if (pressed) + gui_open_settings(); break; case EMU_BTN_TRIGGER_LEFT: lt[_maple_port] = pressed ? 255 : 0; diff --git a/core/input/gamepad_device.h b/core/input/gamepad_device.h index 8aa1b776e..e96ca8815 100644 --- a/core/input/gamepad_device.h +++ b/core/input/gamepad_device.h @@ -51,7 +51,7 @@ public: } InputMapping *get_input_mapping() { return input_mapper; } void save_mapping(); - bool remappable() { return _remappable; } + bool remappable() { return _remappable && input_mapper != NULL; } static void Register(std::shared_ptr gamepad) { diff --git a/core/linux-dist/evdev_gamepad.h b/core/linux-dist/evdev_gamepad.h index 06bdf66ae..7609ccbfc 100644 --- a/core/linux-dist/evdev_gamepad.h +++ b/core/linux-dist/evdev_gamepad.h @@ -1,6 +1,5 @@ #include "../input/gamepad_device.h" #include "evdev.h" -#include "rend/gui.h" class EvdevGamepadDevice : public GamepadDevice { diff --git a/core/rend/gui.cpp b/core/rend/gui.cpp index c3daab2c7..398f38f0d 100644 --- a/core/rend/gui.cpp +++ b/core/rend/gui.cpp @@ -418,17 +418,21 @@ static void detect_input_popup(int index, bool analog) ImGui::Text("Time out in %d s", (int)(5 - (now - map_start_time))); if (mapped_code != -1) { - if (analog) + InputMapping *input_mapping = mapped_device->get_input_mapping(); + if (input_mapping != NULL) { - u32 previous_mapping = mapped_device->get_input_mapping()->get_axis_code(axis_keys[index]); - bool inverted = false; - if (previous_mapping != -1) - inverted = mapped_device->get_input_mapping()->get_axis_inverted(previous_mapping); - // FIXME Allow inverted to be set - mapped_device->get_input_mapping()->set_axis(axis_keys[index], mapped_code, inverted); + if (analog) + { + u32 previous_mapping = input_mapping->get_axis_code(axis_keys[index]); + bool inverted = false; + if (previous_mapping != -1) + inverted = input_mapping->get_axis_inverted(previous_mapping); + // FIXME Allow inverted to be set + input_mapping->set_axis(axis_keys[index], mapped_code, inverted); + } + else + input_mapping->set_button(button_keys[index], mapped_code); } - else - mapped_device->get_input_mapping()->set_button(button_keys[index], mapped_code); mapped_device = NULL; ImGui::CloseCurrentPopup(); } @@ -456,7 +460,8 @@ static void controller_mapping_popup(std::shared_ptr gamepad) - (col0_width + ImGui::GetStyle().ItemSpacing.x) - (ImGui::CalcTextSize("Map").x + ImGui::GetStyle().FramePadding.x * 2.0f + ImGui::GetStyle().ItemSpacing.x); - if (ImGui::Button("Done", ImVec2(100 * scaling, 30 * scaling))) + InputMapping *input_mapping = gamepad->get_input_mapping(); + if (input_mapping == NULL || ImGui::Button("Done", ImVec2(100 * scaling, 30 * scaling))) { ImGui::CloseCurrentPopup(); gamepad->save_mapping(); @@ -477,7 +482,7 @@ static void controller_mapping_popup(std::shared_ptr gamepad) ImGui::PushID(key_id); ImGui::Text("%s", button_names[j]); ImGui::NextColumn(); - u32 code = gamepad->get_input_mapping()->get_button_code(button_keys[j]); + u32 code = input_mapping->get_button_code(button_keys[j]); if (code != -1) ImGui::Text("%d", code); ImGui::NextColumn(); @@ -511,7 +516,7 @@ static void controller_mapping_popup(std::shared_ptr gamepad) ImGui::PushID(key_id); ImGui::Text("%s", axis_names[j]); ImGui::NextColumn(); - u32 code = gamepad->get_input_mapping()->get_axis_code(axis_keys[j]); + u32 code = input_mapping->get_axis_code(axis_keys[j]); if (code != -1) ImGui::Text("%d", code); ImGui::NextColumn(); diff --git a/core/windows/winmain.cpp b/core/windows/winmain.cpp index cb3a29537..4de253d66 100644 --- a/core/windows/winmain.cpp +++ b/core/windows/winmain.cpp @@ -2,6 +2,7 @@ #include "oslib\audiostream.h" #include "imgread\common.h" #include "rend\gui.h" +#include "xinput_gamepad.h" #define _WIN32_WINNT 0x0500 #include @@ -122,6 +123,7 @@ void os_SetupInput() #if DC_PLATFORM == DC_PLATFORM_DREAMCAST mcfg_CreateDevices(); #endif + XInputGamepadDevice::CreateDevices(); } LONG ExeptionHandler(EXCEPTION_POINTERS *ExceptionInfo) @@ -293,40 +295,10 @@ void UpdateInputState(u32 port) } void UpdateController(u32 port) - { - XINPUT_STATE state; - - if (XInputGetState(port, &state) == 0) - { - WORD xbutton = state.Gamepad.wButtons; - - if (xbutton & XINPUT_GAMEPAD_A) - kcode[port] &= ~key_CONT_A; - if (xbutton & XINPUT_GAMEPAD_B) - kcode[port] &= ~key_CONT_B; - if (xbutton & XINPUT_GAMEPAD_Y) - kcode[port] &= ~key_CONT_Y; - if (xbutton & XINPUT_GAMEPAD_X) - kcode[port] &= ~key_CONT_X; - - if (xbutton & XINPUT_GAMEPAD_START) - kcode[port] &= ~key_CONT_START; - - if (xbutton & XINPUT_GAMEPAD_DPAD_UP) - kcode[port] &= ~key_CONT_DPAD_UP; - if (xbutton & XINPUT_GAMEPAD_DPAD_DOWN) - kcode[port] &= ~key_CONT_DPAD_DOWN; - if (xbutton & XINPUT_GAMEPAD_DPAD_LEFT) - kcode[port] &= ~key_CONT_DPAD_LEFT; - if (xbutton & XINPUT_GAMEPAD_DPAD_RIGHT) - kcode[port] &= ~key_CONT_DPAD_RIGHT; - - lt[port] |= state.Gamepad.bLeftTrigger; - rt[port] |= state.Gamepad.bRightTrigger; - - joyx[port] |= state.Gamepad.sThumbLX / 257; - joyy[port] |= -state.Gamepad.sThumbLY / 257; - } +{ + std::shared_ptr gamepad = XInputGamepadDevice::GetXInputDevice(port); + if (gamepad != NULL) + gamepad->ReadInput(); } void UpdateVibration(u32 port, u32 value) diff --git a/core/windows/xinput_gamepad.h b/core/windows/xinput_gamepad.h new file mode 100644 index 000000000..14fca2d11 --- /dev/null +++ b/core/windows/xinput_gamepad.h @@ -0,0 +1,127 @@ +#include "../input/gamepad_device.h" +#include + +class XInputMapping : public InputMapping +{ +public: + XInputMapping() + { + name = "XInput"; + set_button(DC_BTN_A, XINPUT_GAMEPAD_A); + set_button(DC_BTN_B, XINPUT_GAMEPAD_B); + set_button(DC_BTN_X, XINPUT_GAMEPAD_X); + set_button(DC_BTN_Y, XINPUT_GAMEPAD_Y); + set_button(DC_DPAD_UP, XINPUT_GAMEPAD_DPAD_UP); + set_button(DC_DPAD_DOWN, XINPUT_GAMEPAD_DPAD_DOWN); + set_button(DC_DPAD_LEFT, XINPUT_GAMEPAD_DPAD_LEFT); + set_button(DC_DPAD_RIGHT, XINPUT_GAMEPAD_DPAD_RIGHT); + set_button(DC_BTN_START, XINPUT_GAMEPAD_START); + set_button(EMU_BTN_TRIGGER_LEFT, XINPUT_GAMEPAD_LEFT_SHOULDER); + set_button(EMU_BTN_TRIGGER_RIGHT, XINPUT_GAMEPAD_RIGHT_SHOULDER); + set_button(EMU_BTN_MENU, XINPUT_GAMEPAD_BACK); + set_axis(DC_AXIS_LT, 0, false); + set_axis(DC_AXIS_RT, 1, false); + set_axis(DC_AXIS_X, 2, false); + set_axis(DC_AXIS_Y, 3, false); + set_axis(DC_AXIS_X2, 4, false); + set_axis(DC_AXIS_Y2, 5, false); + dirty = false; + } +}; + +class XInputGamepadDevice : public GamepadDevice +{ +public: + XInputGamepadDevice(int maple_port, int xinput_port) + : GamepadDevice(maple_port, "xinput"), _xinput_port(xinput_port) + { + } + + void ReadInput() + { + XINPUT_STATE state; + + if (XInputGetState(_xinput_port, &state) == 0) + { + if (input_mapper == NULL) + Open(); + u32 xbutton = state.Gamepad.wButtons; + + for (int i = 0; i < 16; i++) + { + gamepad_btn_input(1 << i, (xbutton & (1 << i)) != 0); + } + gamepad_axis_input(0, state.Gamepad.bLeftTrigger); + gamepad_axis_input(1, state.Gamepad.bRightTrigger); + gamepad_axis_input(2, state.Gamepad.sThumbLX); + gamepad_axis_input(3, state.Gamepad.sThumbLY); + gamepad_axis_input(4, state.Gamepad.sThumbRX); + gamepad_axis_input(5, state.Gamepad.sThumbRY); + } + else if (input_mapper != NULL) + { + printf("xinput: Controller '%s' on port %d disconnected\n", _name.c_str(), _xinput_port); + GamepadDevice::Unregister(xinput_gamepads[_xinput_port]); + input_mapper = NULL; + } + } + + void Open() + { + JOYCAPS joycaps; + int rc = joyGetDevCaps(_xinput_port, &joycaps, sizeof(joycaps)); + if (rc != 0) + _name = "xinput" + std::to_string(_xinput_port); + else + _name = joycaps.szPname; + printf("xinput: Opened controller '%s' on port %d ", _name.c_str(), _xinput_port); + if (!find_mapping()) + { + input_mapper = new XInputMapping(); + input_mapper->name = _name + " mapping"; + save_mapping(); + printf("using default mapping\n"); + } + else + printf("using custom mapping '%s'\n", input_mapper->name.c_str()); + GamepadDevice::Register(xinput_gamepads[_xinput_port]); + } + + static void CreateDevices() + { + for (int port = 0; port < XUSER_MAX_COUNT; port++) + xinput_gamepads[port] = std::make_shared(port, port); + } + static void CloseDevices() + { + for (int port = 0; port < XUSER_MAX_COUNT; port++) + GamepadDevice::Unregister(xinput_gamepads[port]); + } + + static std::shared_ptr GetXInputDevice(int port) + { + return xinput_gamepads[port]; + } + +protected: + virtual void load_axis_min_max(u32 axis) override + { + if (axis == 0 || axis == 1) + { + axis_ranges[axis] = 255; + axis_min_values[axis] = 0; + } + else + { + axis_ranges[axis] = 65535; + axis_min_values[axis] = -32768; + } + } + +private: + + const int _xinput_port; + static std::vector> xinput_gamepads; +}; + +std::vector> XInputGamepadDevice::xinput_gamepads(XUSER_MAX_COUNT);