diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/core/hle/service/hid/controllers/npad.cpp | 42 | ||||
| -rw-r--r-- | src/input_common/CMakeLists.txt | 6 | ||||
| -rwxr-xr-x | src/input_common/analog_from_button.cpp | 3 | ||||
| -rw-r--r-- | src/input_common/gcadapter/gc_adapter.cpp | 350 | ||||
| -rw-r--r-- | src/input_common/gcadapter/gc_adapter.h | 116 | ||||
| -rw-r--r-- | src/input_common/gcadapter/gc_poller.cpp | 310 | ||||
| -rw-r--r-- | src/input_common/gcadapter/gc_poller.h | 59 | ||||
| -rw-r--r-- | src/input_common/keyboard.cpp | 13 | ||||
| -rw-r--r-- | src/input_common/main.cpp | 23 | ||||
| -rw-r--r-- | src/input_common/main.h | 9 | ||||
| -rw-r--r-- | src/input_common/motion_emu.cpp | 5 | ||||
| -rw-r--r-- | src/input_common/sdl/sdl_impl.cpp | 53 | ||||
| -rw-r--r-- | src/input_common/udp/client.cpp | 140 | ||||
| -rw-r--r-- | src/input_common/udp/client.h | 2 | ||||
| -rw-r--r-- | src/input_common/udp/protocol.h | 32 | ||||
| -rw-r--r-- | src/input_common/udp/udp.cpp | 18 | ||||
| -rw-r--r-- | src/yuzu/configuration/configure_input_player.cpp | 131 | ||||
| -rw-r--r-- | src/yuzu/configuration/configure_input_player.h | 8 |
18 files changed, 1159 insertions, 161 deletions
diff --git a/src/core/hle/service/hid/controllers/npad.cpp b/src/core/hle/service/hid/controllers/npad.cpp index c55d900e2..d92325cb5 100644 --- a/src/core/hle/service/hid/controllers/npad.cpp +++ b/src/core/hle/service/hid/controllers/npad.cpp | |||
| @@ -44,7 +44,7 @@ static Controller_NPad::NPadControllerType MapSettingsTypeToNPad(Settings::Contr | |||
| 44 | case Settings::ControllerType::RightJoycon: | 44 | case Settings::ControllerType::RightJoycon: |
| 45 | return Controller_NPad::NPadControllerType::JoyRight; | 45 | return Controller_NPad::NPadControllerType::JoyRight; |
| 46 | default: | 46 | default: |
| 47 | UNREACHABLE(); | 47 | UNREACHABLE(); |
| 48 | return Controller_NPad::NPadControllerType::JoyDual; | 48 | return Controller_NPad::NPadControllerType::JoyDual; |
| 49 | } | 49 | } |
| 50 | } | 50 | } |
| @@ -93,7 +93,10 @@ u32 Controller_NPad::IndexToNPad(std::size_t index) { | |||
| 93 | }; | 93 | }; |
| 94 | } | 94 | } |
| 95 | 95 | ||
| 96 | Controller_NPad::Controller_NPad(Core::System& system) : ControllerBase(system), system(system) {} | 96 | Controller_NPad::Controller_NPad(Core::System& system) |
| 97 | : ControllerBase(system), system(system) { | ||
| 98 | } | ||
| 99 | |||
| 97 | Controller_NPad::~Controller_NPad() = default; | 100 | Controller_NPad::~Controller_NPad() = default; |
| 98 | 101 | ||
| 99 | void Controller_NPad::InitNewlyAddedControler(std::size_t controller_idx) { | 102 | void Controller_NPad::InitNewlyAddedControler(std::size_t controller_idx) { |
| @@ -106,7 +109,7 @@ void Controller_NPad::InitNewlyAddedControler(std::size_t controller_idx) { | |||
| 106 | controller.device_type.raw = 0; | 109 | controller.device_type.raw = 0; |
| 107 | switch (controller_type) { | 110 | switch (controller_type) { |
| 108 | case NPadControllerType::None: | 111 | case NPadControllerType::None: |
| 109 | UNREACHABLE(); | 112 | UNREACHABLE(); |
| 110 | break; | 113 | break; |
| 111 | case NPadControllerType::Handheld: | 114 | case NPadControllerType::Handheld: |
| 112 | controller.joy_styles.handheld.Assign(1); | 115 | controller.joy_styles.handheld.Assign(1); |
| @@ -194,7 +197,8 @@ void Controller_NPad::OnInit() { | |||
| 194 | 197 | ||
| 195 | std::transform( | 198 | std::transform( |
| 196 | Settings::values.players.begin(), Settings::values.players.end(), | 199 | Settings::values.players.begin(), Settings::values.players.end(), |
| 197 | connected_controllers.begin(), [](const Settings::PlayerInput& player) { | 200 | connected_controllers.begin(), [](const Settings::PlayerInput& player) |
| 201 | { | ||
| 198 | return ControllerHolder{MapSettingsTypeToNPad(player.type), player.connected}; | 202 | return ControllerHolder{MapSettingsTypeToNPad(player.type), player.connected}; |
| 199 | }); | 203 | }); |
| 200 | 204 | ||
| @@ -238,7 +242,8 @@ void Controller_NPad::OnLoadInputDevices() { | |||
| 238 | } | 242 | } |
| 239 | } | 243 | } |
| 240 | 244 | ||
| 241 | void Controller_NPad::OnRelease() {} | 245 | void Controller_NPad::OnRelease() { |
| 246 | } | ||
| 242 | 247 | ||
| 243 | void Controller_NPad::RequestPadStateUpdate(u32 npad_id) { | 248 | void Controller_NPad::RequestPadStateUpdate(u32 npad_id) { |
| 244 | const auto controller_idx = NPadIdToIndex(npad_id); | 249 | const auto controller_idx = NPadIdToIndex(npad_id); |
| @@ -276,27 +281,31 @@ void Controller_NPad::RequestPadStateUpdate(u32 npad_id) { | |||
| 276 | pad_state.d_down.Assign(button_state[DDown - BUTTON_HID_BEGIN]->GetStatus()); | 281 | pad_state.d_down.Assign(button_state[DDown - BUTTON_HID_BEGIN]->GetStatus()); |
| 277 | 282 | ||
| 278 | pad_state.l_stick_right.Assign( | 283 | pad_state.l_stick_right.Assign( |
| 279 | analog_state[static_cast<std::size_t>(JoystickId::Joystick_Left)]->GetAnalogDirectionStatus( | 284 | analog_state[static_cast<std::size_t>(JoystickId::Joystick_Left)]-> |
| 285 | GetAnalogDirectionStatus( | ||
| 280 | Input::AnalogDirection::RIGHT)); | 286 | Input::AnalogDirection::RIGHT)); |
| 281 | pad_state.l_stick_left.Assign( | 287 | pad_state.l_stick_left.Assign( |
| 282 | analog_state[static_cast<std::size_t>(JoystickId::Joystick_Left)]->GetAnalogDirectionStatus( | 288 | analog_state[static_cast<std::size_t>(JoystickId::Joystick_Left)]-> |
| 289 | GetAnalogDirectionStatus( | ||
| 283 | Input::AnalogDirection::LEFT)); | 290 | Input::AnalogDirection::LEFT)); |
| 284 | pad_state.l_stick_up.Assign( | 291 | pad_state.l_stick_up.Assign( |
| 285 | analog_state[static_cast<std::size_t>(JoystickId::Joystick_Left)]->GetAnalogDirectionStatus( | 292 | analog_state[static_cast<std::size_t>(JoystickId::Joystick_Left)]-> |
| 293 | GetAnalogDirectionStatus( | ||
| 286 | Input::AnalogDirection::UP)); | 294 | Input::AnalogDirection::UP)); |
| 287 | pad_state.l_stick_down.Assign( | 295 | pad_state.l_stick_down.Assign( |
| 288 | analog_state[static_cast<std::size_t>(JoystickId::Joystick_Left)]->GetAnalogDirectionStatus( | 296 | analog_state[static_cast<std::size_t>(JoystickId::Joystick_Left)]-> |
| 297 | GetAnalogDirectionStatus( | ||
| 289 | Input::AnalogDirection::DOWN)); | 298 | Input::AnalogDirection::DOWN)); |
| 290 | 299 | ||
| 291 | pad_state.r_stick_right.Assign( | 300 | pad_state.r_stick_right.Assign( |
| 292 | analog_state[static_cast<std::size_t>(JoystickId::Joystick_Right)] | 301 | analog_state[static_cast<std::size_t>(JoystickId::Joystick_Right)] |
| 293 | ->GetAnalogDirectionStatus(Input::AnalogDirection::RIGHT)); | 302 | ->GetAnalogDirectionStatus(Input::AnalogDirection::RIGHT)); |
| 294 | pad_state.r_stick_left.Assign(analog_state[static_cast<std::size_t>(JoystickId::Joystick_Right)] | 303 | pad_state.r_stick_left.Assign(analog_state[static_cast<std::size_t>(JoystickId::Joystick_Right)] |
| 295 | ->GetAnalogDirectionStatus(Input::AnalogDirection::LEFT)); | 304 | ->GetAnalogDirectionStatus(Input::AnalogDirection::LEFT)); |
| 296 | pad_state.r_stick_up.Assign(analog_state[static_cast<std::size_t>(JoystickId::Joystick_Right)] | 305 | pad_state.r_stick_up.Assign(analog_state[static_cast<std::size_t>(JoystickId::Joystick_Right)] |
| 297 | ->GetAnalogDirectionStatus(Input::AnalogDirection::UP)); | 306 | ->GetAnalogDirectionStatus(Input::AnalogDirection::UP)); |
| 298 | pad_state.r_stick_down.Assign(analog_state[static_cast<std::size_t>(JoystickId::Joystick_Right)] | 307 | pad_state.r_stick_down.Assign(analog_state[static_cast<std::size_t>(JoystickId::Joystick_Right)] |
| 299 | ->GetAnalogDirectionStatus(Input::AnalogDirection::DOWN)); | 308 | ->GetAnalogDirectionStatus(Input::AnalogDirection::DOWN)); |
| 300 | 309 | ||
| 301 | pad_state.left_sl.Assign(button_state[SL - BUTTON_HID_BEGIN]->GetStatus()); | 310 | pad_state.left_sl.Assign(button_state[SL - BUTTON_HID_BEGIN]->GetStatus()); |
| 302 | pad_state.left_sr.Assign(button_state[SR - BUTTON_HID_BEGIN]->GetStatus()); | 311 | pad_state.left_sr.Assign(button_state[SR - BUTTON_HID_BEGIN]->GetStatus()); |
| @@ -363,7 +372,7 @@ void Controller_NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* | |||
| 363 | 372 | ||
| 364 | switch (controller_type) { | 373 | switch (controller_type) { |
| 365 | case NPadControllerType::None: | 374 | case NPadControllerType::None: |
| 366 | UNREACHABLE(); | 375 | UNREACHABLE(); |
| 367 | break; | 376 | break; |
| 368 | case NPadControllerType::Handheld: | 377 | case NPadControllerType::Handheld: |
| 369 | handheld_entry.connection_status.raw = 0; | 378 | handheld_entry.connection_status.raw = 0; |
| @@ -459,8 +468,9 @@ void Controller_NPad::SetSupportedNPadIdTypes(u8* data, std::size_t length) { | |||
| 459 | continue; | 468 | continue; |
| 460 | } | 469 | } |
| 461 | const auto requested_controller = | 470 | const auto requested_controller = |
| 462 | i <= MAX_NPAD_ID ? MapSettingsTypeToNPad(Settings::values.players[i].type) | 471 | i <= MAX_NPAD_ID |
| 463 | : NPadControllerType::Handheld; | 472 | ? MapSettingsTypeToNPad(Settings::values.players[i].type) |
| 473 | : NPadControllerType::Handheld; | ||
| 464 | if (!IsControllerSupported(requested_controller)) { | 474 | if (!IsControllerSupported(requested_controller)) { |
| 465 | const auto is_handheld = requested_controller == NPadControllerType::Handheld; | 475 | const auto is_handheld = requested_controller == NPadControllerType::Handheld; |
| 466 | if (is_handheld) { | 476 | if (is_handheld) { |
diff --git a/src/input_common/CMakeLists.txt b/src/input_common/CMakeLists.txt index a9c2392b1..3bd76dd23 100644 --- a/src/input_common/CMakeLists.txt +++ b/src/input_common/CMakeLists.txt | |||
| @@ -7,6 +7,10 @@ add_library(input_common STATIC | |||
| 7 | main.h | 7 | main.h |
| 8 | motion_emu.cpp | 8 | motion_emu.cpp |
| 9 | motion_emu.h | 9 | motion_emu.h |
| 10 | gcadapter/gc_adapter.cpp | ||
| 11 | gcadapter/gc_adapter.h | ||
| 12 | gcadapter/gc_poller.cpp | ||
| 13 | gcadapter/gc_poller.h | ||
| 10 | sdl/sdl.cpp | 14 | sdl/sdl.cpp |
| 11 | sdl/sdl.h | 15 | sdl/sdl.h |
| 12 | udp/client.cpp | 16 | udp/client.cpp |
| @@ -26,5 +30,7 @@ if(SDL2_FOUND) | |||
| 26 | target_compile_definitions(input_common PRIVATE HAVE_SDL2) | 30 | target_compile_definitions(input_common PRIVATE HAVE_SDL2) |
| 27 | endif() | 31 | endif() |
| 28 | 32 | ||
| 33 | target_link_libraries(input_common PUBLIC ${LIBUSB_LIBRARIES}) | ||
| 34 | |||
| 29 | create_target_directory_groups(input_common) | 35 | create_target_directory_groups(input_common) |
| 30 | target_link_libraries(input_common PUBLIC core PRIVATE common Boost::boost) | 36 | target_link_libraries(input_common PUBLIC core PRIVATE common Boost::boost) |
diff --git a/src/input_common/analog_from_button.cpp b/src/input_common/analog_from_button.cpp index 6cabdaa3c..8116fcf9f 100755 --- a/src/input_common/analog_from_button.cpp +++ b/src/input_common/analog_from_button.cpp | |||
| @@ -14,7 +14,8 @@ public: | |||
| 14 | float modifier_scale_) | 14 | float modifier_scale_) |
| 15 | : up(std::move(up_)), down(std::move(down_)), left(std::move(left_)), | 15 | : up(std::move(up_)), down(std::move(down_)), left(std::move(left_)), |
| 16 | right(std::move(right_)), modifier(std::move(modifier_)), | 16 | right(std::move(right_)), modifier(std::move(modifier_)), |
| 17 | modifier_scale(modifier_scale_) {} | 17 | modifier_scale(modifier_scale_) { |
| 18 | } | ||
| 18 | 19 | ||
| 19 | std::tuple<float, float> GetStatus() const override { | 20 | std::tuple<float, float> GetStatus() const override { |
| 20 | constexpr float SQRT_HALF = 0.707106781f; | 21 | constexpr float SQRT_HALF = 0.707106781f; |
diff --git a/src/input_common/gcadapter/gc_adapter.cpp b/src/input_common/gcadapter/gc_adapter.cpp new file mode 100644 index 000000000..d42261d61 --- /dev/null +++ b/src/input_common/gcadapter/gc_adapter.cpp | |||
| @@ -0,0 +1,350 @@ | |||
| 1 | // Copyright 2014 Dolphin Emulator Project | ||
| 2 | // Licensed under GPLv2+ | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | //* | ||
| 5 | #include "common/logging/log.h" | ||
| 6 | #include "common/threadsafe_queue.h" | ||
| 7 | #include "input_common/gcadapter/gc_adapter.h" | ||
| 8 | |||
| 9 | Common::SPSCQueue<GCPadStatus> pad_queue[4]; | ||
| 10 | struct GCState state[4]; | ||
| 11 | |||
| 12 | namespace GCAdapter { | ||
| 13 | |||
| 14 | static libusb_device_handle* usb_adapter_handle = nullptr; | ||
| 15 | static u8 adapter_controllers_status[4] = { | ||
| 16 | ControllerTypes::CONTROLLER_NONE, ControllerTypes::CONTROLLER_NONE, | ||
| 17 | ControllerTypes::CONTROLLER_NONE, ControllerTypes::CONTROLLER_NONE}; | ||
| 18 | |||
| 19 | static std::mutex s_mutex; | ||
| 20 | |||
| 21 | static std::thread adapter_input_thread; | ||
| 22 | static bool adapter_thread_running; | ||
| 23 | |||
| 24 | static std::mutex initialization_mutex; | ||
| 25 | static std::thread detect_thread; | ||
| 26 | static bool detect_thread_running = false; | ||
| 27 | |||
| 28 | static libusb_context* libusb_ctx; | ||
| 29 | |||
| 30 | static u8 input_endpoint = 0; | ||
| 31 | |||
| 32 | static bool configuring = false; | ||
| 33 | |||
| 34 | GCPadStatus CheckStatus(int port, u8 adapter_payload[37]) { | ||
| 35 | GCPadStatus pad = {}; | ||
| 36 | bool get_origin = false; | ||
| 37 | |||
| 38 | u8 type = adapter_payload[1 + (9 * port)] >> 4; | ||
| 39 | if (type) | ||
| 40 | get_origin = true; | ||
| 41 | |||
| 42 | adapter_controllers_status[port] = type; | ||
| 43 | |||
| 44 | if (adapter_controllers_status[port] != ControllerTypes::CONTROLLER_NONE) { | ||
| 45 | u8 b1 = adapter_payload[1 + (9 * port) + 1]; | ||
| 46 | u8 b2 = adapter_payload[1 + (9 * port) + 2]; | ||
| 47 | |||
| 48 | if (b1 & (1 << 0)) | ||
| 49 | pad.button |= PAD_BUTTON_A; | ||
| 50 | if (b1 & (1 << 1)) | ||
| 51 | pad.button |= PAD_BUTTON_B; | ||
| 52 | if (b1 & (1 << 2)) | ||
| 53 | pad.button |= PAD_BUTTON_X; | ||
| 54 | if (b1 & (1 << 3)) | ||
| 55 | pad.button |= PAD_BUTTON_Y; | ||
| 56 | |||
| 57 | if (b1 & (1 << 4)) | ||
| 58 | pad.button |= PAD_BUTTON_LEFT; | ||
| 59 | if (b1 & (1 << 5)) | ||
| 60 | pad.button |= PAD_BUTTON_RIGHT; | ||
| 61 | if (b1 & (1 << 6)) | ||
| 62 | pad.button |= PAD_BUTTON_DOWN; | ||
| 63 | if (b1 & (1 << 7)) | ||
| 64 | pad.button |= PAD_BUTTON_UP; | ||
| 65 | |||
| 66 | if (b2 & (1 << 0)) | ||
| 67 | pad.button |= PAD_BUTTON_START; | ||
| 68 | if (b2 & (1 << 1)) | ||
| 69 | pad.button |= PAD_TRIGGER_Z; | ||
| 70 | if (b2 & (1 << 2)) | ||
| 71 | pad.button |= PAD_TRIGGER_R; | ||
| 72 | if (b2 & (1 << 3)) | ||
| 73 | pad.button |= PAD_TRIGGER_L; | ||
| 74 | |||
| 75 | if (get_origin) | ||
| 76 | pad.button |= PAD_GET_ORIGIN; | ||
| 77 | |||
| 78 | pad.stickX = adapter_payload[1 + (9 * port) + 3]; | ||
| 79 | pad.stickY = adapter_payload[1 + (9 * port) + 4]; | ||
| 80 | pad.substickX = adapter_payload[1 + (9 * port) + 5]; | ||
| 81 | pad.substickY = adapter_payload[1 + (9 * port) + 6]; | ||
| 82 | pad.triggerLeft = adapter_payload[1 + (9 * port) + 7]; | ||
| 83 | pad.triggerRight = adapter_payload[1 + (9 * port) + 8]; | ||
| 84 | } | ||
| 85 | return pad; | ||
| 86 | } | ||
| 87 | |||
| 88 | void PadToState(GCPadStatus pad, GCState& state) { | ||
| 89 | //std::lock_guard lock{s_mutex}; | ||
| 90 | state.buttons.insert_or_assign(PAD_BUTTON_A, pad.button & PAD_BUTTON_A); | ||
| 91 | state.buttons.insert_or_assign(PAD_BUTTON_B, pad.button & PAD_BUTTON_B); | ||
| 92 | state.buttons.insert_or_assign(PAD_BUTTON_X, pad.button & PAD_BUTTON_X); | ||
| 93 | state.buttons.insert_or_assign(PAD_BUTTON_Y, pad.button & PAD_BUTTON_Y); | ||
| 94 | state.buttons.insert_or_assign(PAD_BUTTON_LEFT, pad.button & PAD_BUTTON_LEFT); | ||
| 95 | state.buttons.insert_or_assign(PAD_BUTTON_RIGHT, pad.button & PAD_BUTTON_RIGHT); | ||
| 96 | state.buttons.insert_or_assign(PAD_BUTTON_DOWN, pad.button & PAD_BUTTON_DOWN); | ||
| 97 | state.buttons.insert_or_assign(PAD_BUTTON_UP, pad.button & PAD_BUTTON_UP); | ||
| 98 | state.buttons.insert_or_assign(PAD_BUTTON_START, pad.button & PAD_BUTTON_START); | ||
| 99 | state.buttons.insert_or_assign(PAD_TRIGGER_Z, pad.button & PAD_TRIGGER_Z); | ||
| 100 | state.buttons.insert_or_assign(PAD_TRIGGER_L, pad.button & PAD_TRIGGER_L); | ||
| 101 | state.buttons.insert_or_assign(PAD_TRIGGER_R, pad.button & PAD_TRIGGER_R); | ||
| 102 | state.axes.insert_or_assign(STICK_X, pad.stickX); | ||
| 103 | state.axes.insert_or_assign(STICK_Y, pad.stickY); | ||
| 104 | state.axes.insert_or_assign(SUBSTICK_X, pad.substickX); | ||
| 105 | state.axes.insert_or_assign(SUBSTICK_Y, pad.substickY); | ||
| 106 | state.axes.insert_or_assign(TRIGGER_LEFT, pad.triggerLeft); | ||
| 107 | state.axes.insert_or_assign(TRIGGER_RIGHT, pad.triggerRight); | ||
| 108 | } | ||
| 109 | |||
| 110 | static void Read() { | ||
| 111 | LOG_INFO(Input, "GC Adapter Read() thread started"); | ||
| 112 | |||
| 113 | int payload_size_in; | ||
| 114 | u8 adapter_payload[37]; | ||
| 115 | while (adapter_thread_running) { | ||
| 116 | libusb_interrupt_transfer(usb_adapter_handle, input_endpoint, adapter_payload, | ||
| 117 | sizeof(adapter_payload), &payload_size_in, 32); | ||
| 118 | |||
| 119 | int payload_size = 0; | ||
| 120 | u8 controller_payload_copy[37]; | ||
| 121 | |||
| 122 | { | ||
| 123 | std::lock_guard<std::mutex> lk(s_mutex); | ||
| 124 | std::copy(std::begin(adapter_payload), std::end(adapter_payload), | ||
| 125 | std::begin(controller_payload_copy)); | ||
| 126 | payload_size = payload_size_in; | ||
| 127 | } | ||
| 128 | |||
| 129 | GCPadStatus pad[4]; | ||
| 130 | if (payload_size != sizeof(controller_payload_copy) || | ||
| 131 | controller_payload_copy[0] != LIBUSB_DT_HID) { | ||
| 132 | LOG_ERROR(Input, "error reading payload (size: %d, type: %02x)", payload_size, | ||
| 133 | controller_payload_copy[0]); | ||
| 134 | } else { | ||
| 135 | for (int i = 0; i < 4; i++) | ||
| 136 | pad[i] = CheckStatus(i, controller_payload_copy); | ||
| 137 | } | ||
| 138 | for (int port = 0; port < 4; port++) { | ||
| 139 | if (DeviceConnected(port) && configuring) { | ||
| 140 | if (pad[port].button != PAD_GET_ORIGIN) | ||
| 141 | pad_queue[port].Push(pad[port]); | ||
| 142 | |||
| 143 | // Accounting for a threshold here because of some controller variance | ||
| 144 | if (pad[port].stickX > pad[port].MAIN_STICK_CENTER_X + pad[port].THRESHOLD || | ||
| 145 | pad[port].stickX < pad[port].MAIN_STICK_CENTER_X - pad[port].THRESHOLD) { | ||
| 146 | pad[port].axis_which = STICK_X; | ||
| 147 | pad[port].axis_value = pad[port].stickX; | ||
| 148 | pad_queue[port].Push(pad[port]); | ||
| 149 | } | ||
| 150 | if (pad[port].stickY > pad[port].MAIN_STICK_CENTER_Y + pad[port].THRESHOLD || | ||
| 151 | pad[port].stickY < pad[port].MAIN_STICK_CENTER_Y - pad[port].THRESHOLD) { | ||
| 152 | pad[port].axis_which = STICK_Y; | ||
| 153 | pad[port].axis_value = pad[port].stickY; | ||
| 154 | pad_queue[port].Push(pad[port]); | ||
| 155 | } | ||
| 156 | if (pad[port].substickX > pad[port].C_STICK_CENTER_X + pad[port].THRESHOLD || | ||
| 157 | pad[port].substickX < pad[port].C_STICK_CENTER_X - pad[port].THRESHOLD) { | ||
| 158 | pad[port].axis_which = SUBSTICK_X; | ||
| 159 | pad[port].axis_value = pad[port].substickX; | ||
| 160 | pad_queue[port].Push(pad[port]); | ||
| 161 | } | ||
| 162 | if (pad[port].substickY > pad[port].C_STICK_CENTER_Y + pad[port].THRESHOLD || | ||
| 163 | pad[port].substickY < pad[port].C_STICK_CENTER_Y - pad[port].THRESHOLD) { | ||
| 164 | pad[port].axis_which = SUBSTICK_Y; | ||
| 165 | pad[port].axis_value = pad[port].substickY; | ||
| 166 | pad_queue[port].Push(pad[port]); | ||
| 167 | } | ||
| 168 | } | ||
| 169 | PadToState(pad[port], state[port]); | ||
| 170 | } | ||
| 171 | std::this_thread::yield(); | ||
| 172 | } | ||
| 173 | } | ||
| 174 | |||
| 175 | static void ScanThreadFunc() { | ||
| 176 | LOG_INFO(Input, "GC Adapter scanning thread started"); | ||
| 177 | |||
| 178 | while (detect_thread_running) { | ||
| 179 | if (usb_adapter_handle == nullptr) { | ||
| 180 | std::lock_guard<std::mutex> lk(initialization_mutex); | ||
| 181 | Setup(); | ||
| 182 | } | ||
| 183 | Sleep(500); | ||
| 184 | } | ||
| 185 | } | ||
| 186 | |||
| 187 | void Init() { | ||
| 188 | |||
| 189 | if (usb_adapter_handle != nullptr) | ||
| 190 | return; | ||
| 191 | LOG_INFO(Input, "GC Adapter Initialization started"); | ||
| 192 | |||
| 193 | current_status = NO_ADAPTER_DETECTED; | ||
| 194 | libusb_init(&libusb_ctx); | ||
| 195 | |||
| 196 | StartScanThread(); | ||
| 197 | } | ||
| 198 | |||
| 199 | void StartScanThread() { | ||
| 200 | if (detect_thread_running) | ||
| 201 | return; | ||
| 202 | if (!libusb_ctx) | ||
| 203 | return; | ||
| 204 | |||
| 205 | detect_thread_running = true; | ||
| 206 | detect_thread = std::thread(ScanThreadFunc); | ||
| 207 | } | ||
| 208 | |||
| 209 | void StopScanThread() { | ||
| 210 | detect_thread.join(); | ||
| 211 | } | ||
| 212 | |||
| 213 | static void Setup() { | ||
| 214 | // Reset the error status in case the adapter gets unplugged | ||
| 215 | if (current_status < 0) | ||
| 216 | current_status = NO_ADAPTER_DETECTED; | ||
| 217 | |||
| 218 | for (int i = 0; i < 4; i++) | ||
| 219 | adapter_controllers_status[i] = ControllerTypes::CONTROLLER_NONE; | ||
| 220 | |||
| 221 | libusb_device** devs; // pointer to list of connected usb devices | ||
| 222 | |||
| 223 | int cnt = libusb_get_device_list(libusb_ctx, &devs); //get the list of devices | ||
| 224 | |||
| 225 | for (int i = 0; i < cnt; i++) { | ||
| 226 | if (CheckDeviceAccess(devs[i])) { | ||
| 227 | // GC Adapter found, registering it | ||
| 228 | GetGCEndpoint(devs[i]); | ||
| 229 | break; | ||
| 230 | } | ||
| 231 | } | ||
| 232 | } | ||
| 233 | |||
| 234 | static bool CheckDeviceAccess(libusb_device* device) { | ||
| 235 | libusb_device_descriptor desc; | ||
| 236 | int ret = libusb_get_device_descriptor(device, &desc); | ||
| 237 | if (ret) { | ||
| 238 | // could not acquire the descriptor, no point in trying to use it. | ||
| 239 | LOG_ERROR(Input, "libusb_get_device_descriptor failed with error: %d", ret); | ||
| 240 | return false; | ||
| 241 | } | ||
| 242 | |||
| 243 | if (desc.idVendor != 0x057e || desc.idProduct != 0x0337) { | ||
| 244 | // This isn’t the device we are looking for. | ||
| 245 | return false; | ||
| 246 | } | ||
| 247 | ret = libusb_open(device, &usb_adapter_handle); | ||
| 248 | |||
| 249 | if (ret == LIBUSB_ERROR_ACCESS) { | ||
| 250 | LOG_ERROR(Input, | ||
| 251 | "Yuzu can not gain access to this device: ID %04X:%04X.", | ||
| 252 | desc.idVendor, desc.idProduct); | ||
| 253 | return false; | ||
| 254 | } | ||
| 255 | if (ret) { | ||
| 256 | LOG_ERROR(Input, "libusb_open failed to open device with error = %d", ret); | ||
| 257 | return false; | ||
| 258 | } | ||
| 259 | |||
| 260 | ret = libusb_kernel_driver_active(usb_adapter_handle, 0); | ||
| 261 | if (ret == 1) { | ||
| 262 | ret = libusb_detach_kernel_driver(usb_adapter_handle, 0); | ||
| 263 | if (ret != 0 && ret != LIBUSB_ERROR_NOT_SUPPORTED) | ||
| 264 | LOG_ERROR(Input, "libusb_detach_kernel_driver failed with error = %d", ret); | ||
| 265 | } | ||
| 266 | |||
| 267 | if (ret != 0 && ret != LIBUSB_ERROR_NOT_SUPPORTED) { | ||
| 268 | libusb_close(usb_adapter_handle); | ||
| 269 | usb_adapter_handle = nullptr; | ||
| 270 | return false; | ||
| 271 | } | ||
| 272 | |||
| 273 | ret = libusb_claim_interface(usb_adapter_handle, 0); | ||
| 274 | if (ret) { | ||
| 275 | LOG_ERROR(Input, "libusb_claim_interface failed with error = %d", ret); | ||
| 276 | libusb_close(usb_adapter_handle); | ||
| 277 | usb_adapter_handle = nullptr; | ||
| 278 | return false; | ||
| 279 | } | ||
| 280 | |||
| 281 | return true; | ||
| 282 | } | ||
| 283 | |||
| 284 | static void GetGCEndpoint(libusb_device* device) { | ||
| 285 | libusb_config_descriptor* config = nullptr; | ||
| 286 | libusb_get_config_descriptor(device, 0, &config); | ||
| 287 | for (u8 ic = 0; ic < config->bNumInterfaces; ic++) { | ||
| 288 | const libusb_interface* interfaceContainer = &config->interface[ic]; | ||
| 289 | for (int i = 0; i < interfaceContainer->num_altsetting; i++) { | ||
| 290 | const libusb_interface_descriptor* interface = &interfaceContainer->altsetting[i]; | ||
| 291 | for (u8 e = 0; e < interface->bNumEndpoints; e++) { | ||
| 292 | const libusb_endpoint_descriptor* endpoint = &interface->endpoint[e]; | ||
| 293 | if (endpoint->bEndpointAddress & LIBUSB_ENDPOINT_IN) | ||
| 294 | input_endpoint = endpoint->bEndpointAddress; | ||
| 295 | } | ||
| 296 | } | ||
| 297 | } | ||
| 298 | |||
| 299 | adapter_thread_running = true; | ||
| 300 | current_status = ADAPTER_DETECTED; | ||
| 301 | |||
| 302 | adapter_input_thread = std::thread(Read); // Read input | ||
| 303 | } | ||
| 304 | |||
| 305 | void Shutdown() { | ||
| 306 | StopScanThread(); | ||
| 307 | Reset(); | ||
| 308 | |||
| 309 | current_status = NO_ADAPTER_DETECTED; | ||
| 310 | } | ||
| 311 | |||
| 312 | static void Reset() { | ||
| 313 | std::unique_lock<std::mutex> lock(initialization_mutex, std::defer_lock); | ||
| 314 | if (!lock.try_lock()) | ||
| 315 | return; | ||
| 316 | if (current_status != ADAPTER_DETECTED) | ||
| 317 | return; | ||
| 318 | |||
| 319 | if (adapter_thread_running) | ||
| 320 | adapter_input_thread.join(); | ||
| 321 | |||
| 322 | for (int i = 0; i < 4; i++) | ||
| 323 | adapter_controllers_status[i] = ControllerTypes::CONTROLLER_NONE; | ||
| 324 | |||
| 325 | current_status = NO_ADAPTER_DETECTED; | ||
| 326 | |||
| 327 | if (usb_adapter_handle) { | ||
| 328 | libusb_release_interface(usb_adapter_handle, 0); | ||
| 329 | libusb_close(usb_adapter_handle); | ||
| 330 | usb_adapter_handle = nullptr; | ||
| 331 | } | ||
| 332 | } | ||
| 333 | |||
| 334 | bool DeviceConnected(int port) { | ||
| 335 | return adapter_controllers_status[port] != ControllerTypes::CONTROLLER_NONE; | ||
| 336 | } | ||
| 337 | |||
| 338 | void ResetDeviceType(int port) { | ||
| 339 | adapter_controllers_status[port] = ControllerTypes::CONTROLLER_NONE; | ||
| 340 | } | ||
| 341 | |||
| 342 | void BeginConfiguration() { | ||
| 343 | configuring = true; | ||
| 344 | } | ||
| 345 | |||
| 346 | void EndConfiguration() { | ||
| 347 | configuring = false; | ||
| 348 | } | ||
| 349 | |||
| 350 | } // end of namespace GCAdapter | ||
diff --git a/src/input_common/gcadapter/gc_adapter.h b/src/input_common/gcadapter/gc_adapter.h new file mode 100644 index 000000000..9b02d1382 --- /dev/null +++ b/src/input_common/gcadapter/gc_adapter.h | |||
| @@ -0,0 +1,116 @@ | |||
| 1 | #pragma once | ||
| 2 | #include <algorithm> | ||
| 3 | #include <libusb.h> | ||
| 4 | #include <mutex> | ||
| 5 | #include <functional> | ||
| 6 | #include "common/common_types.h" | ||
| 7 | |||
| 8 | |||
| 9 | enum { | ||
| 10 | PAD_USE_ORIGIN = 0x0080, | ||
| 11 | PAD_GET_ORIGIN = 0x2000, | ||
| 12 | PAD_ERR_STATUS = 0x8000, | ||
| 13 | }; | ||
| 14 | |||
| 15 | enum PadButton { | ||
| 16 | PAD_BUTTON_LEFT = 0x0001, | ||
| 17 | PAD_BUTTON_RIGHT = 0x0002, | ||
| 18 | PAD_BUTTON_DOWN = 0x0004, | ||
| 19 | PAD_BUTTON_UP = 0x0008, | ||
| 20 | PAD_TRIGGER_Z = 0x0010, | ||
| 21 | PAD_TRIGGER_R = 0x0020, | ||
| 22 | PAD_TRIGGER_L = 0x0040, | ||
| 23 | PAD_BUTTON_A = 0x0100, | ||
| 24 | PAD_BUTTON_B = 0x0200, | ||
| 25 | PAD_BUTTON_X = 0x0400, | ||
| 26 | PAD_BUTTON_Y = 0x0800, | ||
| 27 | PAD_BUTTON_START = 0x1000, | ||
| 28 | // Below is for compatibility with "AxisButton" type | ||
| 29 | PAD_STICK = 0x2000, | ||
| 30 | |||
| 31 | }; | ||
| 32 | |||
| 33 | enum PadAxes { STICK_X, STICK_Y, SUBSTICK_X, SUBSTICK_Y, TRIGGER_LEFT, TRIGGER_RIGHT }; | ||
| 34 | |||
| 35 | struct GCPadStatus { | ||
| 36 | u16 button; // Or-ed PAD_BUTTON_* and PAD_TRIGGER_* bits | ||
| 37 | u8 stickX; // 0 <= stickX <= 255 | ||
| 38 | u8 stickY; // 0 <= stickY <= 255 | ||
| 39 | u8 substickX; // 0 <= substickX <= 255 | ||
| 40 | u8 substickY; // 0 <= substickY <= 255 | ||
| 41 | u8 triggerLeft; // 0 <= triggerLeft <= 255 | ||
| 42 | u8 triggerRight; // 0 <= triggerRight <= 255 | ||
| 43 | bool isConnected{true}; | ||
| 44 | |||
| 45 | static const u8 MAIN_STICK_CENTER_X = 0x80; | ||
| 46 | static const u8 MAIN_STICK_CENTER_Y = 0x80; | ||
| 47 | static const u8 MAIN_STICK_RADIUS = 0x7f; | ||
| 48 | static const u8 C_STICK_CENTER_X = 0x80; | ||
| 49 | static const u8 C_STICK_CENTER_Y = 0x80; | ||
| 50 | static const u8 C_STICK_RADIUS = 0x7f; | ||
| 51 | |||
| 52 | static const u8 TRIGGER_CENTER = 20; | ||
| 53 | static const u8 THRESHOLD = 10; | ||
| 54 | u8 port; | ||
| 55 | u8 axis_which = 255; | ||
| 56 | u8 axis_value = 255; | ||
| 57 | }; | ||
| 58 | |||
| 59 | struct GCState { | ||
| 60 | std::unordered_map<int, bool> buttons; | ||
| 61 | std::unordered_map<int, u16> axes; | ||
| 62 | }; | ||
| 63 | |||
| 64 | |||
| 65 | namespace GCAdapter { | ||
| 66 | enum ControllerTypes { | ||
| 67 | CONTROLLER_NONE = 0, | ||
| 68 | CONTROLLER_WIRED = 1, | ||
| 69 | CONTROLLER_WIRELESS = 2 | ||
| 70 | }; | ||
| 71 | |||
| 72 | enum { | ||
| 73 | NO_ADAPTER_DETECTED = 0, | ||
| 74 | ADAPTER_DETECTED = 1, | ||
| 75 | }; | ||
| 76 | |||
| 77 | // Current adapter status: detected/not detected/in error (holds the error code) | ||
| 78 | static int current_status = NO_ADAPTER_DETECTED; | ||
| 79 | |||
| 80 | GCPadStatus CheckStatus(int port, u8 adapter_payload[37]); | ||
| 81 | /// Initialize the GC Adapter capture and read sequence | ||
| 82 | void Init(); | ||
| 83 | |||
| 84 | /// Close the adapter read thread and release the adapter | ||
| 85 | void Shutdown(); | ||
| 86 | |||
| 87 | /// Begin scanning for the GC Adapter. | ||
| 88 | void StartScanThread(); | ||
| 89 | |||
| 90 | /// Stop scanning for the adapter | ||
| 91 | void StopScanThread(); | ||
| 92 | |||
| 93 | /// Returns true if there is a device connected to port | ||
| 94 | bool DeviceConnected(int port); | ||
| 95 | |||
| 96 | /// Resets status of device connected to port | ||
| 97 | void ResetDeviceType(int port); | ||
| 98 | |||
| 99 | /// Returns true if we successfully gain access to GC Adapter | ||
| 100 | bool CheckDeviceAccess(libusb_device* device); | ||
| 101 | |||
| 102 | /// Captures GC Adapter endpoint address, | ||
| 103 | void GetGCEndpoint(libusb_device* device); | ||
| 104 | |||
| 105 | /// For shutting down, clear all data, join all threads, release usb | ||
| 106 | void Reset(); | ||
| 107 | |||
| 108 | /// For use in initialization, querying devices to find the adapter | ||
| 109 | void Setup(); | ||
| 110 | |||
| 111 | /// Used for polling | ||
| 112 | void BeginConfiguration(); | ||
| 113 | |||
| 114 | void EndConfiguration(); | ||
| 115 | |||
| 116 | } // end of namespace GCAdapter | ||
diff --git a/src/input_common/gcadapter/gc_poller.cpp b/src/input_common/gcadapter/gc_poller.cpp new file mode 100644 index 000000000..772bd8890 --- /dev/null +++ b/src/input_common/gcadapter/gc_poller.cpp | |||
| @@ -0,0 +1,310 @@ | |||
| 1 | #include <atomic> | ||
| 2 | #include <list> | ||
| 3 | #include <mutex> | ||
| 4 | #include <utility> | ||
| 5 | #include "input_common/gcadapter/gc_poller.h" | ||
| 6 | #include "input_common/gcadapter/gc_adapter.h" | ||
| 7 | #include "common/threadsafe_queue.h" | ||
| 8 | |||
| 9 | // Using extern as to avoid multply defined symbols. | ||
| 10 | extern Common::SPSCQueue<GCPadStatus> pad_queue[4]; | ||
| 11 | extern struct GCState state[4]; | ||
| 12 | |||
| 13 | namespace InputCommon { | ||
| 14 | |||
| 15 | class GCButton final : public Input::ButtonDevice { | ||
| 16 | public: | ||
| 17 | explicit GCButton(int port_, int button_, int axis_) | ||
| 18 | : port(port_), button(button_) { | ||
| 19 | } | ||
| 20 | |||
| 21 | ~GCButton() override; | ||
| 22 | |||
| 23 | bool GetStatus() const override { | ||
| 24 | return state[port].buttons.at(button); | ||
| 25 | } | ||
| 26 | |||
| 27 | private: | ||
| 28 | const int port; | ||
| 29 | const int button; | ||
| 30 | }; | ||
| 31 | |||
| 32 | class GCAxisButton final : public Input::ButtonDevice { | ||
| 33 | public: | ||
| 34 | explicit GCAxisButton(int port_, int axis_, float threshold_, | ||
| 35 | bool trigger_if_greater_) | ||
| 36 | : port(port_), axis(axis_), threshold(threshold_), | ||
| 37 | trigger_if_greater(trigger_if_greater_) { | ||
| 38 | } | ||
| 39 | |||
| 40 | |||
| 41 | bool GetStatus() const override { | ||
| 42 | const float axis_value = (state[port].axes.at(axis) - 128.0f) / 128.0f; | ||
| 43 | if (trigger_if_greater) { | ||
| 44 | return axis_value > 0.10f; //TODO(ameerj) : Fix threshold. | ||
| 45 | } | ||
| 46 | return axis_value < -0.10f; | ||
| 47 | } | ||
| 48 | |||
| 49 | private: | ||
| 50 | const int port; | ||
| 51 | const int axis; | ||
| 52 | float threshold; | ||
| 53 | bool trigger_if_greater; | ||
| 54 | }; | ||
| 55 | |||
| 56 | GCButtonFactory::GCButtonFactory() { | ||
| 57 | GCAdapter::Init(); | ||
| 58 | } | ||
| 59 | |||
| 60 | GCButton::~GCButton() { | ||
| 61 | GCAdapter::Shutdown(); | ||
| 62 | } | ||
| 63 | |||
| 64 | std::unique_ptr<Input::ButtonDevice> GCButtonFactory::Create(const Common::ParamPackage& params) { | ||
| 65 | int button_id = params.Get("button", 0); | ||
| 66 | int port = params.Get("port", 0); | ||
| 67 | // For Axis buttons, used by the binary sticks. | ||
| 68 | if (params.Has("axis")) { | ||
| 69 | const int axis = params.Get("axis", 0); | ||
| 70 | const float threshold = params.Get("threshold", 0.5f); | ||
| 71 | const std::string direction_name = params.Get("direction", ""); | ||
| 72 | bool trigger_if_greater; | ||
| 73 | if (direction_name == "+") { | ||
| 74 | trigger_if_greater = true; | ||
| 75 | } else if (direction_name == "-") { | ||
| 76 | trigger_if_greater = false; | ||
| 77 | } else { | ||
| 78 | trigger_if_greater = true; | ||
| 79 | LOG_ERROR(Input, "Unknown direction {}", direction_name); | ||
| 80 | } | ||
| 81 | return std::make_unique<GCAxisButton>(port, axis, threshold, trigger_if_greater); | ||
| 82 | } | ||
| 83 | |||
| 84 | std::unique_ptr<GCButton> button = | ||
| 85 | std::make_unique<GCButton>(port, button_id, params.Get("axis", 0)); | ||
| 86 | return std::move(button); | ||
| 87 | } | ||
| 88 | |||
| 89 | Common::ParamPackage GCButtonFactory::GetNextInput() { | ||
| 90 | Common::ParamPackage params; | ||
| 91 | GCPadStatus pad; | ||
| 92 | for (int i = 0; i < 4; i++) { | ||
| 93 | while (pad_queue[i].Pop(pad)) { | ||
| 94 | // This while loop will break on the earliest detected button | ||
| 95 | params.Set("engine", "gcpad"); | ||
| 96 | params.Set("port", i); | ||
| 97 | // I was debating whether to keep these verbose for ease of reading | ||
| 98 | // or to use a while loop shifting the bits to test and set the value. | ||
| 99 | if (pad.button & PAD_BUTTON_A) { | ||
| 100 | params.Set("button", PAD_BUTTON_A); | ||
| 101 | break; | ||
| 102 | } | ||
| 103 | if (pad.button & PAD_BUTTON_B) { | ||
| 104 | params.Set("button", PAD_BUTTON_B); | ||
| 105 | break; | ||
| 106 | } | ||
| 107 | if (pad.button & PAD_BUTTON_X) { | ||
| 108 | params.Set("button", PAD_BUTTON_X); | ||
| 109 | break; | ||
| 110 | } | ||
| 111 | if (pad.button & PAD_BUTTON_Y) { | ||
| 112 | params.Set("button", PAD_BUTTON_Y); | ||
| 113 | break; | ||
| 114 | } | ||
| 115 | if (pad.button & PAD_BUTTON_DOWN) { | ||
| 116 | params.Set("button", PAD_BUTTON_DOWN); | ||
| 117 | break; | ||
| 118 | } | ||
| 119 | if (pad.button & PAD_BUTTON_LEFT) { | ||
| 120 | params.Set("button", PAD_BUTTON_LEFT); | ||
| 121 | break; | ||
| 122 | } | ||
| 123 | if (pad.button & PAD_BUTTON_RIGHT) { | ||
| 124 | params.Set("button", PAD_BUTTON_RIGHT); | ||
| 125 | break; | ||
| 126 | } | ||
| 127 | if (pad.button & PAD_BUTTON_UP) { | ||
| 128 | params.Set("button", PAD_BUTTON_UP); | ||
| 129 | break; | ||
| 130 | } | ||
| 131 | if (pad.button & PAD_TRIGGER_L) { | ||
| 132 | params.Set("button", PAD_TRIGGER_L); | ||
| 133 | break; | ||
| 134 | } | ||
| 135 | if (pad.button & PAD_TRIGGER_R) { | ||
| 136 | params.Set("button", PAD_TRIGGER_R); | ||
| 137 | break; | ||
| 138 | } | ||
| 139 | if (pad.button & PAD_TRIGGER_Z) { | ||
| 140 | params.Set("button", PAD_TRIGGER_Z); | ||
| 141 | break; | ||
| 142 | } | ||
| 143 | if (pad.button & PAD_BUTTON_START) { | ||
| 144 | params.Set("button", PAD_BUTTON_START); | ||
| 145 | break; | ||
| 146 | } | ||
| 147 | // For Axis button implementation | ||
| 148 | if (pad.axis_which != 255) { | ||
| 149 | params.Set("axis", pad.axis_which); | ||
| 150 | params.Set("button", PAD_STICK); | ||
| 151 | if (pad.axis_value > 128) { | ||
| 152 | params.Set("direction", "+"); | ||
| 153 | params.Set("threshold", "0.5"); | ||
| 154 | } else { | ||
| 155 | params.Set("direction", "-"); | ||
| 156 | params.Set("threshold", "-0.5"); | ||
| 157 | } | ||
| 158 | break; | ||
| 159 | } | ||
| 160 | } | ||
| 161 | } | ||
| 162 | return params; | ||
| 163 | } | ||
| 164 | |||
| 165 | void GCButtonFactory::BeginConfiguration() { | ||
| 166 | polling = true; | ||
| 167 | for (int i = 0; i < 4; i++) | ||
| 168 | pad_queue[i].Clear(); | ||
| 169 | GCAdapter::BeginConfiguration(); | ||
| 170 | } | ||
| 171 | |||
| 172 | void GCButtonFactory::EndConfiguration() { | ||
| 173 | polling = false; | ||
| 174 | |||
| 175 | for (int i = 0; i < 4; i++) | ||
| 176 | pad_queue[i].Clear(); | ||
| 177 | GCAdapter::EndConfiguration(); | ||
| 178 | } | ||
| 179 | |||
| 180 | class GCAnalog final : public Input::AnalogDevice { | ||
| 181 | public: | ||
| 182 | GCAnalog(int port_, int axis_x_, int axis_y_, float deadzone_) | ||
| 183 | : port(port_), axis_x(axis_x_), axis_y(axis_y_), deadzone(deadzone_) { | ||
| 184 | } | ||
| 185 | |||
| 186 | float GetAxis(int axis) const { | ||
| 187 | std::lock_guard lock{mutex}; | ||
| 188 | // division is not by a perfect 128 to account for some variance in center location | ||
| 189 | // e.g. my device idled at 131 in X, 120 in Y, and full range of motion was in range [20-230] | ||
| 190 | return (state[port].axes.at(axis) - 128.0f) / 95.0f; | ||
| 191 | } | ||
| 192 | |||
| 193 | std::tuple<float, float> GetAnalog(int axis_x, int axis_y) const { | ||
| 194 | float x = GetAxis(axis_x); | ||
| 195 | float y = GetAxis(axis_y); | ||
| 196 | |||
| 197 | // Make sure the coordinates are in the unit circle, | ||
| 198 | // otherwise normalize it. | ||
| 199 | float r = x * x + y * y; | ||
| 200 | if (r > 1.0f) { | ||
| 201 | r = std::sqrt(r); | ||
| 202 | x /= r; | ||
| 203 | y /= r; | ||
| 204 | } | ||
| 205 | |||
| 206 | return std::make_tuple(x, y); | ||
| 207 | } | ||
| 208 | |||
| 209 | std::tuple<float, float> GetStatus() const override { | ||
| 210 | const auto [x, y] = GetAnalog(axis_x, axis_y); | ||
| 211 | const float r = std::sqrt((x * x) + (y * y)); | ||
| 212 | if (r > deadzone) { | ||
| 213 | return std::make_tuple(x / r * (r - deadzone) / (1 - deadzone), | ||
| 214 | y / r * (r - deadzone) / (1 - deadzone)); | ||
| 215 | } | ||
| 216 | return std::make_tuple<float, float>(0.0f, 0.0f); | ||
| 217 | } | ||
| 218 | |||
| 219 | bool GetAnalogDirectionStatus(Input::AnalogDirection direction) const override { | ||
| 220 | const auto [x, y] = GetStatus(); | ||
| 221 | const float directional_deadzone = 0.4f; | ||
| 222 | switch (direction) { | ||
| 223 | case Input::AnalogDirection::RIGHT: | ||
| 224 | return x > directional_deadzone; | ||
| 225 | case Input::AnalogDirection::LEFT: | ||
| 226 | return x < -directional_deadzone; | ||
| 227 | case Input::AnalogDirection::UP: | ||
| 228 | return y > directional_deadzone; | ||
| 229 | case Input::AnalogDirection::DOWN: | ||
| 230 | return y < -directional_deadzone; | ||
| 231 | } | ||
| 232 | return false; | ||
| 233 | } | ||
| 234 | |||
| 235 | private: | ||
| 236 | const int port; | ||
| 237 | const int axis_x; | ||
| 238 | const int axis_y; | ||
| 239 | const float deadzone; | ||
| 240 | mutable std::mutex mutex; | ||
| 241 | }; | ||
| 242 | |||
| 243 | |||
| 244 | /// An analog device factory that creates analog devices from GC Adapter | ||
| 245 | GCAnalogFactory::GCAnalogFactory() {}; | ||
| 246 | |||
| 247 | |||
| 248 | /** | ||
| 249 | * Creates analog device from joystick axes | ||
| 250 | * @param params contains parameters for creating the device: | ||
| 251 | * - "port": the nth gcpad on the adapter | ||
| 252 | * - "axis_x": the index of the axis to be bind as x-axis | ||
| 253 | * - "axis_y": the index of the axis to be bind as y-axis | ||
| 254 | */ | ||
| 255 | std::unique_ptr<Input::AnalogDevice> GCAnalogFactory::Create(const Common::ParamPackage& params) { | ||
| 256 | const std::string guid = params.Get("guid", "0"); | ||
| 257 | const int port = params.Get("port", 0); | ||
| 258 | const int axis_x = params.Get("axis_x", 0); | ||
| 259 | const int axis_y = params.Get("axis_y", 1); | ||
| 260 | const float deadzone = std::clamp(params.Get("deadzone", 0.0f), 0.0f, .99f); | ||
| 261 | |||
| 262 | return std::make_unique<GCAnalog>(port, axis_x, axis_y, deadzone); | ||
| 263 | } | ||
| 264 | |||
| 265 | void GCAnalogFactory::BeginConfiguration() { | ||
| 266 | polling = true; | ||
| 267 | for (int i = 0; i < 4; i++) | ||
| 268 | pad_queue[i].Clear(); | ||
| 269 | GCAdapter::BeginConfiguration(); | ||
| 270 | } | ||
| 271 | |||
| 272 | void GCAnalogFactory::EndConfiguration() { | ||
| 273 | polling = false; | ||
| 274 | for (int i = 0; i < 4; i++) | ||
| 275 | pad_queue[i].Clear(); | ||
| 276 | GCAdapter::EndConfiguration(); | ||
| 277 | } | ||
| 278 | |||
| 279 | Common::ParamPackage GCAnalogFactory::GetNextInput() { | ||
| 280 | GCPadStatus pad; | ||
| 281 | for (int i = 0; i < 4; i++) { | ||
| 282 | while (pad_queue[i].Pop(pad)) { | ||
| 283 | if (pad.axis_which == 255 || std::abs((pad.axis_value - 128.0f) / 128.0f) < 0.1) { | ||
| 284 | continue; | ||
| 285 | } | ||
| 286 | // An analog device needs two axes, so we need to store the axis for later and wait for | ||
| 287 | // a second SDL event. The axes also must be from the same joystick. | ||
| 288 | const int axis = pad.axis_which; | ||
| 289 | if (analog_x_axis == -1) { | ||
| 290 | analog_x_axis = axis; | ||
| 291 | controller_number = i; | ||
| 292 | } else if (analog_y_axis == -1 && analog_x_axis != axis && controller_number == i) { | ||
| 293 | analog_y_axis = axis; | ||
| 294 | } | ||
| 295 | } | ||
| 296 | } | ||
| 297 | Common::ParamPackage params; | ||
| 298 | if (analog_x_axis != -1 && analog_y_axis != -1) { | ||
| 299 | params.Set("engine", "gcpad"); | ||
| 300 | params.Set("port", controller_number); | ||
| 301 | params.Set("axis_x", analog_x_axis); | ||
| 302 | params.Set("axis_y", analog_y_axis); | ||
| 303 | analog_x_axis = -1; | ||
| 304 | analog_y_axis = -1; | ||
| 305 | controller_number = -1; | ||
| 306 | return params; | ||
| 307 | } | ||
| 308 | return params; | ||
| 309 | } | ||
| 310 | } // namespace InputCommon | ||
diff --git a/src/input_common/gcadapter/gc_poller.h b/src/input_common/gcadapter/gc_poller.h new file mode 100644 index 000000000..d115b1d2a --- /dev/null +++ b/src/input_common/gcadapter/gc_poller.h | |||
| @@ -0,0 +1,59 @@ | |||
| 1 | #pragma once | ||
| 2 | |||
| 3 | #include <memory> | ||
| 4 | #include "core/frontend/input.h" | ||
| 5 | |||
| 6 | namespace InputCommon { | ||
| 7 | |||
| 8 | |||
| 9 | /** | ||
| 10 | * A button device factory representing a gcpad. It receives gcpad events and forward them | ||
| 11 | * to all button devices it created. | ||
| 12 | */ | ||
| 13 | class GCButtonFactory final : public Input::Factory<Input::ButtonDevice> { | ||
| 14 | public: | ||
| 15 | GCButtonFactory(); | ||
| 16 | |||
| 17 | /** | ||
| 18 | * Creates a button device from a button press | ||
| 19 | * @param params contains parameters for creating the device: | ||
| 20 | * - "code": the code of the key to bind with the button | ||
| 21 | */ | ||
| 22 | std::unique_ptr<Input::ButtonDevice> Create(const Common::ParamPackage& params) override; | ||
| 23 | |||
| 24 | Common::ParamPackage GetNextInput(); | ||
| 25 | |||
| 26 | /// For device input configuration/polling | ||
| 27 | void BeginConfiguration(); | ||
| 28 | void EndConfiguration(); | ||
| 29 | |||
| 30 | bool IsPolling() { | ||
| 31 | return polling; | ||
| 32 | } | ||
| 33 | |||
| 34 | private: | ||
| 35 | bool polling = false; | ||
| 36 | }; | ||
| 37 | |||
| 38 | /// An analog device factory that creates analog devices from GC Adapter | ||
| 39 | class GCAnalogFactory final : public Input::Factory<Input::AnalogDevice> { | ||
| 40 | public: | ||
| 41 | GCAnalogFactory(); | ||
| 42 | std::unique_ptr<Input::AnalogDevice> Create(const Common::ParamPackage& params) override; | ||
| 43 | Common::ParamPackage GetNextInput(); | ||
| 44 | |||
| 45 | /// For device input configuration/polling | ||
| 46 | void BeginConfiguration(); | ||
| 47 | void EndConfiguration(); | ||
| 48 | |||
| 49 | bool IsPolling() { | ||
| 50 | return polling; | ||
| 51 | } | ||
| 52 | |||
| 53 | private: | ||
| 54 | int analog_x_axis = -1; | ||
| 55 | int analog_y_axis = -1; | ||
| 56 | int controller_number = -1; | ||
| 57 | bool polling = false; | ||
| 58 | }; | ||
| 59 | } // namespace InputCommon | ||
diff --git a/src/input_common/keyboard.cpp b/src/input_common/keyboard.cpp index afb8e6612..d76791860 100644 --- a/src/input_common/keyboard.cpp +++ b/src/input_common/keyboard.cpp | |||
| @@ -13,7 +13,8 @@ namespace InputCommon { | |||
| 13 | class KeyButton final : public Input::ButtonDevice { | 13 | class KeyButton final : public Input::ButtonDevice { |
| 14 | public: | 14 | public: |
| 15 | explicit KeyButton(std::shared_ptr<KeyButtonList> key_button_list_) | 15 | explicit KeyButton(std::shared_ptr<KeyButtonList> key_button_list_) |
| 16 | : key_button_list(std::move(key_button_list_)) {} | 16 | : key_button_list(std::move(key_button_list_)) { |
| 17 | } | ||
| 17 | 18 | ||
| 18 | ~KeyButton() override; | 19 | ~KeyButton() override; |
| 19 | 20 | ||
| @@ -49,8 +50,10 @@ public: | |||
| 49 | void ChangeKeyStatus(int key_code, bool pressed) { | 50 | void ChangeKeyStatus(int key_code, bool pressed) { |
| 50 | std::lock_guard guard{mutex}; | 51 | std::lock_guard guard{mutex}; |
| 51 | for (const KeyButtonPair& pair : list) { | 52 | for (const KeyButtonPair& pair : list) { |
| 52 | if (pair.key_code == key_code) | 53 | if (pair.key_code == key_code) { |
| 53 | pair.key_button->status.store(pressed); | 54 | pair.key_button->status.store(pressed); |
| 55 | break; | ||
| 56 | } | ||
| 54 | } | 57 | } |
| 55 | } | 58 | } |
| 56 | 59 | ||
| @@ -66,7 +69,9 @@ private: | |||
| 66 | std::list<KeyButtonPair> list; | 69 | std::list<KeyButtonPair> list; |
| 67 | }; | 70 | }; |
| 68 | 71 | ||
| 69 | Keyboard::Keyboard() : key_button_list{std::make_shared<KeyButtonList>()} {} | 72 | Keyboard::Keyboard() |
| 73 | : key_button_list{std::make_shared<KeyButtonList>()} { | ||
| 74 | } | ||
| 70 | 75 | ||
| 71 | KeyButton::~KeyButton() { | 76 | KeyButton::~KeyButton() { |
| 72 | key_button_list->RemoveKeyButton(this); | 77 | key_button_list->RemoveKeyButton(this); |
| @@ -76,7 +81,7 @@ std::unique_ptr<Input::ButtonDevice> Keyboard::Create(const Common::ParamPackage | |||
| 76 | int key_code = params.Get("code", 0); | 81 | int key_code = params.Get("code", 0); |
| 77 | std::unique_ptr<KeyButton> button = std::make_unique<KeyButton>(key_button_list); | 82 | std::unique_ptr<KeyButton> button = std::make_unique<KeyButton>(key_button_list); |
| 78 | key_button_list->AddKeyButton(key_code, button.get()); | 83 | key_button_list->AddKeyButton(key_code, button.get()); |
| 79 | return button; | 84 | return std::move(button); |
| 80 | } | 85 | } |
| 81 | 86 | ||
| 82 | void Keyboard::PressKey(int key_code) { | 87 | void Keyboard::PressKey(int key_code) { |
diff --git a/src/input_common/main.cpp b/src/input_common/main.cpp index 95e351e24..be13129af 100644 --- a/src/input_common/main.cpp +++ b/src/input_common/main.cpp | |||
| @@ -4,8 +4,11 @@ | |||
| 4 | 4 | ||
| 5 | #include <memory> | 5 | #include <memory> |
| 6 | #include <thread> | 6 | #include <thread> |
| 7 | #include <libusb.h> | ||
| 8 | #include <iostream> | ||
| 7 | #include "common/param_package.h" | 9 | #include "common/param_package.h" |
| 8 | #include "input_common/analog_from_button.h" | 10 | #include "input_common/analog_from_button.h" |
| 11 | #include "input_common/gcadapter/gc_poller.h" | ||
| 9 | #include "input_common/keyboard.h" | 12 | #include "input_common/keyboard.h" |
| 10 | #include "input_common/main.h" | 13 | #include "input_common/main.h" |
| 11 | #include "input_common/motion_emu.h" | 14 | #include "input_common/motion_emu.h" |
| @@ -22,8 +25,15 @@ static std::shared_ptr<MotionEmu> motion_emu; | |||
| 22 | static std::unique_ptr<SDL::State> sdl; | 25 | static std::unique_ptr<SDL::State> sdl; |
| 23 | #endif | 26 | #endif |
| 24 | static std::unique_ptr<CemuhookUDP::State> udp; | 27 | static std::unique_ptr<CemuhookUDP::State> udp; |
| 28 | static std::shared_ptr<GCButtonFactory> gcbuttons; | ||
| 29 | static std::shared_ptr<GCAnalogFactory> gcanalog; | ||
| 25 | 30 | ||
| 26 | void Init() { | 31 | void Init() { |
| 32 | gcbuttons = std::make_shared<GCButtonFactory>(); | ||
| 33 | Input::RegisterFactory<Input::ButtonDevice>("gcpad", gcbuttons); | ||
| 34 | gcanalog = std::make_shared<GCAnalogFactory>(); | ||
| 35 | Input::RegisterFactory<Input::AnalogDevice>("gcpad", gcanalog); | ||
| 36 | |||
| 27 | keyboard = std::make_shared<Keyboard>(); | 37 | keyboard = std::make_shared<Keyboard>(); |
| 28 | Input::RegisterFactory<Input::ButtonDevice>("keyboard", keyboard); | 38 | Input::RegisterFactory<Input::ButtonDevice>("keyboard", keyboard); |
| 29 | Input::RegisterFactory<Input::AnalogDevice>("analog_from_button", | 39 | Input::RegisterFactory<Input::AnalogDevice>("analog_from_button", |
| @@ -34,8 +44,10 @@ void Init() { | |||
| 34 | #ifdef HAVE_SDL2 | 44 | #ifdef HAVE_SDL2 |
| 35 | sdl = SDL::Init(); | 45 | sdl = SDL::Init(); |
| 36 | #endif | 46 | #endif |
| 47 | /* | ||
| 37 | 48 | ||
| 38 | udp = CemuhookUDP::Init(); | 49 | udp = CemuhookUDP::Init(); |
| 50 | */ | ||
| 39 | } | 51 | } |
| 40 | 52 | ||
| 41 | void Shutdown() { | 53 | void Shutdown() { |
| @@ -48,6 +60,8 @@ void Shutdown() { | |||
| 48 | sdl.reset(); | 60 | sdl.reset(); |
| 49 | #endif | 61 | #endif |
| 50 | udp.reset(); | 62 | udp.reset(); |
| 63 | Input::UnregisterFactory<Input::ButtonDevice>("gcpad"); | ||
| 64 | gcbuttons.reset(); | ||
| 51 | } | 65 | } |
| 52 | 66 | ||
| 53 | Keyboard* GetKeyboard() { | 67 | Keyboard* GetKeyboard() { |
| @@ -58,6 +72,14 @@ MotionEmu* GetMotionEmu() { | |||
| 58 | return motion_emu.get(); | 72 | return motion_emu.get(); |
| 59 | } | 73 | } |
| 60 | 74 | ||
| 75 | GCButtonFactory* GetGCButtons() { | ||
| 76 | return gcbuttons.get(); | ||
| 77 | } | ||
| 78 | |||
| 79 | GCAnalogFactory* GetGCAnalogs() { | ||
| 80 | return gcanalog.get(); | ||
| 81 | } | ||
| 82 | |||
| 61 | std::string GenerateKeyboardParam(int key_code) { | 83 | std::string GenerateKeyboardParam(int key_code) { |
| 62 | Common::ParamPackage param{ | 84 | Common::ParamPackage param{ |
| 63 | {"engine", "keyboard"}, | 85 | {"engine", "keyboard"}, |
| @@ -88,7 +110,6 @@ std::vector<std::unique_ptr<DevicePoller>> GetPollers(DeviceType type) { | |||
| 88 | #ifdef HAVE_SDL2 | 110 | #ifdef HAVE_SDL2 |
| 89 | pollers = sdl->GetPollers(type); | 111 | pollers = sdl->GetPollers(type); |
| 90 | #endif | 112 | #endif |
| 91 | |||
| 92 | return pollers; | 113 | return pollers; |
| 93 | } | 114 | } |
| 94 | 115 | ||
diff --git a/src/input_common/main.h b/src/input_common/main.h index 77a0ce90b..be2e7a6c4 100644 --- a/src/input_common/main.h +++ b/src/input_common/main.h | |||
| @@ -7,6 +7,8 @@ | |||
| 7 | #include <memory> | 7 | #include <memory> |
| 8 | #include <string> | 8 | #include <string> |
| 9 | #include <vector> | 9 | #include <vector> |
| 10 | #include "input_common/gcadapter/gc_poller.h" | ||
| 11 | #include "input_common/gcadapter/gc_adapter.h" | ||
| 10 | 12 | ||
| 11 | namespace Common { | 13 | namespace Common { |
| 12 | class ParamPackage; | 14 | class ParamPackage; |
| @@ -30,6 +32,13 @@ class MotionEmu; | |||
| 30 | /// Gets the motion emulation factory. | 32 | /// Gets the motion emulation factory. |
| 31 | MotionEmu* GetMotionEmu(); | 33 | MotionEmu* GetMotionEmu(); |
| 32 | 34 | ||
| 35 | class GCButtonFactory; | ||
| 36 | class GCAnalogFactory; | ||
| 37 | |||
| 38 | GCButtonFactory* GetGCButtons(); | ||
| 39 | GCAnalogFactory* GetGCAnalogs(); | ||
| 40 | |||
| 41 | |||
| 33 | /// Generates a serialized param package for creating a keyboard button device | 42 | /// Generates a serialized param package for creating a keyboard button device |
| 34 | std::string GenerateKeyboardParam(int key_code); | 43 | std::string GenerateKeyboardParam(int key_code); |
| 35 | 44 | ||
diff --git a/src/input_common/motion_emu.cpp b/src/input_common/motion_emu.cpp index d4cdf76a3..b7120311a 100644 --- a/src/input_common/motion_emu.cpp +++ b/src/input_common/motion_emu.cpp | |||
| @@ -22,7 +22,8 @@ public: | |||
| 22 | : update_millisecond(update_millisecond), | 22 | : update_millisecond(update_millisecond), |
| 23 | update_duration(std::chrono::duration_cast<std::chrono::steady_clock::duration>( | 23 | update_duration(std::chrono::duration_cast<std::chrono::steady_clock::duration>( |
| 24 | std::chrono::milliseconds(update_millisecond))), | 24 | std::chrono::milliseconds(update_millisecond))), |
| 25 | sensitivity(sensitivity), motion_emu_thread(&MotionEmuDevice::MotionEmuThread, this) {} | 25 | sensitivity(sensitivity), motion_emu_thread(&MotionEmuDevice::MotionEmuThread, this) { |
| 26 | } | ||
| 26 | 27 | ||
| 27 | ~MotionEmuDevice() { | 28 | ~MotionEmuDevice() { |
| 28 | if (motion_emu_thread.joinable()) { | 29 | if (motion_emu_thread.joinable()) { |
| @@ -145,7 +146,7 @@ std::unique_ptr<Input::MotionDevice> MotionEmu::Create(const Common::ParamPackag | |||
| 145 | // Previously created device is disconnected here. Having two motion devices for 3DS is not | 146 | // Previously created device is disconnected here. Having two motion devices for 3DS is not |
| 146 | // expected. | 147 | // expected. |
| 147 | current_device = device_wrapper->device; | 148 | current_device = device_wrapper->device; |
| 148 | return device_wrapper; | 149 | return std::move(device_wrapper); |
| 149 | } | 150 | } |
| 150 | 151 | ||
| 151 | void MotionEmu::BeginTilt(int x, int y) { | 152 | void MotionEmu::BeginTilt(int x, int y) { |
diff --git a/src/input_common/sdl/sdl_impl.cpp b/src/input_common/sdl/sdl_impl.cpp index 675b477fa..3c1820c4a 100644 --- a/src/input_common/sdl/sdl_impl.cpp +++ b/src/input_common/sdl/sdl_impl.cpp | |||
| @@ -49,7 +49,8 @@ static int SDLEventWatcher(void* user_data, SDL_Event* event) { | |||
| 49 | class SDLJoystick { | 49 | class SDLJoystick { |
| 50 | public: | 50 | public: |
| 51 | SDLJoystick(std::string guid_, int port_, SDL_Joystick* joystick) | 51 | SDLJoystick(std::string guid_, int port_, SDL_Joystick* joystick) |
| 52 | : guid{std::move(guid_)}, port{port_}, sdl_joystick{joystick, &SDL_JoystickClose} {} | 52 | : guid{std::move(guid_)}, port{port_}, sdl_joystick{joystick, &SDL_JoystickClose} { |
| 53 | } | ||
| 53 | 54 | ||
| 54 | void SetButton(int button, bool value) { | 55 | void SetButton(int button, bool value) { |
| 55 | std::lock_guard lock{mutex}; | 56 | std::lock_guard lock{mutex}; |
| @@ -97,6 +98,7 @@ public: | |||
| 97 | std::lock_guard lock{mutex}; | 98 | std::lock_guard lock{mutex}; |
| 98 | return (state.hats.at(hat) & direction) != 0; | 99 | return (state.hats.at(hat) & direction) != 0; |
| 99 | } | 100 | } |
| 101 | |||
| 100 | /** | 102 | /** |
| 101 | * The guid of the joystick | 103 | * The guid of the joystick |
| 102 | */ | 104 | */ |
| @@ -125,6 +127,7 @@ private: | |||
| 125 | std::unordered_map<int, Sint16> axes; | 127 | std::unordered_map<int, Sint16> axes; |
| 126 | std::unordered_map<int, Uint8> hats; | 128 | std::unordered_map<int, Uint8> hats; |
| 127 | } state; | 129 | } state; |
| 130 | |||
| 128 | std::string guid; | 131 | std::string guid; |
| 129 | int port; | 132 | int port; |
| 130 | std::unique_ptr<SDL_Joystick, decltype(&SDL_JoystickClose)> sdl_joystick; | 133 | std::unique_ptr<SDL_Joystick, decltype(&SDL_JoystickClose)> sdl_joystick; |
| @@ -155,7 +158,8 @@ std::shared_ptr<SDLJoystick> SDLState::GetSDLJoystickBySDLID(SDL_JoystickID sdl_ | |||
| 155 | if (map_it != joystick_map.end()) { | 158 | if (map_it != joystick_map.end()) { |
| 156 | const auto vec_it = | 159 | const auto vec_it = |
| 157 | std::find_if(map_it->second.begin(), map_it->second.end(), | 160 | std::find_if(map_it->second.begin(), map_it->second.end(), |
| 158 | [&sdl_joystick](const std::shared_ptr<SDLJoystick>& joystick) { | 161 | [&sdl_joystick](const std::shared_ptr<SDLJoystick>& joystick) |
| 162 | { | ||
| 159 | return sdl_joystick == joystick->GetSDLJoystick(); | 163 | return sdl_joystick == joystick->GetSDLJoystick(); |
| 160 | }); | 164 | }); |
| 161 | if (vec_it != map_it->second.end()) { | 165 | if (vec_it != map_it->second.end()) { |
| @@ -166,7 +170,8 @@ std::shared_ptr<SDLJoystick> SDLState::GetSDLJoystickBySDLID(SDL_JoystickID sdl_ | |||
| 166 | 170 | ||
| 167 | // Search for a SDLJoystick without a mapped SDL_Joystick... | 171 | // Search for a SDLJoystick without a mapped SDL_Joystick... |
| 168 | const auto nullptr_it = std::find_if(map_it->second.begin(), map_it->second.end(), | 172 | const auto nullptr_it = std::find_if(map_it->second.begin(), map_it->second.end(), |
| 169 | [](const std::shared_ptr<SDLJoystick>& joystick) { | 173 | [](const std::shared_ptr<SDLJoystick>& joystick) |
| 174 | { | ||
| 170 | return !joystick->GetSDLJoystick(); | 175 | return !joystick->GetSDLJoystick(); |
| 171 | }); | 176 | }); |
| 172 | if (nullptr_it != map_it->second.end()) { | 177 | if (nullptr_it != map_it->second.end()) { |
| @@ -223,7 +228,8 @@ void SDLState::CloseJoystick(SDL_Joystick* sdl_joystick) { | |||
| 223 | const auto& joystick_guid_list = joystick_map[guid]; | 228 | const auto& joystick_guid_list = joystick_map[guid]; |
| 224 | const auto joystick_it = | 229 | const auto joystick_it = |
| 225 | std::find_if(joystick_guid_list.begin(), joystick_guid_list.end(), | 230 | std::find_if(joystick_guid_list.begin(), joystick_guid_list.end(), |
| 226 | [&sdl_joystick](const std::shared_ptr<SDLJoystick>& joystick) { | 231 | [&sdl_joystick](const std::shared_ptr<SDLJoystick>& joystick) |
| 232 | { | ||
| 227 | return joystick->GetSDLJoystick() == sdl_joystick; | 233 | return joystick->GetSDLJoystick() == sdl_joystick; |
| 228 | }); | 234 | }); |
| 229 | joystick = *joystick_it; | 235 | joystick = *joystick_it; |
| @@ -279,7 +285,8 @@ void SDLState::CloseJoysticks() { | |||
| 279 | class SDLButton final : public Input::ButtonDevice { | 285 | class SDLButton final : public Input::ButtonDevice { |
| 280 | public: | 286 | public: |
| 281 | explicit SDLButton(std::shared_ptr<SDLJoystick> joystick_, int button_) | 287 | explicit SDLButton(std::shared_ptr<SDLJoystick> joystick_, int button_) |
| 282 | : joystick(std::move(joystick_)), button(button_) {} | 288 | : joystick(std::move(joystick_)), button(button_) { |
| 289 | } | ||
| 283 | 290 | ||
| 284 | bool GetStatus() const override { | 291 | bool GetStatus() const override { |
| 285 | return joystick->GetButton(button); | 292 | return joystick->GetButton(button); |
| @@ -293,7 +300,8 @@ private: | |||
| 293 | class SDLDirectionButton final : public Input::ButtonDevice { | 300 | class SDLDirectionButton final : public Input::ButtonDevice { |
| 294 | public: | 301 | public: |
| 295 | explicit SDLDirectionButton(std::shared_ptr<SDLJoystick> joystick_, int hat_, Uint8 direction_) | 302 | explicit SDLDirectionButton(std::shared_ptr<SDLJoystick> joystick_, int hat_, Uint8 direction_) |
| 296 | : joystick(std::move(joystick_)), hat(hat_), direction(direction_) {} | 303 | : joystick(std::move(joystick_)), hat(hat_), direction(direction_) { |
| 304 | } | ||
| 297 | 305 | ||
| 298 | bool GetStatus() const override { | 306 | bool GetStatus() const override { |
| 299 | return joystick->GetHatDirection(hat, direction); | 307 | return joystick->GetHatDirection(hat, direction); |
| @@ -310,7 +318,8 @@ public: | |||
| 310 | explicit SDLAxisButton(std::shared_ptr<SDLJoystick> joystick_, int axis_, float threshold_, | 318 | explicit SDLAxisButton(std::shared_ptr<SDLJoystick> joystick_, int axis_, float threshold_, |
| 311 | bool trigger_if_greater_) | 319 | bool trigger_if_greater_) |
| 312 | : joystick(std::move(joystick_)), axis(axis_), threshold(threshold_), | 320 | : joystick(std::move(joystick_)), axis(axis_), threshold(threshold_), |
| 313 | trigger_if_greater(trigger_if_greater_) {} | 321 | trigger_if_greater(trigger_if_greater_) { |
| 322 | } | ||
| 314 | 323 | ||
| 315 | bool GetStatus() const override { | 324 | bool GetStatus() const override { |
| 316 | const float axis_value = joystick->GetAxis(axis); | 325 | const float axis_value = joystick->GetAxis(axis); |
| @@ -330,7 +339,8 @@ private: | |||
| 330 | class SDLAnalog final : public Input::AnalogDevice { | 339 | class SDLAnalog final : public Input::AnalogDevice { |
| 331 | public: | 340 | public: |
| 332 | SDLAnalog(std::shared_ptr<SDLJoystick> joystick_, int axis_x_, int axis_y_, float deadzone_) | 341 | SDLAnalog(std::shared_ptr<SDLJoystick> joystick_, int axis_x_, int axis_y_, float deadzone_) |
| 333 | : joystick(std::move(joystick_)), axis_x(axis_x_), axis_y(axis_y_), deadzone(deadzone_) {} | 342 | : joystick(std::move(joystick_)), axis_x(axis_x_), axis_y(axis_y_), deadzone(deadzone_) { |
| 343 | } | ||
| 334 | 344 | ||
| 335 | std::tuple<float, float> GetStatus() const override { | 345 | std::tuple<float, float> GetStatus() const override { |
| 336 | const auto [x, y] = joystick->GetAnalog(axis_x, axis_y); | 346 | const auto [x, y] = joystick->GetAnalog(axis_x, axis_y); |
| @@ -368,7 +378,9 @@ private: | |||
| 368 | /// A button device factory that creates button devices from SDL joystick | 378 | /// A button device factory that creates button devices from SDL joystick |
| 369 | class SDLButtonFactory final : public Input::Factory<Input::ButtonDevice> { | 379 | class SDLButtonFactory final : public Input::Factory<Input::ButtonDevice> { |
| 370 | public: | 380 | public: |
| 371 | explicit SDLButtonFactory(SDLState& state_) : state(state_) {} | 381 | explicit SDLButtonFactory(SDLState& state_) |
| 382 | : state(state_) { | ||
| 383 | } | ||
| 372 | 384 | ||
| 373 | /** | 385 | /** |
| 374 | * Creates a button device from a joystick button | 386 | * Creates a button device from a joystick button |
| @@ -443,7 +455,10 @@ private: | |||
| 443 | /// An analog device factory that creates analog devices from SDL joystick | 455 | /// An analog device factory that creates analog devices from SDL joystick |
| 444 | class SDLAnalogFactory final : public Input::Factory<Input::AnalogDevice> { | 456 | class SDLAnalogFactory final : public Input::Factory<Input::AnalogDevice> { |
| 445 | public: | 457 | public: |
| 446 | explicit SDLAnalogFactory(SDLState& state_) : state(state_) {} | 458 | explicit SDLAnalogFactory(SDLState& state_) |
| 459 | : state(state_) { | ||
| 460 | } | ||
| 461 | |||
| 447 | /** | 462 | /** |
| 448 | * Creates analog device from joystick axes | 463 | * Creates analog device from joystick axes |
| 449 | * @param params contains parameters for creating the device: | 464 | * @param params contains parameters for creating the device: |
| @@ -490,7 +505,8 @@ SDLState::SDLState() { | |||
| 490 | 505 | ||
| 491 | initialized = true; | 506 | initialized = true; |
| 492 | if (start_thread) { | 507 | if (start_thread) { |
| 493 | poll_thread = std::thread([this] { | 508 | poll_thread = std::thread([this] |
| 509 | { | ||
| 494 | using namespace std::chrono_literals; | 510 | using namespace std::chrono_literals; |
| 495 | while (initialized) { | 511 | while (initialized) { |
| 496 | SDL_PumpEvents(); | 512 | SDL_PumpEvents(); |
| @@ -576,7 +592,9 @@ namespace Polling { | |||
| 576 | 592 | ||
| 577 | class SDLPoller : public InputCommon::Polling::DevicePoller { | 593 | class SDLPoller : public InputCommon::Polling::DevicePoller { |
| 578 | public: | 594 | public: |
| 579 | explicit SDLPoller(SDLState& state_) : state(state_) {} | 595 | explicit SDLPoller(SDLState& state_) |
| 596 | : state(state_) { | ||
| 597 | } | ||
| 580 | 598 | ||
| 581 | void Start() override { | 599 | void Start() override { |
| 582 | state.event_queue.Clear(); | 600 | state.event_queue.Clear(); |
| @@ -593,7 +611,9 @@ protected: | |||
| 593 | 611 | ||
| 594 | class SDLButtonPoller final : public SDLPoller { | 612 | class SDLButtonPoller final : public SDLPoller { |
| 595 | public: | 613 | public: |
| 596 | explicit SDLButtonPoller(SDLState& state_) : SDLPoller(state_) {} | 614 | explicit SDLButtonPoller(SDLState& state_) |
| 615 | : SDLPoller(state_) { | ||
| 616 | } | ||
| 597 | 617 | ||
| 598 | Common::ParamPackage GetNextInput() override { | 618 | Common::ParamPackage GetNextInput() override { |
| 599 | SDL_Event event; | 619 | SDL_Event event; |
| @@ -602,8 +622,7 @@ public: | |||
| 602 | case SDL_JOYAXISMOTION: | 622 | case SDL_JOYAXISMOTION: |
| 603 | if (std::abs(event.jaxis.value / 32767.0) < 0.5) { | 623 | if (std::abs(event.jaxis.value / 32767.0) < 0.5) { |
| 604 | break; | 624 | break; |
| 605 | } | 625 | }[[fallthrough]]; |
| 606 | [[fallthrough]]; | ||
| 607 | case SDL_JOYBUTTONUP: | 626 | case SDL_JOYBUTTONUP: |
| 608 | case SDL_JOYHATMOTION: | 627 | case SDL_JOYHATMOTION: |
| 609 | return SDLEventToButtonParamPackage(state, event); | 628 | return SDLEventToButtonParamPackage(state, event); |
| @@ -615,7 +634,9 @@ public: | |||
| 615 | 634 | ||
| 616 | class SDLAnalogPoller final : public SDLPoller { | 635 | class SDLAnalogPoller final : public SDLPoller { |
| 617 | public: | 636 | public: |
| 618 | explicit SDLAnalogPoller(SDLState& state_) : SDLPoller(state_) {} | 637 | explicit SDLAnalogPoller(SDLState& state_) |
| 638 | : SDLPoller(state_) { | ||
| 639 | } | ||
| 619 | 640 | ||
| 620 | void Start() override { | 641 | void Start() override { |
| 621 | SDLPoller::Start(); | 642 | SDLPoller::Start(); |
diff --git a/src/input_common/udp/client.cpp b/src/input_common/udp/client.cpp index da5227058..befa4c86d 100644 --- a/src/input_common/udp/client.cpp +++ b/src/input_common/udp/client.cpp | |||
| @@ -59,7 +59,8 @@ public: | |||
| 59 | void StartReceive() { | 59 | void StartReceive() { |
| 60 | socket.async_receive_from( | 60 | socket.async_receive_from( |
| 61 | boost::asio::buffer(receive_buffer), receive_endpoint, | 61 | boost::asio::buffer(receive_buffer), receive_endpoint, |
| 62 | [this](const boost::system::error_code& error, std::size_t bytes_transferred) { | 62 | [this](const boost::system::error_code& error, std::size_t bytes_transferred) |
| 63 | { | ||
| 63 | HandleReceive(error, bytes_transferred); | 64 | HandleReceive(error, bytes_transferred); |
| 64 | }); | 65 | }); |
| 65 | } | 66 | } |
| @@ -211,21 +212,27 @@ void Client::StartCommunication(const std::string& host, u16 port, u8 pad_index, | |||
| 211 | void TestCommunication(const std::string& host, u16 port, u8 pad_index, u32 client_id, | 212 | void TestCommunication(const std::string& host, u16 port, u8 pad_index, u32 client_id, |
| 212 | std::function<void()> success_callback, | 213 | std::function<void()> success_callback, |
| 213 | std::function<void()> failure_callback) { | 214 | std::function<void()> failure_callback) { |
| 214 | std::thread([=] { | 215 | std::thread([=] |
| 215 | Common::Event success_event; | 216 | { |
| 216 | SocketCallback callback{[](Response::Version version) {}, [](Response::PortInfo info) {}, | 217 | Common::Event success_event; |
| 217 | [&](Response::PadData data) { success_event.Set(); }}; | 218 | SocketCallback callback{[](Response::Version version) |
| 218 | Socket socket{host, port, pad_index, client_id, std::move(callback)}; | 219 | { |
| 219 | std::thread worker_thread{SocketLoop, &socket}; | 220 | }, |
| 220 | bool result = success_event.WaitFor(std::chrono::seconds(8)); | 221 | [](Response::PortInfo info) |
| 221 | socket.Stop(); | 222 | { |
| 222 | worker_thread.join(); | 223 | }, |
| 223 | if (result) { | 224 | [&](Response::PadData data) { success_event.Set(); }}; |
| 224 | success_callback(); | 225 | Socket socket{host, port, pad_index, client_id, std::move(callback)}; |
| 225 | } else { | 226 | std::thread worker_thread{SocketLoop, &socket}; |
| 226 | failure_callback(); | 227 | bool result = success_event.WaitFor(std::chrono::seconds(8)); |
| 227 | } | 228 | socket.Stop(); |
| 228 | }) | 229 | worker_thread.join(); |
| 230 | if (result) { | ||
| 231 | success_callback(); | ||
| 232 | } else { | ||
| 233 | failure_callback(); | ||
| 234 | } | ||
| 235 | }) | ||
| 229 | .detach(); | 236 | .detach(); |
| 230 | } | 237 | } |
| 231 | 238 | ||
| @@ -234,53 +241,60 @@ CalibrationConfigurationJob::CalibrationConfigurationJob( | |||
| 234 | std::function<void(Status)> status_callback, | 241 | std::function<void(Status)> status_callback, |
| 235 | std::function<void(u16, u16, u16, u16)> data_callback) { | 242 | std::function<void(u16, u16, u16, u16)> data_callback) { |
| 236 | 243 | ||
| 237 | std::thread([=] { | 244 | std::thread([=] |
| 238 | constexpr u16 CALIBRATION_THRESHOLD = 100; | 245 | { |
| 239 | 246 | constexpr u16 CALIBRATION_THRESHOLD = 100; | |
| 240 | u16 min_x{UINT16_MAX}; | 247 | |
| 241 | u16 min_y{UINT16_MAX}; | 248 | u16 min_x{UINT16_MAX}; |
| 242 | u16 max_x{}; | 249 | u16 min_y{UINT16_MAX}; |
| 243 | u16 max_y{}; | 250 | u16 max_x{}; |
| 244 | 251 | u16 max_y{}; | |
| 245 | Status current_status{Status::Initialized}; | 252 | |
| 246 | SocketCallback callback{[](Response::Version version) {}, [](Response::PortInfo info) {}, | 253 | Status current_status{Status::Initialized}; |
| 247 | [&](Response::PadData data) { | 254 | SocketCallback callback{[](Response::Version version) |
| 248 | if (current_status == Status::Initialized) { | 255 | { |
| 249 | // Receiving data means the communication is ready now | 256 | }, |
| 250 | current_status = Status::Ready; | 257 | [](Response::PortInfo info) |
| 251 | status_callback(current_status); | 258 | { |
| 252 | } | 259 | }, |
| 253 | if (!data.touch_1.is_active) { | 260 | [&](Response::PadData data) |
| 254 | return; | 261 | { |
| 255 | } | 262 | if (current_status == Status::Initialized) { |
| 256 | LOG_DEBUG(Input, "Current touch: {} {}", data.touch_1.x, | 263 | // Receiving data means the communication is ready now |
| 257 | data.touch_1.y); | 264 | current_status = Status::Ready; |
| 258 | min_x = std::min(min_x, static_cast<u16>(data.touch_1.x)); | 265 | status_callback(current_status); |
| 259 | min_y = std::min(min_y, static_cast<u16>(data.touch_1.y)); | 266 | } |
| 260 | if (current_status == Status::Ready) { | 267 | if (!data.touch_1.is_active) { |
| 261 | // First touch - min data (min_x/min_y) | 268 | return; |
| 262 | current_status = Status::Stage1Completed; | 269 | } |
| 263 | status_callback(current_status); | 270 | LOG_DEBUG(Input, "Current touch: {} {}", data.touch_1.x, |
| 264 | } | 271 | data.touch_1.y); |
| 265 | if (data.touch_1.x - min_x > CALIBRATION_THRESHOLD && | 272 | min_x = std::min(min_x, static_cast<u16>(data.touch_1.x)); |
| 266 | data.touch_1.y - min_y > CALIBRATION_THRESHOLD) { | 273 | min_y = std::min(min_y, static_cast<u16>(data.touch_1.y)); |
| 267 | // Set the current position as max value and finishes | 274 | if (current_status == Status::Ready) { |
| 268 | // configuration | 275 | // First touch - min data (min_x/min_y) |
| 269 | max_x = data.touch_1.x; | 276 | current_status = Status::Stage1Completed; |
| 270 | max_y = data.touch_1.y; | 277 | status_callback(current_status); |
| 271 | current_status = Status::Completed; | 278 | } |
| 272 | data_callback(min_x, min_y, max_x, max_y); | 279 | if (data.touch_1.x - min_x > CALIBRATION_THRESHOLD && |
| 273 | status_callback(current_status); | 280 | data.touch_1.y - min_y > CALIBRATION_THRESHOLD) { |
| 274 | 281 | // Set the current position as max value and finishes | |
| 275 | complete_event.Set(); | 282 | // configuration |
| 276 | } | 283 | max_x = data.touch_1.x; |
| 277 | }}; | 284 | max_y = data.touch_1.y; |
| 278 | Socket socket{host, port, pad_index, client_id, std::move(callback)}; | 285 | current_status = Status::Completed; |
| 279 | std::thread worker_thread{SocketLoop, &socket}; | 286 | data_callback(min_x, min_y, max_x, max_y); |
| 280 | complete_event.Wait(); | 287 | status_callback(current_status); |
| 281 | socket.Stop(); | 288 | |
| 282 | worker_thread.join(); | 289 | complete_event.Set(); |
| 283 | }) | 290 | } |
| 291 | }}; | ||
| 292 | Socket socket{host, port, pad_index, client_id, std::move(callback)}; | ||
| 293 | std::thread worker_thread{SocketLoop, &socket}; | ||
| 294 | complete_event.Wait(); | ||
| 295 | socket.Stop(); | ||
| 296 | worker_thread.join(); | ||
| 297 | }) | ||
| 284 | .detach(); | 298 | .detach(); |
| 285 | } | 299 | } |
| 286 | 300 | ||
diff --git a/src/input_common/udp/client.h b/src/input_common/udp/client.h index b8c654755..b58e319b6 100644 --- a/src/input_common/udp/client.h +++ b/src/input_common/udp/client.h | |||
| @@ -40,6 +40,7 @@ struct DeviceStatus { | |||
| 40 | u16 max_x{}; | 40 | u16 max_x{}; |
| 41 | u16 max_y{}; | 41 | u16 max_y{}; |
| 42 | }; | 42 | }; |
| 43 | |||
| 43 | std::optional<CalibrationData> touch_calibration; | 44 | std::optional<CalibrationData> touch_calibration; |
| 44 | }; | 45 | }; |
| 45 | 46 | ||
| @@ -72,6 +73,7 @@ public: | |||
| 72 | Stage1Completed, | 73 | Stage1Completed, |
| 73 | Completed, | 74 | Completed, |
| 74 | }; | 75 | }; |
| 76 | |||
| 75 | /** | 77 | /** |
| 76 | * Constructs and starts the job with the specified parameter. | 78 | * Constructs and starts the job with the specified parameter. |
| 77 | * | 79 | * |
diff --git a/src/input_common/udp/protocol.h b/src/input_common/udp/protocol.h index 3ba4d1fc8..2b31846db 100644 --- a/src/input_common/udp/protocol.h +++ b/src/input_common/udp/protocol.h | |||
| @@ -35,6 +35,7 @@ struct Header { | |||
| 35 | ///> the data | 35 | ///> the data |
| 36 | Type type{}; | 36 | Type type{}; |
| 37 | }; | 37 | }; |
| 38 | |||
| 38 | static_assert(sizeof(Header) == 20, "UDP Message Header struct has wrong size"); | 39 | static_assert(sizeof(Header) == 20, "UDP Message Header struct has wrong size"); |
| 39 | static_assert(std::is_trivially_copyable_v<Header>, "UDP Message Header is not trivially copyable"); | 40 | static_assert(std::is_trivially_copyable_v<Header>, "UDP Message Header is not trivially copyable"); |
| 40 | 41 | ||
| @@ -54,7 +55,9 @@ constexpr Type GetMessageType(); | |||
| 54 | 55 | ||
| 55 | namespace Request { | 56 | namespace Request { |
| 56 | 57 | ||
| 57 | struct Version {}; | 58 | struct Version { |
| 59 | }; | ||
| 60 | |||
| 58 | /** | 61 | /** |
| 59 | * Requests the server to send information about what controllers are plugged into the ports | 62 | * Requests the server to send information about what controllers are plugged into the ports |
| 60 | * In citra's case, we only have one controller, so for simplicity's sake, we can just send a | 63 | * In citra's case, we only have one controller, so for simplicity's sake, we can just send a |
| @@ -62,12 +65,14 @@ struct Version {}; | |||
| 62 | * nice to make this configurable | 65 | * nice to make this configurable |
| 63 | */ | 66 | */ |
| 64 | constexpr u32 MAX_PORTS = 4; | 67 | constexpr u32 MAX_PORTS = 4; |
| 68 | |||
| 65 | struct PortInfo { | 69 | struct PortInfo { |
| 66 | u32_le pad_count{}; ///> Number of ports to request data for | 70 | u32_le pad_count{}; ///> Number of ports to request data for |
| 67 | std::array<u8, MAX_PORTS> port; | 71 | std::array<u8, MAX_PORTS> port; |
| 68 | }; | 72 | }; |
| 73 | |||
| 69 | static_assert(std::is_trivially_copyable_v<PortInfo>, | 74 | static_assert(std::is_trivially_copyable_v<PortInfo>, |
| 70 | "UDP Request PortInfo is not trivially copyable"); | 75 | "UDP Request PortInfo is not trivially copyable"); |
| 71 | 76 | ||
| 72 | /** | 77 | /** |
| 73 | * Request the latest pad information from the server. If the server hasn't received this message | 78 | * Request the latest pad information from the server. If the server hasn't received this message |
| @@ -80,6 +85,7 @@ struct PadData { | |||
| 80 | Id, | 85 | Id, |
| 81 | Mac, | 86 | Mac, |
| 82 | }; | 87 | }; |
| 88 | |||
| 83 | /// Determines which method will be used as a look up for the controller | 89 | /// Determines which method will be used as a look up for the controller |
| 84 | Flags flags{}; | 90 | Flags flags{}; |
| 85 | /// Index of the port of the controller to retrieve data about | 91 | /// Index of the port of the controller to retrieve data about |
| @@ -87,9 +93,10 @@ struct PadData { | |||
| 87 | /// Mac address of the controller to retrieve data about | 93 | /// Mac address of the controller to retrieve data about |
| 88 | MacAddress mac; | 94 | MacAddress mac; |
| 89 | }; | 95 | }; |
| 96 | |||
| 90 | static_assert(sizeof(PadData) == 8, "UDP Request PadData struct has wrong size"); | 97 | static_assert(sizeof(PadData) == 8, "UDP Request PadData struct has wrong size"); |
| 91 | static_assert(std::is_trivially_copyable_v<PadData>, | 98 | static_assert(std::is_trivially_copyable_v<PadData>, |
| 92 | "UDP Request PadData is not trivially copyable"); | 99 | "UDP Request PadData is not trivially copyable"); |
| 93 | 100 | ||
| 94 | /** | 101 | /** |
| 95 | * Creates a message with the proper header data that can be sent to the server. | 102 | * Creates a message with the proper header data that can be sent to the server. |
| @@ -114,9 +121,10 @@ namespace Response { | |||
| 114 | struct Version { | 121 | struct Version { |
| 115 | u16_le version{}; | 122 | u16_le version{}; |
| 116 | }; | 123 | }; |
| 124 | |||
| 117 | static_assert(sizeof(Version) == 2, "UDP Response Version struct has wrong size"); | 125 | static_assert(sizeof(Version) == 2, "UDP Response Version struct has wrong size"); |
| 118 | static_assert(std::is_trivially_copyable_v<Version>, | 126 | static_assert(std::is_trivially_copyable_v<Version>, |
| 119 | "UDP Response Version is not trivially copyable"); | 127 | "UDP Response Version is not trivially copyable"); |
| 120 | 128 | ||
| 121 | struct PortInfo { | 129 | struct PortInfo { |
| 122 | u8 id{}; | 130 | u8 id{}; |
| @@ -127,9 +135,10 @@ struct PortInfo { | |||
| 127 | u8 battery{}; | 135 | u8 battery{}; |
| 128 | u8 is_pad_active{}; | 136 | u8 is_pad_active{}; |
| 129 | }; | 137 | }; |
| 138 | |||
| 130 | static_assert(sizeof(PortInfo) == 12, "UDP Response PortInfo struct has wrong size"); | 139 | static_assert(sizeof(PortInfo) == 12, "UDP Response PortInfo struct has wrong size"); |
| 131 | static_assert(std::is_trivially_copyable_v<PortInfo>, | 140 | static_assert(std::is_trivially_copyable_v<PortInfo>, |
| 132 | "UDP Response PortInfo is not trivially copyable"); | 141 | "UDP Response PortInfo is not trivially copyable"); |
| 133 | 142 | ||
| 134 | #pragma pack(push, 1) | 143 | #pragma pack(push, 1) |
| 135 | struct PadData { | 144 | struct PadData { |
| @@ -206,16 +215,16 @@ struct PadData { | |||
| 206 | 215 | ||
| 207 | static_assert(sizeof(PadData) == 80, "UDP Response PadData struct has wrong size "); | 216 | static_assert(sizeof(PadData) == 80, "UDP Response PadData struct has wrong size "); |
| 208 | static_assert(std::is_trivially_copyable_v<PadData>, | 217 | static_assert(std::is_trivially_copyable_v<PadData>, |
| 209 | "UDP Response PadData is not trivially copyable"); | 218 | "UDP Response PadData is not trivially copyable"); |
| 210 | 219 | ||
| 211 | static_assert(sizeof(Message<PadData>) == MAX_PACKET_SIZE, | 220 | static_assert(sizeof(Message<PadData>) == MAX_PACKET_SIZE, |
| 212 | "UDP MAX_PACKET_SIZE is no longer larger than Message<PadData>"); | 221 | "UDP MAX_PACKET_SIZE is no longer larger than Message<PadData>"); |
| 213 | 222 | ||
| 214 | static_assert(sizeof(PadData::AnalogButton) == 12, | 223 | static_assert(sizeof(PadData::AnalogButton) == 12, |
| 215 | "UDP Response AnalogButton struct has wrong size "); | 224 | "UDP Response AnalogButton struct has wrong size "); |
| 216 | static_assert(sizeof(PadData::TouchPad) == 6, "UDP Response TouchPad struct has wrong size "); | 225 | static_assert(sizeof(PadData::TouchPad) == 6, "UDP Response TouchPad struct has wrong size "); |
| 217 | static_assert(sizeof(PadData::Accelerometer) == 12, | 226 | static_assert(sizeof(PadData::Accelerometer) == 12, |
| 218 | "UDP Response Accelerometer struct has wrong size "); | 227 | "UDP Response Accelerometer struct has wrong size "); |
| 219 | static_assert(sizeof(PadData::Gyroscope) == 12, "UDP Response Gyroscope struct has wrong size "); | 228 | static_assert(sizeof(PadData::Gyroscope) == 12, "UDP Response Gyroscope struct has wrong size "); |
| 220 | 229 | ||
| 221 | /** | 230 | /** |
| @@ -232,22 +241,27 @@ template <> | |||
| 232 | constexpr Type GetMessageType<Request::Version>() { | 241 | constexpr Type GetMessageType<Request::Version>() { |
| 233 | return Type::Version; | 242 | return Type::Version; |
| 234 | } | 243 | } |
| 244 | |||
| 235 | template <> | 245 | template <> |
| 236 | constexpr Type GetMessageType<Request::PortInfo>() { | 246 | constexpr Type GetMessageType<Request::PortInfo>() { |
| 237 | return Type::PortInfo; | 247 | return Type::PortInfo; |
| 238 | } | 248 | } |
| 249 | |||
| 239 | template <> | 250 | template <> |
| 240 | constexpr Type GetMessageType<Request::PadData>() { | 251 | constexpr Type GetMessageType<Request::PadData>() { |
| 241 | return Type::PadData; | 252 | return Type::PadData; |
| 242 | } | 253 | } |
| 254 | |||
| 243 | template <> | 255 | template <> |
| 244 | constexpr Type GetMessageType<Response::Version>() { | 256 | constexpr Type GetMessageType<Response::Version>() { |
| 245 | return Type::Version; | 257 | return Type::Version; |
| 246 | } | 258 | } |
| 259 | |||
| 247 | template <> | 260 | template <> |
| 248 | constexpr Type GetMessageType<Response::PortInfo>() { | 261 | constexpr Type GetMessageType<Response::PortInfo>() { |
| 249 | return Type::PortInfo; | 262 | return Type::PortInfo; |
| 250 | } | 263 | } |
| 264 | |||
| 251 | template <> | 265 | template <> |
| 252 | constexpr Type GetMessageType<Response::PadData>() { | 266 | constexpr Type GetMessageType<Response::PadData>() { |
| 253 | return Type::PadData; | 267 | return Type::PadData; |
diff --git a/src/input_common/udp/udp.cpp b/src/input_common/udp/udp.cpp index 8c6ef1394..343c3985e 100644 --- a/src/input_common/udp/udp.cpp +++ b/src/input_common/udp/udp.cpp | |||
| @@ -16,7 +16,10 @@ namespace InputCommon::CemuhookUDP { | |||
| 16 | 16 | ||
| 17 | class UDPTouchDevice final : public Input::TouchDevice { | 17 | class UDPTouchDevice final : public Input::TouchDevice { |
| 18 | public: | 18 | public: |
| 19 | explicit UDPTouchDevice(std::shared_ptr<DeviceStatus> status_) : status(std::move(status_)) {} | 19 | explicit UDPTouchDevice(std::shared_ptr<DeviceStatus> status_) |
| 20 | : status(std::move(status_)) { | ||
| 21 | } | ||
| 22 | |||
| 20 | std::tuple<float, float, bool> GetStatus() const override { | 23 | std::tuple<float, float, bool> GetStatus() const override { |
| 21 | std::lock_guard guard(status->update_mutex); | 24 | std::lock_guard guard(status->update_mutex); |
| 22 | return status->touch_status; | 25 | return status->touch_status; |
| @@ -28,7 +31,10 @@ private: | |||
| 28 | 31 | ||
| 29 | class UDPMotionDevice final : public Input::MotionDevice { | 32 | class UDPMotionDevice final : public Input::MotionDevice { |
| 30 | public: | 33 | public: |
| 31 | explicit UDPMotionDevice(std::shared_ptr<DeviceStatus> status_) : status(std::move(status_)) {} | 34 | explicit UDPMotionDevice(std::shared_ptr<DeviceStatus> status_) |
| 35 | : status(std::move(status_)) { | ||
| 36 | } | ||
| 37 | |||
| 32 | std::tuple<Common::Vec3<float>, Common::Vec3<float>> GetStatus() const override { | 38 | std::tuple<Common::Vec3<float>, Common::Vec3<float>> GetStatus() const override { |
| 33 | std::lock_guard guard(status->update_mutex); | 39 | std::lock_guard guard(status->update_mutex); |
| 34 | return status->motion_status; | 40 | return status->motion_status; |
| @@ -40,7 +46,9 @@ private: | |||
| 40 | 46 | ||
| 41 | class UDPTouchFactory final : public Input::Factory<Input::TouchDevice> { | 47 | class UDPTouchFactory final : public Input::Factory<Input::TouchDevice> { |
| 42 | public: | 48 | public: |
| 43 | explicit UDPTouchFactory(std::shared_ptr<DeviceStatus> status_) : status(std::move(status_)) {} | 49 | explicit UDPTouchFactory(std::shared_ptr<DeviceStatus> status_) |
| 50 | : status(std::move(status_)) { | ||
| 51 | } | ||
| 44 | 52 | ||
| 45 | std::unique_ptr<Input::TouchDevice> Create(const Common::ParamPackage& params) override { | 53 | std::unique_ptr<Input::TouchDevice> Create(const Common::ParamPackage& params) override { |
| 46 | { | 54 | { |
| @@ -61,7 +69,9 @@ private: | |||
| 61 | 69 | ||
| 62 | class UDPMotionFactory final : public Input::Factory<Input::MotionDevice> { | 70 | class UDPMotionFactory final : public Input::Factory<Input::MotionDevice> { |
| 63 | public: | 71 | public: |
| 64 | explicit UDPMotionFactory(std::shared_ptr<DeviceStatus> status_) : status(std::move(status_)) {} | 72 | explicit UDPMotionFactory(std::shared_ptr<DeviceStatus> status_) |
| 73 | : status(std::move(status_)) { | ||
| 74 | } | ||
| 65 | 75 | ||
| 66 | std::unique_ptr<Input::MotionDevice> Create(const Common::ParamPackage& params) override { | 76 | std::unique_ptr<Input::MotionDevice> Create(const Common::ParamPackage& params) override { |
| 67 | return std::make_unique<UDPMotionDevice>(status); | 77 | return std::make_unique<UDPMotionDevice>(status); |
diff --git a/src/yuzu/configuration/configure_input_player.cpp b/src/yuzu/configuration/configure_input_player.cpp index a05fa64ba..81436af1b 100644 --- a/src/yuzu/configuration/configure_input_player.cpp +++ b/src/yuzu/configuration/configure_input_player.cpp | |||
| @@ -19,13 +19,13 @@ | |||
| 19 | #include "yuzu/configuration/configure_input_player.h" | 19 | #include "yuzu/configuration/configure_input_player.h" |
| 20 | 20 | ||
| 21 | const std::array<std::string, ConfigureInputPlayer::ANALOG_SUB_BUTTONS_NUM> | 21 | const std::array<std::string, ConfigureInputPlayer::ANALOG_SUB_BUTTONS_NUM> |
| 22 | ConfigureInputPlayer::analog_sub_buttons{{ | 22 | ConfigureInputPlayer::analog_sub_buttons{{ |
| 23 | "up", | 23 | "up", |
| 24 | "down", | 24 | "down", |
| 25 | "left", | 25 | "left", |
| 26 | "right", | 26 | "right", |
| 27 | "modifier", | 27 | "modifier", |
| 28 | }}; | 28 | }}; |
| 29 | 29 | ||
| 30 | static void LayerGridElements(QGridLayout* grid, QWidget* item, QWidget* onTopOf) { | 30 | static void LayerGridElements(QGridLayout* grid, QWidget* item, QWidget* onTopOf) { |
| 31 | const int index1 = grid->indexOf(item); | 31 | const int index1 = grid->indexOf(item); |
| @@ -70,6 +70,20 @@ static QString ButtonToText(const Common::ParamPackage& param) { | |||
| 70 | return GetKeyName(param.Get("code", 0)); | 70 | return GetKeyName(param.Get("code", 0)); |
| 71 | } | 71 | } |
| 72 | 72 | ||
| 73 | if (param.Get("engine", "") == "gcpad") { | ||
| 74 | if (param.Has("axis")) { | ||
| 75 | const QString axis_str = QString::fromStdString(param.Get("axis", "")); | ||
| 76 | const QString direction_str = QString::fromStdString(param.Get("direction", "")); | ||
| 77 | |||
| 78 | return QObject::tr("Axis %1%2").arg(axis_str, direction_str); | ||
| 79 | } | ||
| 80 | if (param.Has("button")) { | ||
| 81 | const QString button_str = QString::number(int(std::log2(param.Get("button", 0)))); | ||
| 82 | return QObject::tr("Button %1").arg(button_str); | ||
| 83 | } | ||
| 84 | return GetKeyName(param.Get("code", 0)); | ||
| 85 | } | ||
| 86 | |||
| 73 | if (param.Get("engine", "") == "sdl") { | 87 | if (param.Get("engine", "") == "sdl") { |
| 74 | if (param.Has("hat")) { | 88 | if (param.Has("hat")) { |
| 75 | const QString hat_str = QString::fromStdString(param.Get("hat", "")); | 89 | const QString hat_str = QString::fromStdString(param.Get("hat", "")); |
| @@ -106,7 +120,7 @@ static QString AnalogToText(const Common::ParamPackage& param, const std::string | |||
| 106 | return ButtonToText(Common::ParamPackage{param.Get(dir, "")}); | 120 | return ButtonToText(Common::ParamPackage{param.Get(dir, "")}); |
| 107 | } | 121 | } |
| 108 | 122 | ||
| 109 | if (param.Get("engine", "") == "sdl") { | 123 | if (param.Get("engine", "") == "sdl" || param.Get("engine", "") == "gcpad") { |
| 110 | if (dir == "modifier") { | 124 | if (dir == "modifier") { |
| 111 | return QObject::tr("[unused]"); | 125 | return QObject::tr("[unused]"); |
| 112 | } | 126 | } |
| @@ -137,13 +151,13 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i | |||
| 137 | setFocusPolicy(Qt::ClickFocus); | 151 | setFocusPolicy(Qt::ClickFocus); |
| 138 | 152 | ||
| 139 | button_map = { | 153 | button_map = { |
| 140 | ui->buttonA, ui->buttonB, ui->buttonX, ui->buttonY, | 154 | ui->buttonA, ui->buttonB, ui->buttonX, ui->buttonY, |
| 141 | ui->buttonLStick, ui->buttonRStick, ui->buttonL, ui->buttonR, | 155 | ui->buttonLStick, ui->buttonRStick, ui->buttonL, ui->buttonR, |
| 142 | ui->buttonZL, ui->buttonZR, ui->buttonPlus, ui->buttonMinus, | 156 | ui->buttonZL, ui->buttonZR, ui->buttonPlus, ui->buttonMinus, |
| 143 | ui->buttonDpadLeft, ui->buttonDpadUp, ui->buttonDpadRight, ui->buttonDpadDown, | 157 | ui->buttonDpadLeft, ui->buttonDpadUp, ui->buttonDpadRight, ui->buttonDpadDown, |
| 144 | ui->buttonLStickLeft, ui->buttonLStickUp, ui->buttonLStickRight, ui->buttonLStickDown, | 158 | ui->buttonLStickLeft, ui->buttonLStickUp, ui->buttonLStickRight, ui->buttonLStickDown, |
| 145 | ui->buttonRStickLeft, ui->buttonRStickUp, ui->buttonRStickRight, ui->buttonRStickDown, | 159 | ui->buttonRStickLeft, ui->buttonRStickUp, ui->buttonRStickRight, ui->buttonRStickDown, |
| 146 | ui->buttonSL, ui->buttonSR, ui->buttonHome, ui->buttonScreenshot, | 160 | ui->buttonSL, ui->buttonSR, ui->buttonHome, ui->buttonScreenshot, |
| 147 | }; | 161 | }; |
| 148 | 162 | ||
| 149 | analog_map_buttons = {{ | 163 | analog_map_buttons = {{ |
| @@ -164,11 +178,11 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i | |||
| 164 | }}; | 178 | }}; |
| 165 | 179 | ||
| 166 | debug_hidden = { | 180 | debug_hidden = { |
| 167 | ui->buttonSL, ui->labelSL, | 181 | ui->buttonSL, ui->labelSL, |
| 168 | ui->buttonSR, ui->labelSR, | 182 | ui->buttonSR, ui->labelSR, |
| 169 | ui->buttonLStick, ui->labelLStickPressed, | 183 | ui->buttonLStick, ui->labelLStickPressed, |
| 170 | ui->buttonRStick, ui->labelRStickPressed, | 184 | ui->buttonRStick, ui->labelRStickPressed, |
| 171 | ui->buttonHome, ui->labelHome, | 185 | ui->buttonHome, ui->labelHome, |
| 172 | ui->buttonScreenshot, ui->labelScreenshot, | 186 | ui->buttonScreenshot, ui->labelScreenshot, |
| 173 | }; | 187 | }; |
| 174 | 188 | ||
| @@ -207,12 +221,12 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i | |||
| 207 | case Settings::ControllerType::RightJoycon: | 221 | case Settings::ControllerType::RightJoycon: |
| 208 | layout_hidden = { | 222 | layout_hidden = { |
| 209 | ui->left_body_button, ui->left_buttons_button, | 223 | ui->left_body_button, ui->left_buttons_button, |
| 210 | ui->left_body_label, ui->left_buttons_label, | 224 | ui->left_body_label, ui->left_buttons_label, |
| 211 | ui->buttonL, ui->labelL, | 225 | ui->buttonL, ui->labelL, |
| 212 | ui->buttonZL, ui->labelZL, | 226 | ui->buttonZL, ui->labelZL, |
| 213 | ui->labelScreenshot, ui->buttonScreenshot, | 227 | ui->labelScreenshot, ui->buttonScreenshot, |
| 214 | ui->buttonMinus, ui->labelMinus, | 228 | ui->buttonMinus, ui->labelMinus, |
| 215 | ui->LStick, ui->Dpad, | 229 | ui->LStick, ui->Dpad, |
| 216 | }; | 230 | }; |
| 217 | break; | 231 | break; |
| 218 | } | 232 | } |
| @@ -247,9 +261,11 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i | |||
| 247 | } | 261 | } |
| 248 | 262 | ||
| 249 | button->setContextMenuPolicy(Qt::CustomContextMenu); | 263 | button->setContextMenuPolicy(Qt::CustomContextMenu); |
| 250 | connect(button, &QPushButton::clicked, [=] { | 264 | connect(button, &QPushButton::clicked, [=] |
| 265 | { | ||
| 251 | HandleClick(button_map[button_id], | 266 | HandleClick(button_map[button_id], |
| 252 | [=](Common::ParamPackage params) { | 267 | [=](Common::ParamPackage params) |
| 268 | { | ||
| 253 | // Workaround for ZL & ZR for analog triggers like on XBOX controllors. | 269 | // Workaround for ZL & ZR for analog triggers like on XBOX controllors. |
| 254 | // Analog triggers (from controllers like the XBOX controller) would not | 270 | // Analog triggers (from controllers like the XBOX controller) would not |
| 255 | // work due to a different range of their signals (from 0 to 255 on | 271 | // work due to a different range of their signals (from 0 to 255 on |
| @@ -267,13 +283,16 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i | |||
| 267 | }, | 283 | }, |
| 268 | InputCommon::Polling::DeviceType::Button); | 284 | InputCommon::Polling::DeviceType::Button); |
| 269 | }); | 285 | }); |
| 270 | connect(button, &QPushButton::customContextMenuRequested, [=](const QPoint& menu_location) { | 286 | connect(button, &QPushButton::customContextMenuRequested, [=](const QPoint& menu_location) |
| 287 | { | ||
| 271 | QMenu context_menu; | 288 | QMenu context_menu; |
| 272 | context_menu.addAction(tr("Clear"), [&] { | 289 | context_menu.addAction(tr("Clear"), [&] |
| 290 | { | ||
| 273 | buttons_param[button_id].Clear(); | 291 | buttons_param[button_id].Clear(); |
| 274 | button_map[button_id]->setText(tr("[not set]")); | 292 | button_map[button_id]->setText(tr("[not set]")); |
| 275 | }); | 293 | }); |
| 276 | context_menu.addAction(tr("Restore Default"), [&] { | 294 | context_menu.addAction(tr("Restore Default"), [&] |
| 295 | { | ||
| 277 | buttons_param[button_id] = Common::ParamPackage{ | 296 | buttons_param[button_id] = Common::ParamPackage{ |
| 278 | InputCommon::GenerateKeyboardParam(Config::default_buttons[button_id])}; | 297 | InputCommon::GenerateKeyboardParam(Config::default_buttons[button_id])}; |
| 279 | button_map[button_id]->setText(ButtonToText(buttons_param[button_id])); | 298 | button_map[button_id]->setText(ButtonToText(buttons_param[button_id])); |
| @@ -290,22 +309,27 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i | |||
| 290 | } | 309 | } |
| 291 | 310 | ||
| 292 | analog_button->setContextMenuPolicy(Qt::CustomContextMenu); | 311 | analog_button->setContextMenuPolicy(Qt::CustomContextMenu); |
| 293 | connect(analog_button, &QPushButton::clicked, [=]() { | 312 | connect(analog_button, &QPushButton::clicked, [=]() |
| 313 | { | ||
| 294 | HandleClick(analog_map_buttons[analog_id][sub_button_id], | 314 | HandleClick(analog_map_buttons[analog_id][sub_button_id], |
| 295 | [=](const Common::ParamPackage& params) { | 315 | [=](const Common::ParamPackage& params) |
| 316 | { | ||
| 296 | SetAnalogButton(params, analogs_param[analog_id], | 317 | SetAnalogButton(params, analogs_param[analog_id], |
| 297 | analog_sub_buttons[sub_button_id]); | 318 | analog_sub_buttons[sub_button_id]); |
| 298 | }, | 319 | }, |
| 299 | InputCommon::Polling::DeviceType::Button); | 320 | InputCommon::Polling::DeviceType::Button); |
| 300 | }); | 321 | }); |
| 301 | connect(analog_button, &QPushButton::customContextMenuRequested, | 322 | connect(analog_button, &QPushButton::customContextMenuRequested, |
| 302 | [=](const QPoint& menu_location) { | 323 | [=](const QPoint& menu_location) |
| 324 | { | ||
| 303 | QMenu context_menu; | 325 | QMenu context_menu; |
| 304 | context_menu.addAction(tr("Clear"), [&] { | 326 | context_menu.addAction(tr("Clear"), [&] |
| 327 | { | ||
| 305 | analogs_param[analog_id].Erase(analog_sub_buttons[sub_button_id]); | 328 | analogs_param[analog_id].Erase(analog_sub_buttons[sub_button_id]); |
| 306 | analog_map_buttons[analog_id][sub_button_id]->setText(tr("[not set]")); | 329 | analog_map_buttons[analog_id][sub_button_id]->setText(tr("[not set]")); |
| 307 | }); | 330 | }); |
| 308 | context_menu.addAction(tr("Restore Default"), [&] { | 331 | context_menu.addAction(tr("Restore Default"), [&] |
| 332 | { | ||
| 309 | Common::ParamPackage params{InputCommon::GenerateKeyboardParam( | 333 | Common::ParamPackage params{InputCommon::GenerateKeyboardParam( |
| 310 | Config::default_analogs[analog_id][sub_button_id])}; | 334 | Config::default_analogs[analog_id][sub_button_id])}; |
| 311 | SetAnalogButton(params, analogs_param[analog_id], | 335 | SetAnalogButton(params, analogs_param[analog_id], |
| @@ -317,11 +341,12 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i | |||
| 317 | menu_location)); | 341 | menu_location)); |
| 318 | }); | 342 | }); |
| 319 | } | 343 | } |
| 320 | connect(analog_map_stick[analog_id], &QPushButton::clicked, [=] { | 344 | connect(analog_map_stick[analog_id], &QPushButton::clicked, [=] |
| 345 | { | ||
| 321 | if (QMessageBox::information( | 346 | if (QMessageBox::information( |
| 322 | this, tr("Information"), | 347 | this, tr("Information"), |
| 323 | tr("After pressing OK, first move your joystick horizontally, " | 348 | tr("After pressing OK, first move your joystick horizontally, " |
| 324 | "and then vertically."), | 349 | "and then vertically."), |
| 325 | QMessageBox::Ok | QMessageBox::Cancel) == QMessageBox::Ok) { | 350 | QMessageBox::Ok | QMessageBox::Cancel) == QMessageBox::Ok) { |
| 326 | HandleClick( | 351 | HandleClick( |
| 327 | analog_map_stick[analog_id], | 352 | analog_map_stick[analog_id], |
| @@ -330,9 +355,11 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i | |||
| 330 | } | 355 | } |
| 331 | }); | 356 | }); |
| 332 | 357 | ||
| 333 | connect(analog_map_deadzone_and_modifier_slider[analog_id], &QSlider::valueChanged, [=] { | 358 | connect(analog_map_deadzone_and_modifier_slider[analog_id], &QSlider::valueChanged, [=] |
| 359 | { | ||
| 334 | const float slider_value = analog_map_deadzone_and_modifier_slider[analog_id]->value(); | 360 | const float slider_value = analog_map_deadzone_and_modifier_slider[analog_id]->value(); |
| 335 | if (analogs_param[analog_id].Get("engine", "") == "sdl") { | 361 | if (analogs_param[analog_id].Get("engine", "") == "sdl" || |
| 362 | analogs_param[analog_id].Get("engine", "") == "gcpad") { | ||
| 336 | analog_map_deadzone_and_modifier_slider_label[analog_id]->setText( | 363 | analog_map_deadzone_and_modifier_slider_label[analog_id]->setText( |
| 337 | tr("Deadzone: %1%").arg(slider_value)); | 364 | tr("Deadzone: %1%").arg(slider_value)); |
| 338 | analogs_param[analog_id].Set("deadzone", slider_value / 100.0f); | 365 | analogs_param[analog_id].Set("deadzone", slider_value / 100.0f); |
| @@ -350,8 +377,23 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i | |||
| 350 | timeout_timer->setSingleShot(true); | 377 | timeout_timer->setSingleShot(true); |
| 351 | connect(timeout_timer.get(), &QTimer::timeout, [this] { SetPollingResult({}, true); }); | 378 | connect(timeout_timer.get(), &QTimer::timeout, [this] { SetPollingResult({}, true); }); |
| 352 | 379 | ||
| 353 | connect(poll_timer.get(), &QTimer::timeout, [this] { | 380 | connect(poll_timer.get(), &QTimer::timeout, [this] |
| 381 | { | ||
| 354 | Common::ParamPackage params; | 382 | Common::ParamPackage params; |
| 383 | if (InputCommon::GetGCButtons()->IsPolling()) { | ||
| 384 | params = InputCommon::GetGCButtons()->GetNextInput(); | ||
| 385 | if (params.Has("engine")) { | ||
| 386 | SetPollingResult(params, false); | ||
| 387 | return; | ||
| 388 | } | ||
| 389 | } | ||
| 390 | if (InputCommon::GetGCAnalogs()->IsPolling()) { | ||
| 391 | params = InputCommon::GetGCAnalogs()->GetNextInput(); | ||
| 392 | if (params.Has("engine")) { | ||
| 393 | SetPollingResult(params, false); | ||
| 394 | return; | ||
| 395 | } | ||
| 396 | } | ||
| 355 | for (auto& poller : device_pollers) { | 397 | for (auto& poller : device_pollers) { |
| 356 | params = poller->GetNextInput(); | 398 | params = poller->GetNextInput(); |
| 357 | if (params.Has("engine")) { | 399 | if (params.Has("engine")) { |
| @@ -463,7 +505,7 @@ void ConfigureInputPlayer::LoadConfiguration() { | |||
| 463 | for (std::size_t i = 0; i < colors.size(); ++i) { | 505 | for (std::size_t i = 0; i < colors.size(); ++i) { |
| 464 | controller_color_buttons[i]->setStyleSheet( | 506 | controller_color_buttons[i]->setStyleSheet( |
| 465 | QStringLiteral("QPushButton { background-color: %1 }") | 507 | QStringLiteral("QPushButton { background-color: %1 }") |
| 466 | .arg(controller_colors[i].name())); | 508 | .arg(controller_colors[i].name())); |
| 467 | } | 509 | } |
| 468 | } | 510 | } |
| 469 | 511 | ||
| @@ -534,7 +576,7 @@ void ConfigureInputPlayer::UpdateButtonLabels() { | |||
| 534 | analog_map_deadzone_and_modifier_slider_label[analog_id]; | 576 | analog_map_deadzone_and_modifier_slider_label[analog_id]; |
| 535 | 577 | ||
| 536 | if (param.Has("engine")) { | 578 | if (param.Has("engine")) { |
| 537 | if (param.Get("engine", "") == "sdl") { | 579 | if (param.Get("engine", "") == "sdl" || param.Get("engine", "") == "gcpad") { |
| 538 | if (!param.Has("deadzone")) { | 580 | if (!param.Has("deadzone")) { |
| 539 | param.Set("deadzone", 0.1f); | 581 | param.Set("deadzone", 0.1f); |
| 540 | } | 582 | } |
| @@ -583,6 +625,10 @@ void ConfigureInputPlayer::HandleClick( | |||
| 583 | 625 | ||
| 584 | grabKeyboard(); | 626 | grabKeyboard(); |
| 585 | grabMouse(); | 627 | grabMouse(); |
| 628 | if (type == InputCommon::Polling::DeviceType::Button) | ||
| 629 | InputCommon::GetGCButtons()->BeginConfiguration(); | ||
| 630 | else | ||
| 631 | InputCommon::GetGCAnalogs()->BeginConfiguration(); | ||
| 586 | timeout_timer->start(5000); // Cancel after 5 seconds | 632 | timeout_timer->start(5000); // Cancel after 5 seconds |
| 587 | poll_timer->start(200); // Check for new inputs every 200ms | 633 | poll_timer->start(200); // Check for new inputs every 200ms |
| 588 | } | 634 | } |
| @@ -596,6 +642,9 @@ void ConfigureInputPlayer::SetPollingResult(const Common::ParamPackage& params, | |||
| 596 | poller->Stop(); | 642 | poller->Stop(); |
| 597 | } | 643 | } |
| 598 | 644 | ||
| 645 | InputCommon::GetGCButtons()->EndConfiguration(); | ||
| 646 | InputCommon::GetGCAnalogs()->EndConfiguration(); | ||
| 647 | |||
| 599 | if (!abort) { | 648 | if (!abort) { |
| 600 | (*input_setter)(params); | 649 | (*input_setter)(params); |
| 601 | } | 650 | } |
diff --git a/src/yuzu/configuration/configure_input_player.h b/src/yuzu/configuration/configure_input_player.h index 95afa5375..dad2a80ec 100644 --- a/src/yuzu/configuration/configure_input_player.h +++ b/src/yuzu/configuration/configure_input_player.h | |||
| @@ -31,7 +31,7 @@ class ConfigureInputPlayer; | |||
| 31 | } | 31 | } |
| 32 | 32 | ||
| 33 | class ConfigureInputPlayer : public QDialog { | 33 | class ConfigureInputPlayer : public QDialog { |
| 34 | Q_OBJECT | 34 | Q_OBJECT |
| 35 | 35 | ||
| 36 | public: | 36 | public: |
| 37 | explicit ConfigureInputPlayer(QWidget* parent, std::size_t player_index, bool debug = false); | 37 | explicit ConfigureInputPlayer(QWidget* parent, std::size_t player_index, bool debug = false); |
| @@ -92,15 +92,15 @@ private: | |||
| 92 | /// A group of five QPushButtons represent one analog input. The buttons each represent up, | 92 | /// A group of five QPushButtons represent one analog input. The buttons each represent up, |
| 93 | /// down, left, right, and modifier, respectively. | 93 | /// down, left, right, and modifier, respectively. |
| 94 | std::array<std::array<QPushButton*, ANALOG_SUB_BUTTONS_NUM>, Settings::NativeAnalog::NumAnalogs> | 94 | std::array<std::array<QPushButton*, ANALOG_SUB_BUTTONS_NUM>, Settings::NativeAnalog::NumAnalogs> |
| 95 | analog_map_buttons; | 95 | analog_map_buttons; |
| 96 | 96 | ||
| 97 | /// Analog inputs are also represented each with a single button, used to configure with an | 97 | /// Analog inputs are also represented each with a single button, used to configure with an |
| 98 | /// actual analog stick | 98 | /// actual analog stick |
| 99 | std::array<QPushButton*, Settings::NativeAnalog::NumAnalogs> analog_map_stick; | 99 | std::array<QPushButton*, Settings::NativeAnalog::NumAnalogs> analog_map_stick; |
| 100 | std::array<QSlider*, Settings::NativeAnalog::NumAnalogs> | 100 | std::array<QSlider*, Settings::NativeAnalog::NumAnalogs> |
| 101 | analog_map_deadzone_and_modifier_slider; | 101 | analog_map_deadzone_and_modifier_slider; |
| 102 | std::array<QLabel*, Settings::NativeAnalog::NumAnalogs> | 102 | std::array<QLabel*, Settings::NativeAnalog::NumAnalogs> |
| 103 | analog_map_deadzone_and_modifier_slider_label; | 103 | analog_map_deadzone_and_modifier_slider_label; |
| 104 | 104 | ||
| 105 | static const std::array<std::string, ANALOG_SUB_BUTTONS_NUM> analog_sub_buttons; | 105 | static const std::array<std::string, ANALOG_SUB_BUTTONS_NUM> analog_sub_buttons; |
| 106 | 106 | ||