mirror of
https://github.com/kunkundi/crossdesk.git
synced 2026-11-05 13:42:38 +08:00
[fix] prevent remote input from blocking transport callbacks
This commit is contained in:
@@ -21,7 +21,6 @@
|
||||
#ifdef _WIN32
|
||||
#include <nlohmann/json.hpp>
|
||||
#include "platform/windows/screen_capturer/screen_capturer_win.h"
|
||||
#include "platform/windows/input/mouse/mouse_controller.h"
|
||||
#include "service_host.h"
|
||||
#endif
|
||||
|
||||
@@ -333,26 +332,44 @@ int SessionDeviceManager::StopScreenCapturer() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool SessionDeviceManager::ReleaseRemoteMouseButtons() {
|
||||
return remote_mouse_buttons_.ReleaseAll(
|
||||
[this](unsigned mask) { return ReleaseMouseButtonMask(mask); });
|
||||
}
|
||||
|
||||
bool SessionDeviceManager::ReleaseRemoteMouseButtons(const std::string& remote_id,
|
||||
unsigned mask) {
|
||||
return remote_mouse_buttons_.ReleaseController(
|
||||
remote_id, [this](unsigned buttons) { return ReleaseMouseButtonMask(buttons); }, mask);
|
||||
}
|
||||
|
||||
unsigned SessionDeviceManager::ReleaseMouseButtonMask(unsigned mask) {
|
||||
unsigned released = mask;
|
||||
{
|
||||
std::lock_guard lock(mouse_controller_mutex_);
|
||||
if (mouse_controller_) released &= mouse_controller_->ReleasePressedButtons(mask);
|
||||
}
|
||||
#ifdef _WIN32
|
||||
void SessionDeviceManager::ReleaseRemoteMouseButtons() {
|
||||
if (auto mouse = dynamic_cast<PlatformMouseController*>(mouse_controller_))
|
||||
mouse->ReleasePressedButtons();
|
||||
std::lock_guard lock(service_mouse_mutex_);
|
||||
for (int button = 0; button < 3; ++button) {
|
||||
const unsigned bit = 1u << button;
|
||||
if (!(service_mouse_buttons_ & bit)) continue;
|
||||
if (!(service_mouse_buttons_ & mask & bit)) continue;
|
||||
const auto response = SendCrossDeskSecureDesktopMouseInput(
|
||||
service_mouse_x_, service_mouse_y_, 0, (button + 1) * 2, 1000);
|
||||
const auto json = nlohmann::json::parse(response, nullptr, false);
|
||||
if (json.is_object() && json.value("ok", false)) {
|
||||
service_mouse_buttons_ &= ~bit;
|
||||
} else {
|
||||
released &= ~bit;
|
||||
LOG_WARN("Service mouse button release failed: button={}, response={}",
|
||||
button, response);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return released;
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
std::string SessionDeviceManager::SendServiceMouseCommand(int x, int y,
|
||||
int wheel, int flag) {
|
||||
std::lock_guard lock(service_mouse_mutex_);
|
||||
@@ -398,7 +415,10 @@ bool SessionDeviceManager::SyncDisplayInfo() {
|
||||
});
|
||||
if (changed) display_info_list_ = displays;
|
||||
}
|
||||
if (changed && mouse_controller_) mouse_controller_->UpdateDisplayInfoList(displays);
|
||||
if (changed) {
|
||||
std::lock_guard lock(mouse_controller_mutex_);
|
||||
if (mouse_controller_) mouse_controller_->UpdateDisplayInfoList(displays);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -434,6 +454,7 @@ int SessionDeviceManager::StartMouseController() {
|
||||
#endif
|
||||
|
||||
SyncDisplayInfo();
|
||||
std::lock_guard lock(mouse_controller_mutex_);
|
||||
mouse_controller_ =
|
||||
static_cast<MouseController *>(device_controller_factory_->Create(
|
||||
DeviceControllerFactory::Device::Mouse));
|
||||
@@ -452,10 +473,16 @@ int SessionDeviceManager::StartMouseController() {
|
||||
return init_ret;
|
||||
}
|
||||
|
||||
int SessionDeviceManager::StopMouseController() {
|
||||
#ifdef _WIN32
|
||||
int SessionDeviceManager::StopMouseController(bool force) {
|
||||
// Retain the native button state across transient cleanup failures. The UI
|
||||
// can keep pumping while the input worker retries, including with no peers.
|
||||
if (!force && owner_.remote_input_.HasPendingReleases()) return 1;
|
||||
// A disconnect has revoked queued input. Finish its running injection and
|
||||
// release callback before destroying the native controller.
|
||||
owner_.remote_input_.WaitIdle();
|
||||
if (!force && owner_.remote_input_.HasPendingReleases()) return 1;
|
||||
ReleaseRemoteMouseButtons();
|
||||
#endif
|
||||
std::lock_guard lock(mouse_controller_mutex_);
|
||||
if (mouse_controller_) {
|
||||
mouse_controller_->Destroy();
|
||||
delete mouse_controller_;
|
||||
@@ -636,9 +663,9 @@ void SessionDeviceManager::UpdateInteractions() {
|
||||
owner_.screen_capturer_is_started_ && !owner_.start_mouse_controller_ &&
|
||||
owner_.mouse_controller_is_started_;
|
||||
if (stop_wayland_mouse_before_screen) {
|
||||
LOG_INFO("Stopping Wayland mouse controller before screen capturer to "
|
||||
if (StopMouseController() != 0) return;
|
||||
LOG_INFO("Stopped Wayland mouse controller before screen capturer to "
|
||||
"cleanly release the shared portal session");
|
||||
StopMouseController();
|
||||
owner_.mouse_controller_is_started_ = false;
|
||||
}
|
||||
#endif
|
||||
@@ -659,8 +686,7 @@ void SessionDeviceManager::UpdateInteractions() {
|
||||
}
|
||||
} else if (!owner_.start_mouse_controller_ &&
|
||||
owner_.mouse_controller_is_started_) {
|
||||
StopMouseController();
|
||||
owner_.mouse_controller_is_started_ = false;
|
||||
if (StopMouseController() == 0) owner_.mouse_controller_is_started_ = false;
|
||||
}
|
||||
|
||||
if (owner_.screen_capturer_is_started_ && mouse_controller_ && SyncDisplayInfo()) {
|
||||
@@ -750,6 +776,7 @@ bool SessionDeviceManager::SendKeyboardCommand(int key_code, bool is_down,
|
||||
|
||||
bool SessionDeviceManager::SendMouseCommand(const RemoteAction &action,
|
||||
int selected_display) {
|
||||
std::lock_guard lock(mouse_controller_mutex_);
|
||||
if (mouse_controller_) {
|
||||
return mouse_controller_->SendMouseCommand(action, selected_display) == 0;
|
||||
}
|
||||
@@ -763,19 +790,20 @@ int SessionDeviceManager::SwitchDisplay(int display_id) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
void SessionDeviceManager::ResetToInitialDisplay() {
|
||||
InputOutcome SessionDeviceManager::ResetToInitialDisplay() {
|
||||
if (!screen_capturer_) {
|
||||
return;
|
||||
return InputOutcome::ignored;
|
||||
}
|
||||
const int ret = screen_capturer_->ResetToInitialMonitor();
|
||||
if (ret != 0) {
|
||||
LOG_WARN("Reset to initial display failed, ret={}", ret);
|
||||
return;
|
||||
return InputOutcome::failed;
|
||||
}
|
||||
// Capture backends start at display 0. Reset the input mapping as well so
|
||||
// the next connection cannot show that display while controlling another.
|
||||
owner_.selected_display_ = 0;
|
||||
SyncDisplayInfo();
|
||||
return InputOutcome::applied;
|
||||
}
|
||||
|
||||
std::vector<DisplayInfo> SessionDeviceManager::display_info_list() const {
|
||||
@@ -796,7 +824,7 @@ std::vector<HostDisplay> SessionDeviceManager::host_display_list() const {
|
||||
|
||||
void SessionDeviceManager::DestroyDevices() {
|
||||
speaker_capture_.Shutdown();
|
||||
StopMouseController();
|
||||
StopMouseController(true);
|
||||
if (screen_capturer_) {
|
||||
screen_capturer_->Destroy();
|
||||
delete screen_capturer_;
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
#include <remote_action.h>
|
||||
@@ -21,6 +22,7 @@
|
||||
#include "device_controller.h"
|
||||
#include "display_info.h"
|
||||
#include "features/input/captured_keyboard_queue.h"
|
||||
#include "features/input/remote_mouse_buttons.h"
|
||||
#include "speaker_capture_controller.h"
|
||||
|
||||
struct SDL_AudioStream;
|
||||
@@ -53,8 +55,15 @@ public:
|
||||
int InitializeScreenCapturer();
|
||||
int StartScreenCapturer();
|
||||
int StopScreenCapturer();
|
||||
bool ReleaseRemoteMouseButtons();
|
||||
bool ReleaseRemoteMouseButtons(const std::string& remote_id,
|
||||
unsigned mask = 7);
|
||||
template <typename Send>
|
||||
InputOutcome ApplyRemoteMouse(const std::string& remote_id, MouseFlag flag,
|
||||
Send send) {
|
||||
return remote_mouse_buttons_.Apply(remote_id, flag, std::move(send));
|
||||
}
|
||||
#ifdef _WIN32
|
||||
void ReleaseRemoteMouseButtons();
|
||||
std::string SendServiceMouseCommand(int x, int y, int wheel, int flag);
|
||||
#endif
|
||||
// Requests are asynchronous; Stop drains/revokes audio delivery before
|
||||
@@ -62,7 +71,9 @@ public:
|
||||
void StartSpeakerCapturer();
|
||||
void StopSpeakerCapturer();
|
||||
int StartMouseController();
|
||||
int StopMouseController();
|
||||
// Returns 1 while background releases are pending. force is only used
|
||||
// during final destruction after the input dispatcher has been stopped.
|
||||
int StopMouseController(bool force = false);
|
||||
int StartKeyboardCapturer();
|
||||
int StopKeyboardCapturer();
|
||||
|
||||
@@ -79,7 +90,7 @@ public:
|
||||
bool extended);
|
||||
bool SendMouseCommand(const RemoteAction &action, int selected_display);
|
||||
int SwitchDisplay(int display_id);
|
||||
void ResetToInitialDisplay();
|
||||
InputOutcome ResetToInitialDisplay();
|
||||
|
||||
// Snapshot of the capture displays. The UI thread refreshes the list every
|
||||
// tick while transport threads build host information and map mouse input
|
||||
@@ -89,6 +100,7 @@ public:
|
||||
std::vector<HostDisplay> host_display_list() const;
|
||||
|
||||
private:
|
||||
unsigned ReleaseMouseButtonMask(unsigned mask);
|
||||
void DrainCapturedKeyboardInput();
|
||||
bool ShouldSendCapturedFrame(std::chrono::steady_clock::time_point now,
|
||||
int fps);
|
||||
@@ -107,6 +119,9 @@ private:
|
||||
SpeakerCaptureController speaker_capture_;
|
||||
DeviceControllerFactory *device_controller_factory_ = nullptr;
|
||||
MouseController *mouse_controller_ = nullptr;
|
||||
RemoteMouseButtons remote_mouse_buttons_;
|
||||
// Input is executed on a worker while the UI starts/stops this controller.
|
||||
std::mutex mouse_controller_mutex_;
|
||||
KeyboardCapturer *keyboard_capturer_ = nullptr;
|
||||
// Guards display_info_list_ (UI thread writes, transport threads read).
|
||||
mutable std::mutex display_info_mutex_;
|
||||
|
||||
Reference in New Issue
Block a user