Index: remoting/client/plugin/pepper_input_handler.cc |
diff --git a/remoting/client/plugin/pepper_input_handler.cc b/remoting/client/plugin/pepper_input_handler.cc |
index 1b67ba25d974f3aecce41543df68d626781675b7..cc1bef7d238c8bce5ec540ba2d7325b7064ff3c8 100644 |
--- a/remoting/client/plugin/pepper_input_handler.cc |
+++ b/remoting/client/plugin/pepper_input_handler.cc |
@@ -6,15 +6,24 @@ |
#include "base/logging.h" |
#include "ppapi/c/dev/ppb_keyboard_input_event_dev.h" |
+#include "ppapi/cpp/image_data.h" |
#include "ppapi/cpp/input_event.h" |
#include "ppapi/cpp/module_impl.h" |
+#include "ppapi/cpp/mouse_cursor.h" |
#include "ppapi/cpp/point.h" |
#include "remoting/proto/event.pb.h" |
namespace remoting { |
-PepperInputHandler::PepperInputHandler(protocol::InputStub* input_stub) |
- : input_stub_(input_stub), |
+PepperInputHandler::PepperInputHandler( |
+ pp::Instance* instance, |
+ protocol::InputStub* input_stub) |
+ : pp::MouseLock(instance), |
+ instance_(instance), |
+ input_stub_(input_stub), |
+ callback_factory_(this), |
+ has_focus_(false), |
+ mouse_lock_state_(MouseLockDisallowed), |
wheel_delta_x_(0), |
wheel_delta_y_(0), |
wheel_ticks_x_(0), |
@@ -98,6 +107,14 @@ bool PepperInputHandler::HandleInputEvent(const pp::InputEvent& event) { |
protocol::MouseEvent mouse_event; |
mouse_event.set_x(pp_mouse_event.GetPosition().x()); |
mouse_event.set_y(pp_mouse_event.GetPosition().y()); |
+ |
+ // Add relative movement if the mouse is locked. |
+ if (mouse_lock_state_ == MouseLockOn) { |
+ pp::Point delta = pp_mouse_event.GetMovement(); |
+ mouse_event.set_delta_x(delta.x()); |
+ mouse_event.set_delta_y(delta.y()); |
+ } |
+ |
input_stub_->InjectMouseEvent(mouse_event); |
return true; |
} |
@@ -159,4 +176,115 @@ bool PepperInputHandler::HandleInputEvent(const pp::InputEvent& event) { |
return false; |
} |
+void PepperInputHandler::AllowMouseLock() { |
+ DCHECK_EQ(mouse_lock_state_, MouseLockDisallowed); |
+ mouse_lock_state_ = MouseLockOff; |
+} |
+ |
+void PepperInputHandler::DidChangeFocus(bool has_focus) { |
+ has_focus_ = has_focus; |
+ if (has_focus_) |
+ RequestMouseLock(); |
+} |
+ |
+void PepperInputHandler::SetMouseCursor(scoped_ptr<pp::ImageData> image, |
+ const pp::Point& hotspot) { |
+ cursor_image_ = image.Pass(); |
+ cursor_hotspot_ = hotspot; |
+ |
+ if (mouse_lock_state_ != MouseLockDisallowed && !cursor_image_) { |
+ RequestMouseLock(); |
+ } else { |
+ CancelMouseLock(); |
+ } |
+} |
+ |
+void PepperInputHandler::MouseLockLost() { |
+ DCHECK(mouse_lock_state_ == MouseLockOn || |
+ mouse_lock_state_ == MouseLockCancelling); |
+ |
+ mouse_lock_state_ = MouseLockOff; |
+ UpdateMouseCursor(); |
+} |
+ |
+void PepperInputHandler::RequestMouseLock() { |
+ // Request mouse lock only if the plugin is focused, the host-supplied cursor |
+ // is empty and no callback is pending. |
+ if (has_focus_ && !cursor_image_ && mouse_lock_state_ == MouseLockOff) { |
+ pp::CompletionCallback callback = |
+ callback_factory_.NewCallback(&PepperInputHandler::OnMouseLocked); |
+ int result = pp::MouseLock::LockMouse(callback); |
+ DCHECK_EQ(result, PP_OK_COMPLETIONPENDING); |
+ |
+ // Hide cursor to avoid it becoming a black square (see crbug.com/285809). |
+ pp::MouseCursor::SetCursor(instance_, PP_MOUSECURSOR_TYPE_NONE); |
+ |
+ mouse_lock_state_ = MouseLockRequestPending; |
+ } |
+} |
+ |
+void PepperInputHandler::CancelMouseLock() { |
+ switch (mouse_lock_state_) { |
+ case MouseLockDisallowed: |
+ case MouseLockOff: |
+ UpdateMouseCursor(); |
+ break; |
+ |
+ case MouseLockCancelling: |
+ break; |
+ |
+ case MouseLockRequestPending: |
+ // The mouse lock request is pending. Delay UnlockMouse() call until |
+ // the callback is called. |
+ mouse_lock_state_ = MouseLockCancelling; |
+ break; |
+ |
+ case MouseLockOn: |
+ pp::MouseLock::UnlockMouse(); |
+ |
+ // Note that mouse-lock has been cancelled. We will continue to receive |
+ // locked events until MouseLockLost() is called back. |
+ mouse_lock_state_ = MouseLockCancelling; |
+ break; |
+ |
+ default: |
+ NOTREACHED(); |
+ } |
+} |
+ |
+void PepperInputHandler::UpdateMouseCursor() { |
+ DCHECK(mouse_lock_state_ == MouseLockDisallowed || |
+ mouse_lock_state_ == MouseLockOff); |
+ |
+ if (cursor_image_) { |
+ pp::MouseCursor::SetCursor(instance_, PP_MOUSECURSOR_TYPE_CUSTOM, |
+ *cursor_image_, |
+ cursor_hotspot_); |
+ } else { |
+ // If there is no cursor shape stored, either because the host never |
+ // supplied one, or we were previously in mouse-lock mode, then use |
+ // a standard arrow pointer. |
+ pp::MouseCursor::SetCursor(instance_, PP_MOUSECURSOR_TYPE_POINTER); |
+ } |
+} |
+ |
+void PepperInputHandler::OnMouseLocked(int error) { |
+ DCHECK(mouse_lock_state_ == MouseLockRequestPending || |
+ mouse_lock_state_ == MouseLockCancelling); |
+ |
+ bool should_cancel = (mouse_lock_state_ == MouseLockCancelling); |
+ |
+ // See if the operation succeeded. |
+ if (error == PP_OK) { |
+ mouse_lock_state_ = MouseLockOn; |
+ } else { |
+ mouse_lock_state_ = MouseLockOff; |
+ UpdateMouseCursor(); |
+ } |
+ |
+ // Cancel as needed. |
+ if (should_cancel) |
+ CancelMouseLock(); |
+} |
+ |
} // namespace remoting |