Home | History | Annotate | Download | only in desktop_capture
      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/include/logging.h"
     20 
     21 namespace webrtc {
     22 
     23 class MouseCursorMonitorWin : public MouseCursorMonitor {
     24  public:
     25   explicit MouseCursorMonitorWin(HWND window);
     26   explicit MouseCursorMonitorWin(ScreenId screen);
     27   virtual ~MouseCursorMonitorWin();
     28 
     29   void Init(Callback* callback, Mode mode) override;
     30   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 
     49 MouseCursorMonitorWin::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 
     58 MouseCursorMonitorWin::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 
     68 MouseCursorMonitorWin::~MouseCursorMonitorWin() {
     69   if (desktop_dc_)
     70     ReleaseDC(NULL, desktop_dc_);
     71 }
     72 
     73 void 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 
     83 void 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     rtc::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 
    133 DesktopRect 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 
    162 MouseCursorMonitor* MouseCursorMonitor::CreateForWindow(
    163     const DesktopCaptureOptions& options, WindowId window) {
    164   return new MouseCursorMonitorWin(reinterpret_cast<HWND>(window));
    165 }
    166 
    167 MouseCursorMonitor* MouseCursorMonitor::CreateForScreen(
    168     const DesktopCaptureOptions& options,
    169     ScreenId screen) {
    170   return new MouseCursorMonitorWin(screen);
    171 }
    172 
    173 }  // namespace webrtc
    174