mouse_capture.mm 4.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134
  1. // Copyright 2014 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "base/memory/raw_ptr.h"
  5. #import "components/remote_cocoa/app_shim/mouse_capture.h"
  6. #import <Cocoa/Cocoa.h>
  7. #include "base/check_op.h"
  8. #import "components/remote_cocoa/app_shim/mouse_capture_delegate.h"
  9. #include "ui/base/cocoa/weak_ptr_nsobject.h"
  10. namespace remote_cocoa {
  11. // The ActiveEventTap is a RAII handle on the resources being used to capture
  12. // events. There is either 0 or 1 active instance of this class. If a second
  13. // instance is created, it will destroy the other instance before returning from
  14. // its constructor.
  15. class CocoaMouseCapture::ActiveEventTap {
  16. public:
  17. explicit ActiveEventTap(CocoaMouseCapture* owner);
  18. ActiveEventTap(const ActiveEventTap&) = delete;
  19. ActiveEventTap& operator=(const ActiveEventTap&) = delete;
  20. ~ActiveEventTap();
  21. // Returns the NSWindow with capture or nil if no window has capture
  22. // currently.
  23. static NSWindow* GetGlobalCaptureWindow();
  24. void Init();
  25. private:
  26. // Returns the associated NSWindow with capture.
  27. NSWindow* GetCaptureWindow() const;
  28. // The currently active event tap, or null if there is none.
  29. static ActiveEventTap* g_active_event_tap;
  30. raw_ptr<CocoaMouseCapture> owner_; // Weak. Owns this.
  31. id local_monitor_;
  32. id global_monitor_;
  33. ui::WeakPtrNSObjectFactory<CocoaMouseCapture> factory_;
  34. };
  35. CocoaMouseCapture::ActiveEventTap*
  36. CocoaMouseCapture::ActiveEventTap::g_active_event_tap = nullptr;
  37. CocoaMouseCapture::ActiveEventTap::ActiveEventTap(CocoaMouseCapture* owner)
  38. : owner_(owner),
  39. local_monitor_(nil),
  40. global_monitor_(nil),
  41. factory_(owner) {
  42. if (g_active_event_tap)
  43. g_active_event_tap->owner_->OnOtherClientGotCapture();
  44. DCHECK(!g_active_event_tap);
  45. g_active_event_tap = this;
  46. }
  47. CocoaMouseCapture::ActiveEventTap::~ActiveEventTap() {
  48. DCHECK_EQ(g_active_event_tap, this);
  49. [NSEvent removeMonitor:global_monitor_];
  50. [NSEvent removeMonitor:local_monitor_];
  51. g_active_event_tap = nullptr;
  52. owner_->delegate_->OnMouseCaptureLost();
  53. }
  54. // static
  55. NSWindow* CocoaMouseCapture::ActiveEventTap::GetGlobalCaptureWindow() {
  56. return g_active_event_tap ? g_active_event_tap->GetCaptureWindow() : nil;
  57. }
  58. void CocoaMouseCapture::ActiveEventTap::Init() {
  59. // Consume most things, but not NSEventTypeMouseEntered/Exited: The Widget
  60. // doing capture will still see its own Entered/Exit events, but not those for
  61. // other NSViews, since consuming those would break their tracking area logic.
  62. NSEventMask event_mask = NSEventMaskLeftMouseDown | NSEventMaskLeftMouseUp |
  63. NSEventMaskRightMouseDown | NSEventMaskRightMouseUp |
  64. NSEventMaskMouseMoved | NSEventMaskLeftMouseDragged |
  65. NSEventMaskRightMouseDragged |
  66. NSEventMaskScrollWheel | NSEventMaskOtherMouseDown |
  67. NSEventMaskOtherMouseUp |
  68. NSEventMaskOtherMouseDragged;
  69. // Capture a WeakPtr via NSObject. This allows the block to detect another
  70. // event monitor for the same event deleting |owner_|.
  71. WeakPtrNSObject* handle = factory_.handle();
  72. auto local_block = ^NSEvent*(NSEvent* event) {
  73. CocoaMouseCapture* owner =
  74. ui::WeakPtrNSObjectFactory<CocoaMouseCapture>::Get(handle);
  75. if (!owner)
  76. return event;
  77. bool handled = owner->delegate_->PostCapturedEvent(event);
  78. return handled ? nil : event;
  79. };
  80. auto global_block = ^void(NSEvent* event) {
  81. CocoaMouseCapture* owner =
  82. ui::WeakPtrNSObjectFactory<CocoaMouseCapture>::Get(handle);
  83. if (owner)
  84. owner->delegate_->PostCapturedEvent(event);
  85. };
  86. local_monitor_ = [NSEvent addLocalMonitorForEventsMatchingMask:event_mask
  87. handler:local_block];
  88. global_monitor_ =
  89. [NSEvent addGlobalMonitorForEventsMatchingMask:event_mask
  90. handler:global_block];
  91. }
  92. NSWindow* CocoaMouseCapture::ActiveEventTap::GetCaptureWindow() const {
  93. return owner_->delegate_->GetWindow();
  94. }
  95. CocoaMouseCapture::CocoaMouseCapture(CocoaMouseCaptureDelegate* delegate)
  96. : delegate_(delegate), active_handle_(new ActiveEventTap(this)) {
  97. active_handle_->Init();
  98. }
  99. CocoaMouseCapture::~CocoaMouseCapture() {}
  100. // static
  101. NSWindow* CocoaMouseCapture::GetGlobalCaptureWindow() {
  102. return ActiveEventTap::GetGlobalCaptureWindow();
  103. }
  104. void CocoaMouseCapture::OnOtherClientGotCapture() {
  105. DCHECK(active_handle_);
  106. active_handle_.reset();
  107. }
  108. } // namespace remote_cocoa