gesture_interpreter.cc 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291
  1. // Copyright 2017 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 "remoting/client/gesture_interpreter.h"
  5. #include <memory>
  6. #include "base/bind.h"
  7. #include "base/time/time.h"
  8. #include "remoting/client/chromoting_session.h"
  9. #include "remoting/client/display/renderer_proxy.h"
  10. #include "remoting/client/input/direct_touch_input_strategy.h"
  11. #include "remoting/client/input/trackpad_input_strategy.h"
  12. namespace {
  13. const float kOneFingerFlingTimeConstant = 180.f;
  14. const float kScrollFlingTimeConstant = 250.f;
  15. } // namespace
  16. namespace remoting {
  17. GestureInterpreter::GestureInterpreter()
  18. // TODO(yuweih): These animations are better to take GetWeakPtr().
  19. : pan_animation_(
  20. kOneFingerFlingTimeConstant,
  21. base::BindRepeating(&GestureInterpreter::PanWithoutAbortAnimations,
  22. base::Unretained(this))),
  23. scroll_animation_(
  24. kScrollFlingTimeConstant,
  25. base::BindRepeating(&GestureInterpreter::ScrollWithoutAbortAnimations,
  26. base::Unretained(this))) {}
  27. GestureInterpreter::~GestureInterpreter() = default;
  28. void GestureInterpreter::SetContext(RendererProxy* renderer,
  29. ChromotingSession* input_stub) {
  30. renderer_ = renderer;
  31. input_stub_ = input_stub;
  32. auto transformation_callback =
  33. renderer_ ? base::BindRepeating(&RendererProxy::SetTransformation,
  34. base::Unretained(renderer_))
  35. : DesktopViewport::TransformationCallback();
  36. viewport_.RegisterOnTransformationChangedCallback(transformation_callback,
  37. true);
  38. }
  39. void GestureInterpreter::SetInputMode(InputMode mode) {
  40. switch (mode) {
  41. case DIRECT_INPUT_MODE:
  42. input_strategy_ = std::make_unique<DirectTouchInputStrategy>();
  43. break;
  44. case TRACKPAD_INPUT_MODE:
  45. input_strategy_ = std::make_unique<TrackpadInputStrategy>(viewport_);
  46. break;
  47. default:
  48. NOTREACHED();
  49. }
  50. input_mode_ = mode;
  51. if (!renderer_) {
  52. return;
  53. }
  54. renderer_->SetCursorVisibility(input_strategy_->IsCursorVisible());
  55. ViewMatrix::Point cursor_position = input_strategy_->GetCursorPosition();
  56. renderer_->SetCursorPosition(cursor_position.x, cursor_position.y);
  57. }
  58. GestureInterpreter::InputMode GestureInterpreter::GetInputMode() const {
  59. return input_mode_;
  60. }
  61. void GestureInterpreter::Zoom(float pivot_x,
  62. float pivot_y,
  63. float scale,
  64. GestureState state) {
  65. AbortAnimations();
  66. SetGestureInProgress(TouchInputStrategy::ZOOM, state != GESTURE_ENDED);
  67. if (viewport_.IsViewportReady()) {
  68. input_strategy_->HandleZoom({pivot_x, pivot_y}, scale, &viewport_);
  69. }
  70. }
  71. void GestureInterpreter::Pan(float translation_x, float translation_y) {
  72. AbortAnimations();
  73. PanWithoutAbortAnimations(translation_x, translation_y);
  74. }
  75. void GestureInterpreter::Tap(float x, float y) {
  76. AbortAnimations();
  77. InjectMouseClick(x, y, protocol::MouseEvent_MouseButton_BUTTON_LEFT);
  78. }
  79. void GestureInterpreter::TwoFingerTap(float x, float y) {
  80. AbortAnimations();
  81. InjectMouseClick(x, y, protocol::MouseEvent_MouseButton_BUTTON_RIGHT);
  82. }
  83. void GestureInterpreter::ThreeFingerTap(float x, float y) {
  84. AbortAnimations();
  85. InjectMouseClick(x, y, protocol::MouseEvent_MouseButton_BUTTON_MIDDLE);
  86. }
  87. void GestureInterpreter::Drag(float x, float y, GestureState state) {
  88. AbortAnimations();
  89. bool is_dragging_mode = state != GESTURE_ENDED;
  90. SetGestureInProgress(TouchInputStrategy::DRAG, is_dragging_mode);
  91. if (!input_stub_ || !viewport_.IsViewportReady() ||
  92. !input_strategy_->TrackTouchInput({x, y}, viewport_)) {
  93. return;
  94. }
  95. ViewMatrix::Point cursor_position = input_strategy_->GetCursorPosition();
  96. switch (state) {
  97. case GESTURE_BEGAN:
  98. StartInputFeedback(cursor_position.x, cursor_position.y,
  99. TouchInputStrategy::DRAG_FEEDBACK);
  100. input_stub_->SendMouseEvent(cursor_position.x, cursor_position.y,
  101. protocol::MouseEvent_MouseButton_BUTTON_LEFT,
  102. true);
  103. break;
  104. case GESTURE_CHANGED:
  105. InjectCursorPosition(cursor_position.x, cursor_position.y);
  106. break;
  107. case GESTURE_ENDED:
  108. input_stub_->SendMouseEvent(cursor_position.x, cursor_position.y,
  109. protocol::MouseEvent_MouseButton_BUTTON_LEFT,
  110. false);
  111. break;
  112. default:
  113. NOTREACHED();
  114. }
  115. }
  116. void GestureInterpreter::OneFingerFling(float velocity_x, float velocity_y) {
  117. AbortAnimations();
  118. pan_animation_.SetVelocity(velocity_x, velocity_y);
  119. pan_animation_.Tick();
  120. }
  121. void GestureInterpreter::Scroll(float x, float y, float dx, float dy) {
  122. AbortAnimations();
  123. if (!viewport_.IsViewportReady() ||
  124. !input_strategy_->TrackTouchInput({x, y}, viewport_)) {
  125. return;
  126. }
  127. ViewMatrix::Point cursor_position = input_strategy_->GetCursorPosition();
  128. // Inject the cursor position to the host so that scrolling can happen on the
  129. // right place.
  130. InjectCursorPosition(cursor_position.x, cursor_position.y);
  131. ScrollWithoutAbortAnimations(dx, dy);
  132. }
  133. void GestureInterpreter::ScrollWithVelocity(float velocity_x,
  134. float velocity_y) {
  135. AbortAnimations();
  136. scroll_animation_.SetVelocity(velocity_x, velocity_y);
  137. scroll_animation_.Tick();
  138. }
  139. void GestureInterpreter::ProcessAnimations() {
  140. pan_animation_.Tick();
  141. // TODO(yuweih): It's probably not right to handle host side virtual scroll
  142. // momentum in the renderer's callback.
  143. scroll_animation_.Tick();
  144. }
  145. void GestureInterpreter::OnSurfaceSizeChanged(int width, int height) {
  146. viewport_.SetSurfaceSize(width, height);
  147. if (viewport_.IsViewportReady()) {
  148. input_strategy_->FocusViewportOnCursor(&viewport_);
  149. }
  150. }
  151. void GestureInterpreter::OnDesktopSizeChanged(int width, int height) {
  152. viewport_.SetDesktopSize(width, height);
  153. if (viewport_.IsViewportReady()) {
  154. input_strategy_->FocusViewportOnCursor(&viewport_);
  155. }
  156. }
  157. void GestureInterpreter::OnSafeInsetsChanged(int left,
  158. int top,
  159. int right,
  160. int bottom) {
  161. viewport_.SetSafeInsets(left, top, right, bottom);
  162. if (viewport_.IsViewportReady()) {
  163. input_strategy_->FocusViewportOnCursor(&viewport_);
  164. }
  165. }
  166. base::WeakPtr<GestureInterpreter> GestureInterpreter::GetWeakPtr() {
  167. return weak_factory_.GetWeakPtr();
  168. }
  169. void GestureInterpreter::PanWithoutAbortAnimations(float translation_x,
  170. float translation_y) {
  171. if (viewport_.IsViewportReady() &&
  172. input_strategy_->HandlePan({translation_x, translation_y},
  173. gesture_in_progress_, &viewport_)) {
  174. // Cursor position changed.
  175. ViewMatrix::Point cursor_position = input_strategy_->GetCursorPosition();
  176. if (gesture_in_progress_ != TouchInputStrategy::DRAG) {
  177. // Drag() will inject the position so don't need to do that in that case.
  178. InjectCursorPosition(cursor_position.x, cursor_position.y);
  179. }
  180. if (renderer_) {
  181. renderer_->SetCursorPosition(cursor_position.x, cursor_position.y);
  182. }
  183. }
  184. }
  185. void GestureInterpreter::InjectCursorPosition(float x, float y) {
  186. if (!input_stub_) {
  187. return;
  188. }
  189. input_stub_->SendMouseEvent(
  190. x, y, protocol::MouseEvent_MouseButton_BUTTON_UNDEFINED, false);
  191. }
  192. void GestureInterpreter::ScrollWithoutAbortAnimations(float dx, float dy) {
  193. if (!input_stub_ || !viewport_.IsViewportReady()) {
  194. return;
  195. }
  196. ViewMatrix::Point desktopDelta =
  197. input_strategy_->MapScreenVectorToDesktop({dx, dy}, viewport_);
  198. input_stub_->SendMouseWheelEvent(desktopDelta.x, desktopDelta.y);
  199. }
  200. void GestureInterpreter::AbortAnimations() {
  201. pan_animation_.Abort();
  202. scroll_animation_.Abort();
  203. }
  204. void GestureInterpreter::InjectMouseClick(
  205. float touch_x,
  206. float touch_y,
  207. protocol::MouseEvent_MouseButton button) {
  208. if (!input_stub_ || !viewport_.IsViewportReady() ||
  209. !input_strategy_->TrackTouchInput({touch_x, touch_y}, viewport_)) {
  210. return;
  211. }
  212. ViewMatrix::Point cursor_position = input_strategy_->GetCursorPosition();
  213. StartInputFeedback(cursor_position.x, cursor_position.y,
  214. TouchInputStrategy::TAP_FEEDBACK);
  215. input_stub_->SendMouseEvent(cursor_position.x, cursor_position.y, button,
  216. true);
  217. input_stub_->SendMouseEvent(cursor_position.x, cursor_position.y, button,
  218. false);
  219. }
  220. void GestureInterpreter::SetGestureInProgress(
  221. TouchInputStrategy::Gesture gesture,
  222. bool is_in_progress) {
  223. if (!is_in_progress && gesture_in_progress_ == gesture) {
  224. gesture_in_progress_ = TouchInputStrategy::NONE;
  225. return;
  226. }
  227. gesture_in_progress_ = gesture;
  228. }
  229. void GestureInterpreter::StartInputFeedback(
  230. float cursor_x,
  231. float cursor_y,
  232. TouchInputStrategy::TouchFeedbackType feedback_type) {
  233. // This radius is on the view's coordinates. Need to be converted to desktop
  234. // coordinate.
  235. float feedback_radius = input_strategy_->GetFeedbackRadius(feedback_type);
  236. if (feedback_radius > 0) {
  237. // TODO(yuweih): The renderer takes diameter as parameter. Consider moving
  238. // the *2 logic inside the renderer.
  239. float diameter_on_desktop =
  240. 2.f * feedback_radius / viewport_.GetTransformation().GetScale();
  241. if (renderer_) {
  242. renderer_->StartInputFeedback(cursor_x, cursor_y, diameter_on_desktop);
  243. }
  244. }
  245. }
  246. } // namespace remoting