OLD | NEW |
---|---|
(Empty) | |
1 // Copyright 2015 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/host/touch_injector_win.h" | |
6 | |
7 #include "base/logging.h" | |
8 #include "base/stl_util.h" | |
9 #include "remoting/proto/event.pb.h" | |
10 | |
11 namespace remoting { | |
12 | |
13 using protocol::TouchEvent; | |
14 using protocol::TouchEventPoint; | |
15 | |
16 namespace { | |
17 | |
18 typedef BOOL(NTAPI* InitializeTouchInjectionFunction)(UINT32, DWORD); | |
19 typedef BOOL(NTAPI* InjectTouchInputFunction)(UINT32, | |
20 const POINTER_TOUCH_INFO*); | |
21 const uint32_t kMaxSimlutaneousTouchCount = 10; | |
Wez
2015/03/17 03:06:23
typo: Simultaneous
Rintaro Kuroiwa
2015/03/18 01:33:30
Done.
| |
22 | |
23 // Change the POINTER_TOUCH_INFO structures in the map to MOVE and copy those | |
24 // into |output_vector|. | |
Wez
2015/03/17 03:06:23
Why are you changing them in the map?
Isn't the p
Rintaro Kuroiwa
2015/03/18 01:33:31
Done.
As discussed offline, the map will always co
| |
25 // This is used to reinject all points that have not changed as "move"d point, | |
26 // even if it has not moved. | |
27 // This is required for multi-touch to work, e.g. pinching and zooming gestures | |
28 // (handled by apps) won't work without reinjection the points. If not | |
29 // reinjected, the injection API assumes that they were dropped. | |
30 void ChangeToMovePointsAndAppendToVector( | |
31 std::map<uint32_t, POINTER_TOUCH_INFO>* touches_in_contact, | |
32 std::vector<POINTER_TOUCH_INFO>* output_vector) { | |
33 DCHECK(touches_in_contact); | |
34 DCHECK(output_vector); | |
Wez
2015/03/17 03:06:23
You are about to dereference these anyway, below,
Rintaro Kuroiwa
2015/03/18 01:33:31
Done.
| |
35 for (auto& id_and_pointer_touch_info : *touches_in_contact) { | |
36 POINTER_TOUCH_INFO& pointer_touch_info = id_and_pointer_touch_info.second; | |
37 pointer_touch_info.pointerInfo.pointerFlags = | |
38 POINTER_FLAG_INRANGE | POINTER_FLAG_INCONTACT | POINTER_FLAG_UPDATE; | |
39 output_vector->push_back(pointer_touch_info); | |
40 } | |
41 } | |
42 | |
43 // The caller should set pointer_touch_info->pointerInfo.pointerFlags. | |
44 void ConvertToPointerTouchInfo( | |
45 const TouchEventPoint& touch_point, | |
46 POINTER_TOUCH_INFO* pointer_touch_info) { | |
47 DCHECK(pointer_touch_info); | |
Wez
2015/03/17 03:06:23
Same here
Rintaro Kuroiwa
2015/03/18 01:33:31
Done.
| |
48 | |
49 pointer_touch_info->touchMask = | |
50 TOUCH_MASK_CONTACTAREA | TOUCH_MASK_ORIENTATION; | |
51 pointer_touch_info->touchFlags = TOUCH_FLAG_NONE; | |
52 | |
53 // Although radius_{x,y} can be undefined (i.e. has_radius_{x,y} == false), | |
54 // the default value will set the area correctly. | |
Wez
2015/03/17 03:06:23
Why will the default value set it correctly? That
Rintaro Kuroiwa
2015/03/18 01:33:31
Yes it does rely on get on unset values return 0.
| |
55 pointer_touch_info->rcContact.left = | |
56 touch_point.x() - touch_point.radius_x(); | |
57 pointer_touch_info->rcContact.top = touch_point.y() - touch_point.radius_y(); | |
58 pointer_touch_info->rcContact.right = | |
59 touch_point.x() + touch_point.radius_x(); | |
60 pointer_touch_info->rcContact.bottom = | |
61 touch_point.y() + touch_point.radius_y(); | |
62 | |
63 pointer_touch_info->orientation = touch_point.angle(); | |
64 | |
65 if (touch_point.has_pressure()) { | |
66 pointer_touch_info->touchMask |= TOUCH_MASK_PRESSURE; | |
67 const int kMaxTouchPressure = 1024; // Defined in MSDN. | |
68 const int pressure = touch_point.pressure() * kMaxTouchPressure; | |
Wez
2015/03/17 03:06:23
Is there a danger of this wrapping? Should we inst
Rintaro Kuroiwa
2015/03/18 01:33:31
Done.
| |
69 if (pressure < 0) { | |
70 pointer_touch_info->pressure = 0; | |
71 } else if (pressure > kMaxTouchPressure) { | |
72 pointer_touch_info->pressure = kMaxTouchPressure; | |
73 } else { | |
74 pointer_touch_info->pressure = pressure; | |
75 } | |
76 } else { | |
77 // For a weird case where the pressure was there for a start event but | |
78 // not set in later events, set pressure to 0 because usually | |
79 // POINTER_TOUCH_INFO is memset() to 0. | |
Wez
2015/03/17 03:06:23
Is there a reason you don't both memset()ting it?
Rintaro Kuroiwa
2015/03/18 01:33:31
I was thinking if I memset(0) that's an extra writ
| |
80 pointer_touch_info->pressure = 0; | |
81 } | |
82 | |
83 pointer_touch_info->pointerInfo.pointerType = PT_TOUCH; | |
84 pointer_touch_info->pointerInfo.pointerId = touch_point.id(); | |
85 pointer_touch_info->pointerInfo.ptPixelLocation.x = touch_point.x(); | |
86 pointer_touch_info->pointerInfo.ptPixelLocation.y = touch_point.y(); | |
87 } | |
88 | |
89 } // namespace | |
90 | |
91 TouchInjectFunctionsWin::TouchInjectFunctionsWin() | |
92 : initialize_touch_injection_func_(nullptr), | |
93 inject_touch_input_func_(nullptr) {} | |
94 | |
95 TouchInjectFunctionsWin::~TouchInjectFunctionsWin() {} | |
96 | |
97 bool TouchInjectFunctionsWin::Init() { | |
Wez
2015/03/17 03:06:23
You can use base::NativeLibrary, which wraps all t
Rintaro Kuroiwa
2015/03/18 01:33:31
Done.
| |
98 if (initialize_touch_injection_func_ && inject_touch_input_func_) | |
99 return true; | |
100 | |
101 initialize_touch_injection_func_ = nullptr; | |
102 inject_touch_input_func_ = nullptr; | |
Wez
2015/03/17 03:06:23
Why are you NULLing these? You just checked that t
Rintaro Kuroiwa
2015/03/18 01:33:30
N/A in the new patch.
| |
103 HMODULE user32_dll_handle = ::GetModuleHandleA("User32.dll"); | |
104 if (!user32_dll_handle) { | |
105 PLOG(INFO) << "Failed to get User32.dll handle."; | |
106 return false; | |
107 } | |
108 | |
109 InitializeTouchInjectionFunction init_func = | |
110 reinterpret_cast<InitializeTouchInjectionFunction>( | |
111 ::GetProcAddress(user32_dll_handle, "InitializeTouchInjection")); | |
112 if (!init_func) { | |
113 PLOG(INFO) << "Failed to get InitializeTouchInjection function handle."; | |
114 return false; | |
115 } | |
116 | |
117 InjectTouchInputFunction inject_touch_func = | |
118 reinterpret_cast<InjectTouchInputFunction>( | |
119 ::GetProcAddress(user32_dll_handle, "InjectTouchInput")); | |
120 if (!inject_touch_func) { | |
121 PLOG(INFO) << "Failed to get InjectTouchInput."; | |
122 return false; | |
123 } | |
124 | |
125 initialize_touch_injection_func_ = init_func; | |
126 inject_touch_input_func_ = inject_touch_func; | |
127 return true; | |
128 } | |
129 | |
130 bool TouchInjectFunctionsWin::Initialized() { | |
131 DCHECK((initialize_touch_injection_func_ && inject_touch_input_func_) || | |
132 (!initialize_touch_injection_func_ && !inject_touch_input_func_)); | |
133 return initialize_touch_injection_func_ != nullptr; | |
134 } | |
135 | |
136 BOOL TouchInjectFunctionsWin::InitializeTouchInjection(UINT32 max_count, | |
137 DWORD dw_mode) { | |
Wez
2015/03/17 03:06:23
Indentation
Rintaro Kuroiwa
2015/03/18 01:33:31
Done.
| |
138 return initialize_touch_injection_func_(max_count, dw_mode); | |
139 } | |
140 | |
141 DWORD TouchInjectFunctionsWin::InjectTouchInput( | |
142 UINT32 count, | |
143 const POINTER_TOUCH_INFO* contacts) { | |
144 return inject_touch_input_func_(count, contacts); | |
145 } | |
146 | |
147 TouchInjectorWin::TouchInjectorWin() | |
148 : delegate_(new TouchInjectFunctionsWin()) {} | |
149 | |
150 TouchInjectorWin::~TouchInjectorWin() {} | |
151 | |
152 bool TouchInjectorWin::Init() { | |
153 if (!delegate_->Init()) | |
154 return false; | |
155 | |
156 if (!delegate_->InitializeTouchInjection(kMaxSimlutaneousTouchCount, | |
157 TOUCH_FEEDBACK_DEFAULT)) { | |
158 PLOG(INFO) << "Failed to initialize touch injection."; | |
Wez
2015/03/17 03:06:23
If you null the delegate_ here then you can check
Rintaro Kuroiwa
2015/03/18 01:33:30
Done.
| |
159 return false; | |
160 } | |
161 | |
162 return true; | |
163 } | |
164 | |
165 void TouchInjectorWin::Deinitialize() { | |
166 touches_in_contact_.clear(); | |
167 } | |
168 | |
169 void TouchInjectorWin::InjectTouchEvent(const TouchEvent& event) { | |
170 if (!delegate_->Initialized()) { | |
171 VLOG(3) << "Touch injection functions are not initialized."; | |
172 return; | |
173 } | |
174 | |
175 switch (event.event_type()) { | |
176 case TouchEvent::TOUCH_POINT_START: | |
177 AddNewTouchPoints(event); | |
178 break; | |
179 case TouchEvent::TOUCH_POINT_MOVE: | |
180 MoveTouchPoints(event); | |
181 break; | |
182 case TouchEvent::TOUCH_POINT_END: | |
183 EndTouchPoints(event); | |
184 break; | |
185 case TouchEvent::TOUCH_POINT_CANCEL: | |
186 CancelTouchPoints(event); | |
187 break; | |
188 default: | |
189 NOTREACHED(); | |
190 return; | |
191 } | |
192 } | |
193 | |
194 void TouchInjectorWin::SetInjectFunctionsForTest( | |
195 scoped_ptr<TouchInjectFunctionsWin> functions) { | |
196 delegate_ = functions.Pass(); | |
197 } | |
198 | |
199 void TouchInjectorWin::AddNewTouchPoints(const TouchEvent& event) { | |
200 DCHECK_EQ(event.event_type(), TouchEvent::TOUCH_POINT_START); | |
201 | |
202 std::vector<POINTER_TOUCH_INFO> touches; | |
203 // Must inject already touching points as move events. | |
204 ChangeToMovePointsAndAppendToVector(&touches_in_contact_, &touches); | |
205 | |
206 for (const TouchEventPoint& touch_point : event.touch_points()) { | |
207 POINTER_TOUCH_INFO pointer_touch_info; | |
208 memset(&pointer_touch_info, 0, sizeof(pointer_touch_info)); | |
209 pointer_touch_info.pointerInfo.pointerFlags = | |
210 POINTER_FLAG_INRANGE | POINTER_FLAG_INCONTACT | POINTER_FLAG_DOWN; | |
211 ConvertToPointerTouchInfo(touch_point, &pointer_touch_info); | |
212 touches_in_contact_[touch_point.id()] = pointer_touch_info; | |
213 touches.push_back(pointer_touch_info); | |
214 } | |
215 | |
216 if (delegate_->InjectTouchInput(touches.size(), | |
217 vector_as_array(&touches)) == 0) { | |
218 PLOG(ERROR) << "Failed to inject a touch start event."; | |
219 } | |
220 } | |
221 | |
222 void TouchInjectorWin::MoveTouchPoints(const TouchEvent& event) { | |
223 DCHECK_EQ(event.event_type(), TouchEvent::TOUCH_POINT_MOVE); | |
224 | |
225 for (const TouchEventPoint& touch_point : event.touch_points()) { | |
226 POINTER_TOUCH_INFO* pointer_touch_info = | |
227 &touches_in_contact_[touch_point.id()]; | |
228 pointer_touch_info->pointerInfo.pointerFlags = | |
229 POINTER_FLAG_INRANGE | POINTER_FLAG_INCONTACT | POINTER_FLAG_UPDATE; | |
230 ConvertToPointerTouchInfo(touch_point, pointer_touch_info); | |
231 } | |
232 | |
233 std::vector<POINTER_TOUCH_INFO> touches; | |
234 // Must inject already touching points as move events. | |
235 ChangeToMovePointsAndAppendToVector(&touches_in_contact_, &touches); | |
236 if (delegate_->InjectTouchInput(touches.size(), | |
237 vector_as_array(&touches)) == 0) { | |
238 PLOG(ERROR) << "Failed to inject a touch move event."; | |
239 } | |
240 } | |
241 | |
242 void TouchInjectorWin::EndTouchPoints(const TouchEvent& event) { | |
243 DCHECK_EQ(event.event_type(), TouchEvent::TOUCH_POINT_END); | |
244 | |
245 std::vector<POINTER_TOUCH_INFO> touches; | |
246 for (const TouchEventPoint& touch_point : event.touch_points()) { | |
247 POINTER_TOUCH_INFO pointer_touch_info = | |
248 touches_in_contact_[touch_point.id()]; | |
249 pointer_touch_info.pointerInfo.pointerFlags = POINTER_FLAG_UP; | |
250 | |
251 touches_in_contact_.erase(touch_point.id()); | |
252 touches.push_back(pointer_touch_info); | |
253 } | |
254 | |
255 ChangeToMovePointsAndAppendToVector(&touches_in_contact_, &touches); | |
256 if (delegate_->InjectTouchInput(touches.size(), | |
257 vector_as_array(&touches)) == 0) { | |
258 PLOG(ERROR) << "Failed to inject a touch end event."; | |
259 } | |
260 } | |
261 | |
262 void TouchInjectorWin::CancelTouchPoints(const TouchEvent& event) { | |
263 DCHECK_EQ(event.event_type(), TouchEvent::TOUCH_POINT_CANCEL); | |
264 | |
265 std::vector<POINTER_TOUCH_INFO> touches; | |
266 for (const TouchEventPoint& touch_point : event.touch_points()) { | |
267 POINTER_TOUCH_INFO pointer_touch_info = | |
268 touches_in_contact_[touch_point.id()]; | |
269 pointer_touch_info.pointerInfo.pointerFlags = | |
270 POINTER_FLAG_UP | POINTER_FLAG_CANCELED; | |
271 | |
272 touches_in_contact_.erase(touch_point.id()); | |
273 touches.push_back(pointer_touch_info); | |
274 } | |
275 | |
276 ChangeToMovePointsAndAppendToVector(&touches_in_contact_, &touches); | |
277 if (delegate_->InjectTouchInput(touches.size(), | |
278 vector_as_array(&touches)) == 0) { | |
279 PLOG(ERROR) << "Failed to inject a touch cancel event."; | |
280 } | |
281 } | |
282 | |
283 } // namespace remoting | |
284 | |
OLD | NEW |