Chromium Code Reviews| 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 |