1/* 2 * Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. 3 * 4 * Use of this source code is governed by a BSD-style license 5 * that can be found in the LICENSE file in the root of the source 6 * tree. An additional intellectual property rights grant can be found 7 * in the file PATENTS. All contributing project authors may 8 * be found in the AUTHORS file in the root of the source tree. 9 */ 10 11#include "webrtc/modules/desktop_capture/mouse_cursor_monitor.h" 12 13#include <assert.h> 14 15#include "webrtc/modules/desktop_capture/desktop_frame.h" 16#include "webrtc/modules/desktop_capture/mouse_cursor.h" 17#include "webrtc/modules/desktop_capture/win/cursor.h" 18#include "webrtc/modules/desktop_capture/win/window_capture_utils.h" 19#include "webrtc/system_wrappers/interface/logging.h" 20 21namespace webrtc { 22 23class MouseCursorMonitorWin : public MouseCursorMonitor { 24 public: 25 explicit MouseCursorMonitorWin(HWND window); 26 explicit MouseCursorMonitorWin(ScreenId screen); 27 virtual ~MouseCursorMonitorWin(); 28 29 virtual void Init(Callback* callback, Mode mode) OVERRIDE; 30 virtual void Capture() OVERRIDE; 31 32 private: 33 // Get the rect of the currently selected screen, relative to the primary 34 // display's top-left. If the screen is disabled or disconnected, or any error 35 // happens, an empty rect is returned. 36 DesktopRect GetScreenRect(); 37 38 HWND window_; 39 ScreenId screen_; 40 41 Callback* callback_; 42 Mode mode_; 43 44 HDC desktop_dc_; 45 46 HCURSOR last_cursor_; 47}; 48 49MouseCursorMonitorWin::MouseCursorMonitorWin(HWND window) 50 : window_(window), 51 screen_(kInvalidScreenId), 52 callback_(NULL), 53 mode_(SHAPE_AND_POSITION), 54 desktop_dc_(NULL), 55 last_cursor_(NULL) { 56} 57 58MouseCursorMonitorWin::MouseCursorMonitorWin(ScreenId screen) 59 : window_(NULL), 60 screen_(screen), 61 callback_(NULL), 62 mode_(SHAPE_AND_POSITION), 63 desktop_dc_(NULL), 64 last_cursor_(NULL) { 65 assert(screen >= kFullDesktopScreenId); 66} 67 68MouseCursorMonitorWin::~MouseCursorMonitorWin() { 69 if (desktop_dc_) 70 ReleaseDC(NULL, desktop_dc_); 71} 72 73void MouseCursorMonitorWin::Init(Callback* callback, Mode mode) { 74 assert(!callback_); 75 assert(callback); 76 77 callback_ = callback; 78 mode_ = mode; 79 80 desktop_dc_ = GetDC(NULL); 81} 82 83void MouseCursorMonitorWin::Capture() { 84 assert(callback_); 85 86 CURSORINFO cursor_info; 87 cursor_info.cbSize = sizeof(CURSORINFO); 88 if (!GetCursorInfo(&cursor_info)) { 89 LOG_F(LS_ERROR) << "Unable to get cursor info. Error = " << GetLastError(); 90 return; 91 } 92 93 if (last_cursor_ != cursor_info.hCursor) { 94 last_cursor_ = cursor_info.hCursor; 95 // Note that |cursor_info.hCursor| does not need to be freed. 96 scoped_ptr<MouseCursor> cursor( 97 CreateMouseCursorFromHCursor(desktop_dc_, cursor_info.hCursor)); 98 if (cursor.get()) 99 callback_->OnMouseCursor(cursor.release()); 100 } 101 102 if (mode_ != SHAPE_AND_POSITION) 103 return; 104 105 DesktopVector position(cursor_info.ptScreenPos.x, cursor_info.ptScreenPos.y); 106 bool inside = cursor_info.flags == CURSOR_SHOWING; 107 108 if (window_) { 109 DesktopRect original_rect; 110 DesktopRect cropped_rect; 111 if (!GetCroppedWindowRect(window_, &cropped_rect, &original_rect)) { 112 position.set(0, 0); 113 inside = false; 114 } else { 115 if (inside) { 116 HWND windowUnderCursor = WindowFromPoint(cursor_info.ptScreenPos); 117 inside = windowUnderCursor ? 118 (window_ == GetAncestor(windowUnderCursor, GA_ROOT)) : false; 119 } 120 position = position.subtract(cropped_rect.top_left()); 121 } 122 } else { 123 assert(screen_ != kInvalidScreenId); 124 DesktopRect rect = GetScreenRect(); 125 if (inside) 126 inside = rect.Contains(position); 127 position = position.subtract(rect.top_left()); 128 } 129 130 callback_->OnMouseCursorPosition(inside ? INSIDE : OUTSIDE, position); 131} 132 133DesktopRect MouseCursorMonitorWin::GetScreenRect() { 134 assert(screen_ != kInvalidScreenId); 135 if (screen_ == kFullDesktopScreenId) { 136 return DesktopRect::MakeXYWH( 137 GetSystemMetrics(SM_XVIRTUALSCREEN), 138 GetSystemMetrics(SM_YVIRTUALSCREEN), 139 GetSystemMetrics(SM_CXVIRTUALSCREEN), 140 GetSystemMetrics(SM_CYVIRTUALSCREEN)); 141 } 142 DISPLAY_DEVICE device; 143 device.cb = sizeof(device); 144 BOOL result = EnumDisplayDevices(NULL, screen_, &device, 0); 145 if (!result) 146 return DesktopRect(); 147 148 DEVMODE device_mode; 149 device_mode.dmSize = sizeof(device_mode); 150 device_mode.dmDriverExtra = 0; 151 result = EnumDisplaySettingsEx( 152 device.DeviceName, ENUM_CURRENT_SETTINGS, &device_mode, 0); 153 if (!result) 154 return DesktopRect(); 155 156 return DesktopRect::MakeXYWH(device_mode.dmPosition.x, 157 device_mode.dmPosition.y, 158 device_mode.dmPelsWidth, 159 device_mode.dmPelsHeight); 160} 161 162MouseCursorMonitor* MouseCursorMonitor::CreateForWindow( 163 const DesktopCaptureOptions& options, WindowId window) { 164 return new MouseCursorMonitorWin(reinterpret_cast<HWND>(window)); 165} 166 167MouseCursorMonitor* MouseCursorMonitor::CreateForScreen( 168 const DesktopCaptureOptions& options, 169 ScreenId screen) { 170 return new MouseCursorMonitorWin(screen); 171} 172 173} // namespace webrtc 174