mirror of
https://github.com/mollyim/webrtc.git
synced 2025-05-12 21:30:45 +01:00

This CL completes the removal of assert() and relative headers from the codebase (excluded //examples/objc/AppRTCMobile/third_party/SocketRocket which is in a third_party sub-directory). Bug: webrtc:6779 Change-Id: I93ed57168d2c0e011626873d66529488c5f484f2 Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/225546 Commit-Queue: Mirko Bonadei <mbonadei@webrtc.org> Reviewed-by: Harald Alvestrand <hta@webrtc.org> Cr-Commit-Position: refs/heads/master@{#34528}
215 lines
6.8 KiB
C++
215 lines
6.8 KiB
C++
/*
|
|
* Copyright (c) 2013 The WebRTC project authors. All Rights Reserved.
|
|
*
|
|
* Use of this source code is governed by a BSD-style license
|
|
* that can be found in the LICENSE file in the root of the source
|
|
* tree. An additional intellectual property rights grant can be found
|
|
* in the file PATENTS. All contributing project authors may
|
|
* be found in the AUTHORS file in the root of the source tree.
|
|
*/
|
|
|
|
#include <string.h>
|
|
|
|
#include <memory>
|
|
|
|
#include "modules/desktop_capture/desktop_capture_types.h"
|
|
#include "modules/desktop_capture/desktop_frame.h"
|
|
#include "modules/desktop_capture/desktop_geometry.h"
|
|
#include "modules/desktop_capture/mouse_cursor.h"
|
|
#include "modules/desktop_capture/mouse_cursor_monitor.h"
|
|
#include "modules/desktop_capture/win/cursor.h"
|
|
#include "modules/desktop_capture/win/screen_capture_utils.h"
|
|
#include "modules/desktop_capture/win/window_capture_utils.h"
|
|
#include "rtc_base/logging.h"
|
|
|
|
namespace webrtc {
|
|
|
|
namespace {
|
|
|
|
bool IsSameCursorShape(const CURSORINFO& left, const CURSORINFO& right) {
|
|
// If the cursors are not showing, we do not care the hCursor handle.
|
|
return left.flags == right.flags &&
|
|
(left.flags != CURSOR_SHOWING || left.hCursor == right.hCursor);
|
|
}
|
|
|
|
} // namespace
|
|
|
|
class MouseCursorMonitorWin : public MouseCursorMonitor {
|
|
public:
|
|
explicit MouseCursorMonitorWin(HWND window);
|
|
explicit MouseCursorMonitorWin(ScreenId screen);
|
|
~MouseCursorMonitorWin() override;
|
|
|
|
void Init(Callback* callback, Mode mode) override;
|
|
void Capture() override;
|
|
|
|
private:
|
|
// Get the rect of the currently selected screen, relative to the primary
|
|
// display's top-left. If the screen is disabled or disconnected, or any error
|
|
// happens, an empty rect is returned.
|
|
DesktopRect GetScreenRect();
|
|
|
|
HWND window_;
|
|
ScreenId screen_;
|
|
|
|
Callback* callback_;
|
|
Mode mode_;
|
|
|
|
HDC desktop_dc_;
|
|
|
|
// The last CURSORINFO (converted to MouseCursor) we have sent to the client.
|
|
CURSORINFO last_cursor_;
|
|
};
|
|
|
|
MouseCursorMonitorWin::MouseCursorMonitorWin(HWND window)
|
|
: window_(window),
|
|
screen_(kInvalidScreenId),
|
|
callback_(NULL),
|
|
mode_(SHAPE_AND_POSITION),
|
|
desktop_dc_(NULL) {
|
|
memset(&last_cursor_, 0, sizeof(CURSORINFO));
|
|
}
|
|
|
|
MouseCursorMonitorWin::MouseCursorMonitorWin(ScreenId screen)
|
|
: window_(NULL),
|
|
screen_(screen),
|
|
callback_(NULL),
|
|
mode_(SHAPE_AND_POSITION),
|
|
desktop_dc_(NULL) {
|
|
RTC_DCHECK_GE(screen, kFullDesktopScreenId);
|
|
memset(&last_cursor_, 0, sizeof(CURSORINFO));
|
|
}
|
|
|
|
MouseCursorMonitorWin::~MouseCursorMonitorWin() {
|
|
if (desktop_dc_)
|
|
ReleaseDC(NULL, desktop_dc_);
|
|
}
|
|
|
|
void MouseCursorMonitorWin::Init(Callback* callback, Mode mode) {
|
|
RTC_DCHECK(!callback_);
|
|
RTC_DCHECK(callback);
|
|
|
|
callback_ = callback;
|
|
mode_ = mode;
|
|
|
|
desktop_dc_ = GetDC(NULL);
|
|
}
|
|
|
|
void MouseCursorMonitorWin::Capture() {
|
|
RTC_DCHECK(callback_);
|
|
|
|
CURSORINFO cursor_info;
|
|
cursor_info.cbSize = sizeof(CURSORINFO);
|
|
if (!GetCursorInfo(&cursor_info)) {
|
|
RTC_LOG_F(LS_ERROR) << "Unable to get cursor info. Error = "
|
|
<< GetLastError();
|
|
return;
|
|
}
|
|
|
|
if (!IsSameCursorShape(cursor_info, last_cursor_)) {
|
|
if (cursor_info.flags == CURSOR_SUPPRESSED) {
|
|
// The cursor is intentionally hidden now, send an empty bitmap.
|
|
last_cursor_ = cursor_info;
|
|
callback_->OnMouseCursor(new MouseCursor(
|
|
new BasicDesktopFrame(DesktopSize()), DesktopVector()));
|
|
} else {
|
|
// According to MSDN https://goo.gl/u6gyuC, HCURSOR instances returned by
|
|
// functions other than CreateCursor do not need to be actively destroyed.
|
|
// And CloseHandle function (https://goo.gl/ja5ycW) does not close a
|
|
// cursor, so assume a HCURSOR does not need to be closed.
|
|
if (cursor_info.flags == 0) {
|
|
// Host machine does not have a hardware mouse attached, we will send a
|
|
// default one instead.
|
|
// Note, Windows automatically caches cursor resource, so we do not need
|
|
// to cache the result of LoadCursor.
|
|
cursor_info.hCursor = LoadCursor(nullptr, IDC_ARROW);
|
|
}
|
|
std::unique_ptr<MouseCursor> cursor(
|
|
CreateMouseCursorFromHCursor(desktop_dc_, cursor_info.hCursor));
|
|
if (cursor) {
|
|
last_cursor_ = cursor_info;
|
|
callback_->OnMouseCursor(cursor.release());
|
|
}
|
|
}
|
|
}
|
|
|
|
if (mode_ != SHAPE_AND_POSITION)
|
|
return;
|
|
|
|
// CURSORINFO::ptScreenPos is in full desktop coordinate.
|
|
DesktopVector position(cursor_info.ptScreenPos.x, cursor_info.ptScreenPos.y);
|
|
bool inside = cursor_info.flags == CURSOR_SHOWING;
|
|
|
|
if (window_) {
|
|
DesktopRect original_rect;
|
|
DesktopRect cropped_rect;
|
|
if (!GetCroppedWindowRect(window_, /*avoid_cropping_border*/ false,
|
|
&cropped_rect, &original_rect)) {
|
|
position.set(0, 0);
|
|
inside = false;
|
|
} else {
|
|
if (inside) {
|
|
HWND windowUnderCursor = WindowFromPoint(cursor_info.ptScreenPos);
|
|
inside = windowUnderCursor
|
|
? (window_ == GetAncestor(windowUnderCursor, GA_ROOT))
|
|
: false;
|
|
}
|
|
position = position.subtract(cropped_rect.top_left());
|
|
}
|
|
} else {
|
|
RTC_DCHECK_NE(screen_, kInvalidScreenId);
|
|
DesktopRect rect = GetScreenRect();
|
|
if (inside)
|
|
inside = rect.Contains(position);
|
|
position = position.subtract(rect.top_left());
|
|
}
|
|
|
|
callback_->OnMouseCursorPosition(position);
|
|
}
|
|
|
|
DesktopRect MouseCursorMonitorWin::GetScreenRect() {
|
|
RTC_DCHECK_NE(screen_, kInvalidScreenId);
|
|
if (screen_ == kFullDesktopScreenId) {
|
|
return DesktopRect::MakeXYWH(GetSystemMetrics(SM_XVIRTUALSCREEN),
|
|
GetSystemMetrics(SM_YVIRTUALSCREEN),
|
|
GetSystemMetrics(SM_CXVIRTUALSCREEN),
|
|
GetSystemMetrics(SM_CYVIRTUALSCREEN));
|
|
}
|
|
DISPLAY_DEVICE device;
|
|
device.cb = sizeof(device);
|
|
BOOL result = EnumDisplayDevices(NULL, screen_, &device, 0);
|
|
if (!result)
|
|
return DesktopRect();
|
|
|
|
DEVMODE device_mode;
|
|
device_mode.dmSize = sizeof(device_mode);
|
|
device_mode.dmDriverExtra = 0;
|
|
result = EnumDisplaySettingsEx(device.DeviceName, ENUM_CURRENT_SETTINGS,
|
|
&device_mode, 0);
|
|
if (!result)
|
|
return DesktopRect();
|
|
|
|
return DesktopRect::MakeXYWH(
|
|
device_mode.dmPosition.x, device_mode.dmPosition.y,
|
|
device_mode.dmPelsWidth, device_mode.dmPelsHeight);
|
|
}
|
|
|
|
MouseCursorMonitor* MouseCursorMonitor::CreateForWindow(
|
|
const DesktopCaptureOptions& options,
|
|
WindowId window) {
|
|
return new MouseCursorMonitorWin(reinterpret_cast<HWND>(window));
|
|
}
|
|
|
|
MouseCursorMonitor* MouseCursorMonitor::CreateForScreen(
|
|
const DesktopCaptureOptions& options,
|
|
ScreenId screen) {
|
|
return new MouseCursorMonitorWin(screen);
|
|
}
|
|
|
|
std::unique_ptr<MouseCursorMonitor> MouseCursorMonitor::Create(
|
|
const DesktopCaptureOptions& options) {
|
|
return std::unique_ptr<MouseCursorMonitor>(
|
|
CreateForScreen(options, kFullDesktopScreenId));
|
|
}
|
|
|
|
} // namespace webrtc
|