sergeyu@chromium.org | af54d4b | 2013-10-16 02:42:38 +0000 | [diff] [blame] | 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 | |
sergeyu@chromium.org | 2873c4c | 2013-10-17 19:47:18 +0000 | [diff] [blame] | 13 | #include "webrtc/modules/desktop_capture/desktop_frame.h" |
| 14 | #include "webrtc/modules/desktop_capture/mouse_cursor.h" |
| 15 | #include "webrtc/modules/desktop_capture/win/cursor.h" |
| 16 | #include "webrtc/system_wrappers/interface/logging.h" |
sergeyu@chromium.org | af54d4b | 2013-10-16 02:42:38 +0000 | [diff] [blame] | 17 | |
| 18 | namespace webrtc { |
| 19 | |
sergeyu@chromium.org | 2873c4c | 2013-10-17 19:47:18 +0000 | [diff] [blame] | 20 | class MouseCursorMonitorWin : public MouseCursorMonitor { |
| 21 | public: |
| 22 | explicit MouseCursorMonitorWin(HWND window); |
jiayl@webrtc.org | 28bd30a | 2014-01-17 17:19:16 +0000 | [diff] [blame] | 23 | explicit MouseCursorMonitorWin(ScreenId screen); |
sergeyu@chromium.org | 2873c4c | 2013-10-17 19:47:18 +0000 | [diff] [blame] | 24 | virtual ~MouseCursorMonitorWin(); |
| 25 | |
| 26 | virtual void Init(Callback* callback, Mode mode) OVERRIDE; |
| 27 | virtual void Capture() OVERRIDE; |
| 28 | |
| 29 | private: |
jiayl@webrtc.org | 28bd30a | 2014-01-17 17:19:16 +0000 | [diff] [blame] | 30 | DesktopRect GetScreenRect(); |
| 31 | |
sergeyu@chromium.org | 2873c4c | 2013-10-17 19:47:18 +0000 | [diff] [blame] | 32 | HWND window_; |
jiayl@webrtc.org | 28bd30a | 2014-01-17 17:19:16 +0000 | [diff] [blame] | 33 | ScreenId screen_; |
sergeyu@chromium.org | 2873c4c | 2013-10-17 19:47:18 +0000 | [diff] [blame] | 34 | |
| 35 | Callback* callback_; |
| 36 | Mode mode_; |
| 37 | |
| 38 | HDC desktop_dc_; |
| 39 | |
| 40 | HCURSOR last_cursor_; |
| 41 | }; |
| 42 | |
| 43 | MouseCursorMonitorWin::MouseCursorMonitorWin(HWND window) |
| 44 | : window_(window), |
jiayl@webrtc.org | 28bd30a | 2014-01-17 17:19:16 +0000 | [diff] [blame] | 45 | screen_(kInvalidScreenId), |
sergeyu@chromium.org | 2873c4c | 2013-10-17 19:47:18 +0000 | [diff] [blame] | 46 | callback_(NULL), |
| 47 | mode_(SHAPE_AND_POSITION), |
| 48 | desktop_dc_(NULL), |
| 49 | last_cursor_(NULL) { |
| 50 | } |
| 51 | |
jiayl@webrtc.org | 28bd30a | 2014-01-17 17:19:16 +0000 | [diff] [blame] | 52 | MouseCursorMonitorWin::MouseCursorMonitorWin(ScreenId screen) |
| 53 | : window_(NULL), |
| 54 | screen_(screen), |
| 55 | callback_(NULL), |
| 56 | mode_(SHAPE_AND_POSITION), |
| 57 | desktop_dc_(NULL), |
| 58 | last_cursor_(NULL) { |
| 59 | assert(screen >= kFullDesktopScreenId); |
| 60 | } |
| 61 | |
sergeyu@chromium.org | 2873c4c | 2013-10-17 19:47:18 +0000 | [diff] [blame] | 62 | MouseCursorMonitorWin::~MouseCursorMonitorWin() { |
| 63 | if (desktop_dc_) |
| 64 | ReleaseDC(NULL, desktop_dc_); |
| 65 | } |
| 66 | |
| 67 | void MouseCursorMonitorWin::Init(Callback* callback, Mode mode) { |
| 68 | assert(!callback_); |
| 69 | assert(callback); |
| 70 | |
| 71 | callback_ = callback; |
| 72 | mode_ = mode; |
| 73 | |
| 74 | desktop_dc_ = GetDC(NULL); |
| 75 | } |
| 76 | |
| 77 | void MouseCursorMonitorWin::Capture() { |
| 78 | assert(callback_); |
| 79 | |
| 80 | CURSORINFO cursor_info; |
| 81 | cursor_info.cbSize = sizeof(CURSORINFO); |
| 82 | if (!GetCursorInfo(&cursor_info)) { |
| 83 | LOG_F(LS_ERROR) << "Unable to get cursor info. Error = " << GetLastError(); |
| 84 | return; |
| 85 | } |
| 86 | |
| 87 | if (last_cursor_ != cursor_info.hCursor) { |
| 88 | last_cursor_ = cursor_info.hCursor; |
| 89 | // Note that |cursor_info.hCursor| does not need to be freed. |
| 90 | scoped_ptr<MouseCursor> cursor( |
| 91 | CreateMouseCursorFromHCursor(desktop_dc_, cursor_info.hCursor)); |
| 92 | if (cursor.get()) |
| 93 | callback_->OnMouseCursor(cursor.release()); |
| 94 | } |
| 95 | |
| 96 | if (mode_ != SHAPE_AND_POSITION) |
| 97 | return; |
| 98 | |
| 99 | DesktopVector position(cursor_info.ptScreenPos.x, cursor_info.ptScreenPos.y); |
| 100 | bool inside = cursor_info.flags == CURSOR_SHOWING; |
| 101 | |
| 102 | if (window_) { |
| 103 | RECT rect; |
| 104 | if (!GetWindowRect(window_, &rect)) { |
| 105 | position.set(0, 0); |
| 106 | inside = false; |
| 107 | } else { |
jiayl@webrtc.org | 4845e6e | 2014-02-04 17:49:12 +0000 | [diff] [blame] | 108 | if (inside) { |
| 109 | HWND windowUnderCursor = WindowFromPoint(cursor_info.ptScreenPos); |
| 110 | inside = windowUnderCursor ? |
| 111 | (window_ == GetAncestor(windowUnderCursor, GA_ROOT)) : false; |
| 112 | } |
sergeyu@chromium.org | 2873c4c | 2013-10-17 19:47:18 +0000 | [diff] [blame] | 113 | position = position.subtract(DesktopVector(rect.left, rect.top)); |
sergeyu@chromium.org | 2873c4c | 2013-10-17 19:47:18 +0000 | [diff] [blame] | 114 | } |
jiayl@webrtc.org | 28bd30a | 2014-01-17 17:19:16 +0000 | [diff] [blame] | 115 | } else { |
| 116 | assert(screen_ != kInvalidScreenId); |
| 117 | DesktopRect rect = GetScreenRect(); |
| 118 | if (inside) |
| 119 | inside = rect.Contains(position); |
| 120 | position = position.subtract(rect.top_left()); |
sergeyu@chromium.org | 2873c4c | 2013-10-17 19:47:18 +0000 | [diff] [blame] | 121 | } |
| 122 | |
| 123 | callback_->OnMouseCursorPosition(inside ? INSIDE : OUTSIDE, position); |
| 124 | } |
| 125 | |
jiayl@webrtc.org | 28bd30a | 2014-01-17 17:19:16 +0000 | [diff] [blame] | 126 | DesktopRect MouseCursorMonitorWin::GetScreenRect() { |
| 127 | assert(screen_ != kInvalidScreenId); |
| 128 | if (screen_ == kFullDesktopScreenId) { |
| 129 | return DesktopRect::MakeXYWH( |
| 130 | GetSystemMetrics(SM_XVIRTUALSCREEN), |
| 131 | GetSystemMetrics(SM_YVIRTUALSCREEN), |
| 132 | GetSystemMetrics(SM_CXVIRTUALSCREEN), |
| 133 | GetSystemMetrics(SM_CYVIRTUALSCREEN)); |
| 134 | } |
| 135 | DISPLAY_DEVICE device; |
| 136 | device.cb = sizeof(device); |
| 137 | BOOL result = EnumDisplayDevices(NULL, screen_, &device, 0); |
| 138 | if (!result) |
| 139 | return DesktopRect(); |
| 140 | |
| 141 | DEVMODE device_mode; |
| 142 | device_mode.dmSize = sizeof(device_mode); |
| 143 | device_mode.dmDriverExtra = 0; |
| 144 | result = EnumDisplaySettingsEx( |
| 145 | device.DeviceName, ENUM_CURRENT_SETTINGS, &device_mode, 0); |
| 146 | if (!result) |
| 147 | return DesktopRect(); |
| 148 | |
| 149 | return DesktopRect::MakeXYWH( |
| 150 | GetSystemMetrics(SM_XVIRTUALSCREEN) + device_mode.dmPosition.x, |
| 151 | GetSystemMetrics(SM_YVIRTUALSCREEN) + device_mode.dmPosition.y, |
| 152 | device_mode.dmPelsWidth, |
| 153 | device_mode.dmPelsHeight); |
| 154 | } |
| 155 | |
sergeyu@chromium.org | af54d4b | 2013-10-16 02:42:38 +0000 | [diff] [blame] | 156 | MouseCursorMonitor* MouseCursorMonitor::CreateForWindow( |
| 157 | const DesktopCaptureOptions& options, WindowId window) { |
sergeyu@chromium.org | 2873c4c | 2013-10-17 19:47:18 +0000 | [diff] [blame] | 158 | return new MouseCursorMonitorWin(reinterpret_cast<HWND>(window)); |
sergeyu@chromium.org | af54d4b | 2013-10-16 02:42:38 +0000 | [diff] [blame] | 159 | } |
| 160 | |
| 161 | MouseCursorMonitor* MouseCursorMonitor::CreateForScreen( |
jiayl@webrtc.org | a2c2654 | 2014-01-14 18:26:37 +0000 | [diff] [blame] | 162 | const DesktopCaptureOptions& options, |
| 163 | ScreenId screen) { |
jiayl@webrtc.org | 28bd30a | 2014-01-17 17:19:16 +0000 | [diff] [blame] | 164 | return new MouseCursorMonitorWin(screen); |
sergeyu@chromium.org | af54d4b | 2013-10-16 02:42:38 +0000 | [diff] [blame] | 165 | } |
| 166 | |
| 167 | } // namespace webrtc |