diff --git a/src/citra_qt/configuration/config.cpp b/src/citra_qt/configuration/config.cpp index 0e7777911..7ebdf8712 100644 --- a/src/citra_qt/configuration/config.cpp +++ b/src/citra_qt/configuration/config.cpp @@ -403,8 +403,14 @@ void QtConfig::ReadControlValues() { ReadSetting(QStringLiteral("touch_device"), QStringLiteral("engine:emu_window")) .toString() .toStdString(); + profile.controller_touch_device = + ReadSetting(QStringLiteral("controller_touch_device"),QStringLiteral("")) + .toString() + .toStdString(); profile.use_touch_from_button = ReadSetting(QStringLiteral("use_touch_from_button"), false).toBool(); + profile.use_touchpad = + ReadSetting(QStringLiteral("use_touchpad"), false).toBool(); profile.touch_from_button_map_index = ReadSetting(QStringLiteral("touch_from_button_map"), 0).toInt(); profile.touch_from_button_map_index = @@ -988,6 +994,8 @@ void QtConfig::SaveControlValues() { WriteSetting(QStringLiteral("touch_device"), QString::fromStdString(profile.touch_device), QStringLiteral("engine:emu_window")); WriteSetting(QStringLiteral("use_touch_from_button"), profile.use_touch_from_button, false); + WriteSetting(QStringLiteral("use_touchpad"), profile.use_touchpad, false); + WriteSetting(QStringLiteral("controller_touch_device"), QString::fromStdString(profile.controller_touch_device), QStringLiteral("")); WriteSetting(QStringLiteral("touch_from_button_map"), profile.touch_from_button_map_index, 0); WriteSetting(QStringLiteral("udp_input_address"), diff --git a/src/citra_qt/configuration/configure_motion_touch.cpp b/src/citra_qt/configuration/configure_motion_touch.cpp index 24e05dad3..3f0dd567b 100644 --- a/src/citra_qt/configuration/configure_motion_touch.cpp +++ b/src/citra_qt/configuration/configure_motion_touch.cpp @@ -139,6 +139,8 @@ void ConfigureMotionTouch::SetConfiguration() { ui->touch_provider->findData(QString::fromStdString(touch_engine))); ui->touch_from_button_checkbox->setChecked( Settings::values.current_input_profile.use_touch_from_button); + ui->touchpad_checkbox->setChecked( + Settings::values.current_input_profile.use_touchpad); touch_from_button_maps = Settings::values.touch_from_button_maps; for (const auto& touch_map : touch_from_button_maps) { ui->touch_from_button_map->addItem(QString::fromStdString(touch_map.name)); @@ -164,7 +166,9 @@ void ConfigureMotionTouch::SetConfiguration() { void ConfigureMotionTouch::UpdateUiDisplay() { const std::string motion_engine = ui->motion_provider->currentData().toString().toStdString(); const std::string touch_engine = ui->touch_provider->currentData().toString().toStdString(); - + ui->touchpad_config_btn->setEnabled( + ui->touchpad_checkbox->isChecked() + ); if (motion_engine == "motion_emu") { ui->motion_sensitivity_label->setVisible(true); ui->motion_sensitivity->setVisible(true); @@ -229,6 +233,32 @@ void ConfigureMotionTouch::ConnectEvents() { poll_timer->start(200); // Check for new inputs every 200ms } }); + connect(ui->touchpad_checkbox,&QCheckBox::checkStateChanged, this, [this]() {UpdateUiDisplay(); }); + connect(ui->touchpad_config_btn, &QPushButton::clicked, this, [this]() { + if (QMessageBox::information(this, tr("Information"), + tr("After pressing OK, tap the trackpad on the controller" + "that you want to track."), + QMessageBox::Ok | QMessageBox::Cancel) == QMessageBox::Ok) { + ui->touchpad_config_btn->setText(tr("[press touchpad]")); + ui->touchpad_config_btn->setFocus(); + + input_setter = [this](const Common::ParamPackage& params) { + tpguid = params.Get("guid", "0"); + tpport = params.Get("port", 0); + tp = params.Get("touchpad",0); + }; + + device_pollers = + InputCommon::Polling::GetPollers(InputCommon::Polling::DeviceType::Touchpad); + + for (auto& poller : device_pollers) { + poller->Start(); + } + + timeout_timer->start(5000); // Cancel after 5 seconds + poll_timer->start(200); // Check for new inputs every 200ms + } + }); connect(ui->udp_test, &QPushButton::clicked, this, &ConfigureMotionTouch::OnCemuhookUDPTest); connect(ui->touch_calibration_config, &QPushButton::clicked, this, &ConfigureMotionTouch::OnConfigureTouchCalibration); @@ -253,7 +283,7 @@ void ConfigureMotionTouch::SetPollingResult(const Common::ParamPackage& params, if (!abort && input_setter) { (*input_setter)(params); } - + ui->touchpad_config_btn->setText(tr("Configure")); ui->motion_controller_button->setText(tr("Configure")); input_setter.reset(); } @@ -291,7 +321,6 @@ void ConfigureMotionTouch::OnConfigureTouchCalibration() { "UDP touchpad calibration config success: min_x={}, min_y={}, max_x={}, max_y={}", min_x, min_y, max_x, max_y); UpdateUiDisplay(); - } else { LOG_ERROR(Frontend, "UDP touchpad calibration config failed"); } ui->touch_calibration_config->setEnabled(true); @@ -374,12 +403,22 @@ void ConfigureMotionTouch::ApplyConfiguration() { touch_param.Set("max_y", max_y); } + Common::ParamPackage touchpad_param{}; + if (ui->touchpad_checkbox->isChecked()) { + touchpad_param.Set("engine", "sdl"); + touchpad_param.Set("guid", tpguid); + touchpad_param.Set("port", tpport); + touchpad_param.Set("touchpad",tp); + } Settings::values.current_input_profile.motion_device = motion_param.Serialize(); Settings::values.current_input_profile.touch_device = touch_param.Serialize(); Settings::values.current_input_profile.use_touch_from_button = ui->touch_from_button_checkbox->isChecked(); Settings::values.current_input_profile.touch_from_button_map_index = ui->touch_from_button_map->currentIndex(); + Settings::values.current_input_profile.use_touchpad = + ui->touchpad_checkbox->isChecked(); + Settings::values.current_input_profile.controller_touch_device = touchpad_param.Serialize(); Settings::values.touch_from_button_maps = touch_from_button_maps; Settings::values.current_input_profile.udp_input_address = ui->udp_server->text().toStdString(); Settings::values.current_input_profile.udp_input_port = diff --git a/src/citra_qt/configuration/configure_motion_touch.h b/src/citra_qt/configuration/configure_motion_touch.h index 3b10f752a..7741c8ffa 100644 --- a/src/citra_qt/configuration/configure_motion_touch.h +++ b/src/citra_qt/configuration/configure_motion_touch.h @@ -76,6 +76,9 @@ private: // Used for SDL input polling std::string guid; int port; + std::string tpguid; // guid for touchpad + int tpport; //port for touchpad + int tp; //which touchpad std::unique_ptr timeout_timer; std::unique_ptr poll_timer; std::vector> device_pollers; diff --git a/src/citra_qt/configuration/configure_motion_touch.ui b/src/citra_qt/configuration/configure_motion_touch.ui index 7f4a5c36a..57f5177f0 100644 --- a/src/citra_qt/configuration/configure_motion_touch.ui +++ b/src/citra_qt/configuration/configure_motion_touch.ui @@ -2,17 +2,17 @@ ConfigureMotionTouch - - Configure Motion / Touch - 0 0 - 500 - 450 + 517 + 659 + + Configure Motion / Touch + @@ -175,6 +175,24 @@ + + + + + + Use controller (e.g. DualSense) touchpad + + + + + + + Configure + + + + + @@ -324,4 +342,5 @@ + diff --git a/src/citra_sdl/config.cpp b/src/citra_sdl/config.cpp index da800cc30..03ba9f173 100644 --- a/src/citra_sdl/config.cpp +++ b/src/citra_sdl/config.cpp @@ -121,6 +121,8 @@ void SdlConfig::ReadValues() { "engine:motion_emu,update_period:100,sensitivity:0.01,tilt_clamp:90.0"); Settings::values.current_input_profile.touch_device = sdl2_config->GetString("Controls", "touch_device", "engine:emu_window"); + Settings::values.current_input_profile.controller_touch_device = + sdl2_config->GetString("Controls","controller_touch_device",""); Settings::values.current_input_profile.udp_input_address = sdl2_config->GetString( "Controls", "udp_input_address", InputCommon::CemuhookUDP::DEFAULT_ADDR); Settings::values.current_input_profile.udp_input_port = diff --git a/src/common/settings.h b/src/common/settings.h index 77061db16..d9d9d082d 100644 --- a/src/common/settings.h +++ b/src/common/settings.h @@ -431,6 +431,8 @@ struct InputProfile { std::array analogs; std::string motion_device; std::string touch_device; + std::string controller_touch_device; + bool use_touchpad; bool use_touch_from_button; int touch_from_button_map_index; std::string udp_input_address; diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp index 81b833f34..30f20eeb9 100644 --- a/src/core/hle/service/hid/hid.cpp +++ b/src/core/hle/service/hid/hid.cpp @@ -115,6 +115,7 @@ DirectionState GetStickDirectionState(s16 circle_pad_x, s16 circle_pad_y) { } void Module::LoadInputDevices() { + LOG_DEBUG(Frontend,"Loading input devices"); std::transform(Settings::values.current_input_profile.buttons.begin() + Settings::NativeButton::BUTTON_HID_BEGIN, Settings::values.current_input_profile.buttons.begin() + @@ -126,6 +127,12 @@ void Module::LoadInputDevices() { Settings::values.current_input_profile.motion_device); touch_device = Input::CreateDevice( Settings::values.current_input_profile.touch_device); + if (Settings::values.current_input_profile.use_touchpad && + Settings::values.current_input_profile.controller_touch_device != "") { + controller_touch_device = Input::CreateDevice(Settings::values.current_input_profile.controller_touch_device); + } else { + controller_touch_device.reset(); + } if (Settings::values.current_input_profile.use_touch_from_button) { touch_btn_device = Input::CreateDevice("engine:touch_from_button"); } else { @@ -278,6 +285,9 @@ void Module::UpdatePadCallback(std::uintptr_t user_data, s64 cycles_late) { if (!pressed && touch_btn_device) { std::tie(x, y, pressed) = touch_btn_device->GetStatus(); } + if (!pressed && controller_touch_device) { + std::tie(x,y,pressed) = controller_touch_device->GetStatus(); + } touch_entry.x = static_cast(x * Core::kScreenBottomWidth); touch_entry.y = static_cast(y * Core::kScreenBottomHeight); touch_entry.valid.Assign(pressed ? 1 : 0); diff --git a/src/core/hle/service/hid/hid.h b/src/core/hle/service/hid/hid.h index 79713ca69..ca3ac637a 100644 --- a/src/core/hle/service/hid/hid.h +++ b/src/core/hle/service/hid/hid.h @@ -390,6 +390,7 @@ private: buttons; std::unique_ptr circle_pad; std::unique_ptr motion_device; + std::unique_ptr controller_touch_device; std::unique_ptr touch_device; std::unique_ptr touch_btn_device; diff --git a/src/input_common/main.h b/src/input_common/main.h index 48ecd26ba..6d797bca8 100644 --- a/src/input_common/main.h +++ b/src/input_common/main.h @@ -45,7 +45,7 @@ void ReloadInputDevices(); namespace Polling { -enum class DeviceType { Button, Analog }; +enum class DeviceType { Button, Analog, Touchpad}; /** * A class that can be used to get inputs from an input device like controllers without having to diff --git a/src/input_common/sdl/sdl_impl.cpp b/src/input_common/sdl/sdl_impl.cpp index 1833e49cb..9c75ea758 100644 --- a/src/input_common/sdl/sdl_impl.cpp +++ b/src/input_common/sdl/sdl_impl.cpp @@ -182,6 +182,11 @@ public: return has_gyro || has_accel; } + void SetTouchpad(float x, float y, int touchpad, bool down) { + std::lock_guard lock{mutex}; + state.touchpad[touchpad] = std::make_tuple(x, y, down); + } + void SetButton(int button, bool value) { std::lock_guard lock{mutex}; state.buttons[button] = value; @@ -246,6 +251,11 @@ public: return std::make_tuple(state.accel, state.gyro); } + std::tuple GetTouch(int pad) { + std::lock_guard lock{mutex}; + return state.touchpad[pad]; + } + /** * The guid of the joystick */ @@ -280,6 +290,7 @@ private: std::unordered_map hats; Common::Vec3 accel; Common::Vec3 gyro; + std::unordered_map> touchpad; } state; std::string guid; int port; @@ -590,6 +601,17 @@ void SDLState::HandleGameControllerEvent(const SDL_Event& event) { } break; } + case SDL_CONTROLLERTOUCHPADDOWN: + case SDL_CONTROLLERTOUCHPADMOTION: + if (auto joystick = GetSDLJoystickBySDLID(event.ctouchpad.which)) { + joystick->SetTouchpad(event.ctouchpad.x, event.ctouchpad.y, event.ctouchpad.touchpad, true); + } + break; + case SDL_CONTROLLERTOUCHPADUP: + if (auto joystick = GetSDLJoystickBySDLID(event.ctouchpad.which)) { + joystick->SetTouchpad(event.ctouchpad.x, event.ctouchpad.y, event.ctouchpad.touchpad, false); + } + break; #endif case SDL_JOYDEVICEREMOVED: LOG_DEBUG(Input, "Joystick removed with Instance_ID {}", event.jdevice.which); @@ -691,6 +713,19 @@ private: std::shared_ptr joystick; }; +class SDLTouch final : public Input::TouchDevice { +public: + explicit SDLTouch(std::shared_ptr joystick_, int pad_) : + joystick(std::move(joystick_)),pad(pad_) {} + + std::tuple GetStatus() const override { + return joystick->GetTouch(pad); + } +private: + std::shared_ptr joystick; + const int pad; +}; + /// A button device factory that creates button devices from SDL joystick class SDLButtonFactory final : public Input::Factory { public: @@ -810,6 +845,30 @@ public: return std::make_unique(joystick); } +private: + SDLState& state; +}; +/** + * A factory that creates a TouchDevice from an SDL Touchpad + */ +class SDLTouchFactory final : public Input::Factory { + public: + explicit SDLTouchFactory(SDLState& state_) : state(state_) {} + /** + * Creates touch device from touchpad + * @param params contains parameters for creating the device: + * - "guid": the guid of the joystick to bind + * - "port": the nth joystick of the same type + * - "touchpad": which touchpad to bind + */ + std::unique_ptr Create(const Common::ParamPackage& params) override { + const std::string guid = params.Get("guid", "0"); + const int port = params.Get("port", 0); + const int touchpad = params.Get("touchpad", 0); + auto joystick = state.GetSDLJoystickByGUID(guid, port); + return std::make_unique(joystick, touchpad); + } + private: SDLState& state; }; @@ -819,7 +878,7 @@ SDLState::SDLState() { RegisterFactory("sdl", std::make_shared(*this)); RegisterFactory("sdl", std::make_shared(*this)); RegisterFactory("sdl", std::make_shared(*this)); - + RegisterFactory("sdl",std::make_shared(*this)); // If the frontend is going to manage the event loop, then we dont start one here start_thread = !SDL_WasInit(SDL_INIT_GAMECONTROLLER); if (start_thread && SDL_Init(SDL_INIT_GAMECONTROLLER) < 0) { @@ -874,7 +933,7 @@ SDLState::~SDLState() { UnregisterFactory("sdl"); UnregisterFactory("sdl"); UnregisterFactory("sdl"); - + UnregisterFactory("sdl"); CloseJoysticks(); SDL_DelEventWatch(&SDLEventWatcher, this); @@ -956,6 +1015,30 @@ protected: SDLState& state; }; +class SDLTouchpadPoller final: public SDLPoller { +public: + explicit SDLTouchpadPoller(SDLState& state_) : SDLPoller(state_) {} + + Common::ParamPackage GetNextInput() override { + SDL_Event event; + Common::ParamPackage params; + while (state.event_queue.Pop(event)) { + if (event.type != SDL_CONTROLLERTOUCHPADDOWN) { + continue; + } + switch (event.type) { + case SDL_CONTROLLERTOUCHPADDOWN: + auto joystick = state.GetSDLJoystickBySDLID(event.ctouchpad.which); + params.Set("engine", "sdl"); + params.Set("touchpad",event.ctouchpad.touchpad); + params.Set("port", joystick->GetPort()); + params.Set("guid", joystick->GetGUID()); + } + } + return params; + } +}; + class SDLButtonPoller final : public SDLPoller { public: explicit SDLButtonPoller(SDLState& state_) : SDLPoller(state_) {} @@ -1083,6 +1166,9 @@ SDLState::Pollers SDLState::GetPollers(InputCommon::Polling::DeviceType type) { case InputCommon::Polling::DeviceType::Button: pollers.emplace_back(std::make_unique(*this)); break; + case InputCommon::Polling::DeviceType::Touchpad: + pollers.emplace_back(std::make_unique(*this)); + break; } return pollers; diff --git a/src/input_common/sdl/sdl_impl.h b/src/input_common/sdl/sdl_impl.h index 56f53121b..edb9c126f 100644 --- a/src/input_common/sdl/sdl_impl.h +++ b/src/input_common/sdl/sdl_impl.h @@ -24,6 +24,7 @@ class SDLGameController; class SDLButtonFactory; class SDLAnalogFactory; class SDLMotionFactory; +class SDLTouchFactory; class SDLState : public State { public: @@ -62,6 +63,7 @@ private: std::unordered_map>> joystick_map; std::mutex joystick_map_mutex; + std::shared_ptr touch_factory; std::shared_ptr button_factory; std::shared_ptr analog_factory; std::shared_ptr motion_factory;