mirror of
https://github.com/kunkundi/crossdesk.git
synced 2026-10-18 01:46:47 +08:00
[feat] add Windows privacy screen and prefer DXGI capture
This commit is contained in:
@@ -10,6 +10,10 @@
|
||||
#include "rd_log.h"
|
||||
#include "runtime/gui_runtime.h"
|
||||
#include "speaker_capturer_factory.h"
|
||||
#ifdef _WIN32
|
||||
#include "platform/windows/screen_capturer/screen_capturer_win.h"
|
||||
#include "platform/windows/input/mouse/mouse_controller.h"
|
||||
#endif
|
||||
|
||||
namespace crossdesk {
|
||||
namespace {
|
||||
@@ -28,7 +32,7 @@ SessionDeviceManager::SessionDeviceManager(GuiRuntime &owner)
|
||||
SpeakerCapturerFactory().Create());
|
||||
},
|
||||
[this](unsigned char *data, size_t size, const char *) {
|
||||
if (!owner_.peer_) return;
|
||||
if (!owner_.peer_ || !owner_.privacy_.RemoteAllowed()) return;
|
||||
MiniRtcAudioFrame frame{};
|
||||
frame.data = reinterpret_cast<const char *>(data);
|
||||
frame.size = size;
|
||||
@@ -74,6 +78,10 @@ int SessionDeviceManager::InitializeScreenCapturer() {
|
||||
if (!screen_capturer_) {
|
||||
screen_capturer_ =
|
||||
static_cast<ScreenCapturer *>(screen_capturer_factory_->Create());
|
||||
#ifdef _WIN32
|
||||
if (auto windows = dynamic_cast<ScreenCapturerWin*>(screen_capturer_))
|
||||
windows->SetPrivacyController(&owner_.privacy_);
|
||||
#endif
|
||||
}
|
||||
|
||||
last_frame_time_ = {};
|
||||
@@ -92,6 +100,7 @@ int SessionDeviceManager::InitializeScreenCapturer() {
|
||||
fps, [this, fps](unsigned char *data, int size, int width, int height,
|
||||
const char *display_name,
|
||||
const MiniRtcNativeVideoFrame *native_frame) {
|
||||
if (!owner_.privacy_.RemoteAllowed()) return;
|
||||
const auto now_time = std::chrono::steady_clock::now();
|
||||
if (!ShouldSendCapturedFrame(now_time, fps)) {
|
||||
return;
|
||||
@@ -154,6 +163,9 @@ int SessionDeviceManager::InitializeScreenCapturer() {
|
||||
}
|
||||
|
||||
MiniRtcVideoFrame frame{};
|
||||
// A new controller can connect after this callback's first gate check
|
||||
// while it is collecting the Connected peer IDs above.
|
||||
if (!owner_.privacy_.RemoteAllowed()) return;
|
||||
frame.data = reinterpret_cast<const char *>(data);
|
||||
frame.size = size;
|
||||
frame.width = width;
|
||||
@@ -216,6 +228,13 @@ int SessionDeviceManager::StopScreenCapturer() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
void SessionDeviceManager::ReleaseRemoteMouseButtons() {
|
||||
if (auto mouse = dynamic_cast<PlatformMouseController*>(mouse_controller_))
|
||||
mouse->ReleasePressedButtons();
|
||||
}
|
||||
#endif
|
||||
|
||||
void SessionDeviceManager::StartSpeakerCapturer() {
|
||||
speaker_capture_.SetEnabled(true);
|
||||
}
|
||||
@@ -488,6 +507,7 @@ void SessionDeviceManager::DrainCapturedKeyboardInput() {
|
||||
std::lock_guard<std::mutex> lock(captured_keyboard_inputs_mutex_);
|
||||
inputs.swap(captured_keyboard_inputs_);
|
||||
}
|
||||
if (owner_.privacy_.Snapshot().input_blocked) return;
|
||||
for (const CapturedKeyboardInput &input : inputs) {
|
||||
owner_.keyboard_.SendKeyCommand(input.key_code, input.is_down,
|
||||
input.scan_code, input.extended);
|
||||
@@ -508,6 +528,7 @@ bool SessionDeviceManager::SendKeyboardCommand(int key_code, bool is_down,
|
||||
|
||||
void SessionDeviceManager::SendMouseCommand(const RemoteAction &action,
|
||||
int selected_display) {
|
||||
if (!owner_.privacy_.RemoteAllowed()) return;
|
||||
if (mouse_controller_) {
|
||||
mouse_controller_->SendMouseCommand(action, selected_display);
|
||||
}
|
||||
|
||||
@@ -46,6 +46,9 @@ public:
|
||||
int InitializeScreenCapturer();
|
||||
int StartScreenCapturer();
|
||||
int StopScreenCapturer();
|
||||
#ifdef _WIN32
|
||||
void ReleaseRemoteMouseButtons();
|
||||
#endif
|
||||
// Requests are asynchronous; Stop drains/revokes audio delivery before
|
||||
// returning so the connection peer can be destroyed safely.
|
||||
void StartSpeakerCapturer();
|
||||
@@ -102,4 +105,4 @@ private:
|
||||
|
||||
} // namespace crossdesk
|
||||
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@@ -212,8 +212,13 @@ int KeyboardController::SendKeyCommand(int key_code, bool is_down,
|
||||
|
||||
bool KeyboardController::InjectRemoteKey(int key_code, bool is_down,
|
||||
uint32_t scan_code, bool extended) {
|
||||
if (is_down && !owner_.privacy_.RemoteAllowed()) return false;
|
||||
#if _WIN32
|
||||
if (owner_.local_service_status_received_ &&
|
||||
if (owner_.privacy_.Engaged() && !IsWindowsPrivacyDesktopAvailable()) {
|
||||
owner_.privacy_.Fail("Secure desktop or locked session; remote key injection paused");
|
||||
return false;
|
||||
}
|
||||
if (!owner_.privacy_.Engaged() && owner_.local_service_status_received_ &&
|
||||
IsSecureDesktopInteractionRequired(owner_.local_interactive_stage_)) {
|
||||
const std::string response = SendCrossDeskSecureDesktopKeyInput(
|
||||
key_code, is_down, scan_code, extended, 1000);
|
||||
@@ -246,6 +251,8 @@ bool KeyboardController::InjectRemoteKey(int key_code, bool is_down,
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
// Recheck after the desktop query; key-up cleanup remains allowed while paused.
|
||||
if (is_down && !owner_.privacy_.RemoteAllowed()) return false;
|
||||
return owner_.devices_.SendKeyboardCommand(key_code, is_down, scan_code,
|
||||
extended);
|
||||
}
|
||||
@@ -342,11 +349,50 @@ void KeyboardController::ReleaseRemotePressedKeys(const std::string& remote_id,
|
||||
keys_to_release.size(), remote_id, reason ? reason : "unknown");
|
||||
}
|
||||
for (const PressedKey& key : keys_to_release) {
|
||||
InjectRemoteKey(key.key_code, false, key.scan_code, key.extended);
|
||||
if (!InjectRemoteKey(key.key_code, false, key.scan_code, key.extended)) {
|
||||
#ifdef _WIN32
|
||||
if (owner_.privacy_.Engaged()) {
|
||||
std::lock_guard lock(remote_states_mutex_);
|
||||
pending_privacy_releases_[key.key_code] = key;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void KeyboardController::ReleaseAllRemotePressedKeys(const char* reason) {
|
||||
std::vector<std::string> remotes;
|
||||
{
|
||||
std::lock_guard lock(remote_states_mutex_);
|
||||
for (const auto& [id, state] : remote_states_) remotes.push_back(id);
|
||||
}
|
||||
for (const auto& id : remotes) ReleaseRemotePressedKeys(id, reason);
|
||||
CheckRemoteTimeouts();
|
||||
}
|
||||
|
||||
void KeyboardController::CheckRemoteTimeouts() {
|
||||
#ifdef _WIN32
|
||||
bool pending = false;
|
||||
{
|
||||
std::lock_guard lock(remote_states_mutex_);
|
||||
pending = !pending_privacy_releases_.empty();
|
||||
}
|
||||
// A key-up rejected on the secure desktop is retained until the ordinary
|
||||
// desktop returns. Never route cleanup through the security UI helper.
|
||||
if (pending && IsWindowsPrivacyDesktopAvailable()) {
|
||||
std::unordered_map<int, PressedKey> releases;
|
||||
{
|
||||
std::lock_guard lock(remote_states_mutex_);
|
||||
releases.swap(pending_privacy_releases_);
|
||||
}
|
||||
for (const auto& [code, key] : releases) {
|
||||
if (!owner_.devices_.SendKeyboardCommand(code, false, key.scan_code, key.extended)) {
|
||||
std::lock_guard lock(remote_states_mutex_);
|
||||
pending_privacy_releases_[code] = key;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
const uint32_t now = static_cast<uint32_t>(SDL_GetTicks());
|
||||
std::vector<std::string> timed_out_remotes;
|
||||
{
|
||||
|
||||
@@ -30,6 +30,7 @@ public:
|
||||
const RemoteAction &remote_action);
|
||||
void ReleaseRemotePressedKeys(const std::string &remote_id,
|
||||
const char *reason);
|
||||
void ReleaseAllRemotePressedKeys(const char* reason);
|
||||
void CheckRemoteTimeouts();
|
||||
|
||||
private:
|
||||
@@ -58,6 +59,9 @@ private:
|
||||
uint32_t last_heartbeat_tick_ = 0;
|
||||
std::unordered_map<std::string, RemoteState> remote_states_;
|
||||
std::mutex remote_states_mutex_;
|
||||
#ifdef _WIN32
|
||||
std::unordered_map<int, PressedKey> pending_privacy_releases_;
|
||||
#endif
|
||||
};
|
||||
|
||||
} // namespace crossdesk
|
||||
|
||||
Reference in New Issue
Block a user