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