Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(245)

Side by Side Diff: remoting/host/touch_injector_win.cc

Issue 991643002: Windows Host Touch Injection (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Add Deinitialize() and change test Created 5 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(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
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698