mirror of
https://github.com/kunkundi/crossdesk.git
synced 2026-10-16 00:33:22 +08:00
[fix] prevent duplicate cursors during Windows window dragging
This commit is contained in:
@@ -6,6 +6,7 @@
|
||||
|
||||
#include <windows.h>
|
||||
|
||||
#include "platform/windows/screen_capturer/dxgi_cursor_state.h"
|
||||
#include "runtime/cursor_position.h"
|
||||
|
||||
namespace crossdesk {
|
||||
@@ -52,11 +53,15 @@ bool CursorStateProvider::Sample(const std::vector<DisplayInfo>& displays,
|
||||
if (!GetCursorInfo(&info)) return false;
|
||||
|
||||
state->seq = 0;
|
||||
state->visible = (info.flags & CURSOR_SHOWING) != 0;
|
||||
state->shape = state->visible ? ShapeFromWindowsCursor(info.hCursor)
|
||||
: RemoteCursorShape::none;
|
||||
NormalizeCursorPosition(info.ptScreenPos.x, info.ptScreenPos.y, displays,
|
||||
preferred_display, state);
|
||||
void* cursor_monitor = state->position_valid
|
||||
? displays[state->display_id].handle
|
||||
: nullptr;
|
||||
state->visible = SharedDxgiCursorState().ShouldDrawCursor(
|
||||
(info.flags & CURSOR_SHOWING) != 0, cursor_monitor);
|
||||
state->shape = state->visible ? ShapeFromWindowsCursor(info.hCursor)
|
||||
: RemoteCursorShape::none;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,48 @@
|
||||
#ifndef CROSSDESK_DXGI_CURSOR_STATE_H_
|
||||
#define CROSSDESK_DXGI_CURSOR_STATE_H_
|
||||
|
||||
#include <atomic>
|
||||
#include <cstdint>
|
||||
|
||||
namespace crossdesk {
|
||||
|
||||
// DXGI's Visible flag describes the separate hardware pointer, not the
|
||||
// system cursor. When it is false, a visible system cursor can already be
|
||||
// included in the desktop texture (for example, during window dragging).
|
||||
// Share that distinction with the GUI thread without changing cursor input
|
||||
// coordinates or the wire protocol.
|
||||
class DxgiCursorState {
|
||||
public:
|
||||
void Update(int64_t last_mouse_update_time, bool separate_pointer_visible,
|
||||
void* monitor) {
|
||||
// PointerPosition is undefined on desktop-only updates. Retain the last
|
||||
// pointer state until DXGI actually reports another pointer update.
|
||||
if (last_mouse_update_time == 0) return;
|
||||
embedded_monitor_.store(separate_pointer_visible ? nullptr : monitor,
|
||||
std::memory_order_relaxed);
|
||||
}
|
||||
|
||||
void Reset() {
|
||||
embedded_monitor_.store(nullptr, std::memory_order_relaxed);
|
||||
}
|
||||
|
||||
bool ShouldDrawCursor(bool system_cursor_visible, void* cursor_monitor) const {
|
||||
// A hidden cursor or a pointer on another monitor also makes DXGI report
|
||||
// Visible=false. Only suppress a visible cursor on the captured monitor.
|
||||
return system_cursor_visible &&
|
||||
(!cursor_monitor ||
|
||||
embedded_monitor_.load(std::memory_order_relaxed) != cursor_monitor);
|
||||
}
|
||||
|
||||
private:
|
||||
std::atomic<void*> embedded_monitor_{nullptr};
|
||||
};
|
||||
|
||||
inline DxgiCursorState& SharedDxgiCursorState() {
|
||||
static DxgiCursorState state;
|
||||
return state;
|
||||
}
|
||||
|
||||
} // namespace crossdesk
|
||||
|
||||
#endif // CROSSDESK_DXGI_CURSOR_STATE_H_
|
||||
@@ -7,6 +7,7 @@
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "dxgi_cursor_state.h"
|
||||
#include "libyuv.h"
|
||||
#include "rd_log.h"
|
||||
|
||||
@@ -232,6 +233,7 @@ void ScreenCapturerDxgi::EnumerateDisplays() {
|
||||
}
|
||||
|
||||
bool ScreenCapturerDxgi::CreateDuplicationForMonitor(int monitor_index) {
|
||||
SharedDxgiCursorState().Reset();
|
||||
if (monitor_index < 0 || monitor_index >= (int)outputs_.size()) return false;
|
||||
Microsoft::WRL::ComPtr<IDXGIOutput1> output1;
|
||||
HRESULT hr = outputs_[monitor_index]->QueryInterface(
|
||||
@@ -284,6 +286,7 @@ bool ScreenCapturerDxgi::RecreateDuplicationForCurrentMonitor() {
|
||||
}
|
||||
|
||||
void ScreenCapturerDxgi::ReleaseDuplication() {
|
||||
SharedDxgiCursorState().Reset();
|
||||
++duplication_generation_;
|
||||
staging_.Reset();
|
||||
if (duplication_) {
|
||||
@@ -344,6 +347,7 @@ void ScreenCapturerDxgi::CaptureLoop() {
|
||||
// a backend rebuild. Normal error/reset handling releases optional privacy.
|
||||
cached_frame_valid = false;
|
||||
if (FAILED(hr)) {
|
||||
SharedDxgiCursorState().Reset();
|
||||
LOG_ERROR("DXGI: AcquireNextFrame failed, hr={}", (int)hr);
|
||||
capture_lock.unlock();
|
||||
if (callback_)
|
||||
@@ -352,6 +356,14 @@ void ScreenCapturerDxgi::CaptureLoop() {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (frame_monitor >= 0 &&
|
||||
frame_monitor < static_cast<int>(display_info_list_.size())) {
|
||||
SharedDxgiCursorState().Update(
|
||||
frame_info.LastMouseUpdateTime.QuadPart,
|
||||
frame_info.PointerPosition.Visible != FALSE,
|
||||
display_info_list_[frame_monitor].handle);
|
||||
}
|
||||
|
||||
Microsoft::WRL::ComPtr<ID3D11Texture2D> acquired_tex;
|
||||
if (desktop_resource) {
|
||||
hr = desktop_resource->QueryInterface(
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
#include <display_stream_id.h>
|
||||
#include "captured_nv12_frame.h"
|
||||
#include "dxgi_cursor_state.h"
|
||||
#include "interactive_state.h"
|
||||
#include "named_pipe_deadline.h"
|
||||
#include "rd_log.h"
|
||||
@@ -364,6 +365,7 @@ int ScreenCapturerWin::Init(const int fps, cb_desktop_data cb) {
|
||||
return;
|
||||
}
|
||||
if (secure_desktop_capture_active_.load(std::memory_order_relaxed)) {
|
||||
SharedDxgiCursorState().Reset();
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -470,6 +472,9 @@ void ScreenCapturerWin::EmitCapturedFrame(
|
||||
unsigned char* data, int size, int width, int height,
|
||||
const char* stream_id, const MiniRtcNativeVideoFrame* native_frame,
|
||||
bool from_secure_desktop) {
|
||||
// Helper frames do not use DXGI's pointer plane. Do not carry normal-desktop
|
||||
// cursor suppression into the lock screen or UAC desktop.
|
||||
if (from_secure_desktop) SharedDxgiCursorState().Reset();
|
||||
// Secure-desktop capture takes priority; remove privacy without dropping
|
||||
// the helper frame or delaying the remote session.
|
||||
if (from_secure_desktop && privacy_ && privacy_->Engaged()) {
|
||||
|
||||
Reference in New Issue
Block a user