OLD | NEW |
(Empty) | |
| 1 // Copyright (c) 2012 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 "ui/aura/gestures/gesture_recognizer_grail.h" |
| 6 |
| 7 #include <utouch/grail.h> |
| 8 |
| 9 #include "base/logging.h" |
| 10 #include "base/memory/scoped_ptr.h" |
| 11 #include "base/memory/singleton.h" |
| 12 #include "base/time.h" |
| 13 #include "ui/aura/event.h" |
| 14 #include "ui/aura/window.h" |
| 15 #include "ui/base/events.h" |
| 16 #include "ui/base/touch/touch_factory.h" |
| 17 #include "ui/base/x/x11_util.h" |
| 18 |
| 19 namespace { |
| 20 |
| 21 static const base::TimeDelta kLongPressTimeThreshold |
| 22 = base::TimeDelta::FromMilliseconds(3000); |
| 23 |
| 24 static const base::TimeDelta kDoubleTapTimeout |
| 25 = base::TimeDelta::FromMilliseconds(300); |
| 26 |
| 27 bool GetDeviceAndWindowFromEvent( |
| 28 const UFEvent event, |
| 29 UFDevice* device, |
| 30 UFWindowId* window_id) { |
| 31 |
| 32 UFFrame frame; |
| 33 UFStatus status = frame_event_get_property(event, UFEventPropertyFrame, |
| 34 &frame); |
| 35 if (status != UFStatusSuccess) { |
| 36 LOG(ERROR) << "failed to get frame from event\n"; |
| 37 return false; |
| 38 } |
| 39 |
| 40 *device = frame_frame_get_device(frame); |
| 41 *window_id = frame_frame_get_window_id(frame); |
| 42 |
| 43 char * deviceName; |
| 44 if (UFStatusSuccess == |
| 45 frame_device_get_property(*device, UFDevicePropertyName, &deviceName)) |
| 46 DLOG(INFO) << "Considering device: " << deviceName; |
| 47 else |
| 48 DLOG(INFO) << "Problem reading out device name."; |
| 49 |
| 50 return true; |
| 51 } |
| 52 |
| 53 // Subscribes to the grail instance (handle) |
| 54 // for two-finger taps, drags and pinches. Please |
| 55 // note that subscribing to the grail instance is non-blocking. |
| 56 // Returns an int with boolean semantics to indicate success or failure. |
| 57 int SubscribeForGestures( |
| 58 UGHandle handle, |
| 59 UFDevice device, |
| 60 ::Window window, |
| 61 UGSubscription subscription) { |
| 62 char * deviceName = NULL; |
| 63 if (UFStatusSuccess == |
| 64 frame_device_get_property(device, UFDevicePropertyName, &deviceName)) |
| 65 DLOG(INFO) << "Subscribing to device: " << deviceName; |
| 66 |
| 67 UGStatus status; |
| 68 |
| 69 int touches_start = 2; |
| 70 int touches_max = 2; |
| 71 int touches_min = 2; |
| 72 int atomic = 1; |
| 73 |
| 74 UFWindowId window_id = frame_x11_create_window_id(window); |
| 75 const UGGestureTypeMask mask = |
| 76 UGGestureTypeDrag | |
| 77 UGGestureTypePinch | |
| 78 UGGestureTypeTap; |
| 79 status = grail_subscription_new(&subscription); |
| 80 if (status != UGStatusSuccess) { |
| 81 LOG(ERROR) << "Failed to create subscription"; |
| 82 return 0; |
| 83 } |
| 84 |
| 85 status = grail_subscription_set_property(subscription, |
| 86 UGSubscriptionPropertyDevice, |
| 87 &device); |
| 88 if (status != UGStatusSuccess) { |
| 89 LOG(ERROR) << "Failed to set subscription device"; |
| 90 return 0; |
| 91 } |
| 92 |
| 93 status = grail_subscription_set_property(subscription, |
| 94 UGSubscriptionPropertyWindow, |
| 95 &window_id); |
| 96 if (status != UGStatusSuccess) { |
| 97 LOG(ERROR) << "Failed to set subscription window"; |
| 98 return 0; |
| 99 } |
| 100 |
| 101 status = grail_subscription_set_property(subscription, |
| 102 UGSubscriptionPropertyAtomicGestures, |
| 103 &atomic); |
| 104 if (status != UGStatusSuccess) { |
| 105 LOG(ERROR) << "Failed to set atomic gestures subscription property."; |
| 106 return 0; |
| 107 } |
| 108 |
| 109 status = grail_subscription_set_property(subscription, |
| 110 UGSubscriptionPropertyTouchesStart, |
| 111 &touches_start); |
| 112 if (status != UGStatusSuccess) { |
| 113 LOG(ERROR) << "Failed to set subscription start touches."; |
| 114 return 0; |
| 115 } |
| 116 |
| 117 status = grail_subscription_set_property(subscription, |
| 118 UGSubscriptionPropertyTouchesMaximum, |
| 119 &touches_max); |
| 120 if (status != UGStatusSuccess) { |
| 121 LOG(ERROR) << "Failed to set subscription start touches."; |
| 122 return 0; |
| 123 } |
| 124 |
| 125 status = grail_subscription_set_property(subscription, |
| 126 UGSubscriptionPropertyTouchesMinimum, |
| 127 &touches_min); |
| 128 if (status != UGStatusSuccess) { |
| 129 LOG(ERROR) << "Failed to set subscription min touches."; |
| 130 return 0; |
| 131 } |
| 132 |
| 133 status = grail_subscription_set_property(subscription, |
| 134 UGSubscriptionPropertyMask, |
| 135 &mask); |
| 136 if (status != UGStatusSuccess) { |
| 137 LOG(ERROR) << "Failed to set subscription mask"; |
| 138 return 0; |
| 139 } |
| 140 |
| 141 status = grail_subscription_activate(handle, subscription); |
| 142 if (status != UGStatusSuccess) { |
| 143 LOG(ERROR) << "Failed to activate subscription\n"; |
| 144 return 0; |
| 145 } |
| 146 |
| 147 DLOG(INFO) << "Successfully configured and activated grail subscription"; |
| 148 |
| 149 return 1; |
| 150 } |
| 151 |
| 152 } // namespace |
| 153 |
| 154 namespace aura { |
| 155 |
| 156 // Implements a singleton for a raw grail instance and |
| 157 // makes sure that RAII. |
| 158 class GrailHolder { |
| 159 public: |
| 160 // Returns the singleton instance |
| 161 static GrailHolder* GetInstance() { |
| 162 return Singleton<GrailHolder>::get(); |
| 163 } |
| 164 |
| 165 // Returns the handle managed by the instance |
| 166 UGHandle handle() const { |
| 167 return utouch_grail_handle_; |
| 168 } |
| 169 |
| 170 private: |
| 171 friend struct DefaultSingletonTraits<GrailHolder>; |
| 172 |
| 173 GrailHolder() |
| 174 : utouch_grail_handle_(NULL) { |
| 175 if (UGStatusSuccess != grail_new( |
| 176 ui::TouchFactory::GetInstance()->handle(), |
| 177 &utouch_grail_handle_)) { |
| 178 LOG(ERROR) << "Problem initializing grail api."; |
| 179 } else { |
| 180 fd_set set; |
| 181 FD_ZERO(&set); |
| 182 int fd = grail_get_fd(utouch_grail_handle_); |
| 183 FD_SET(fd, &set); |
| 184 } |
| 185 } |
| 186 |
| 187 ~GrailHolder() { |
| 188 if (utouch_grail_handle_ != NULL) |
| 189 grail_delete_v3(utouch_grail_handle_); |
| 190 } |
| 191 |
| 192 UGHandle utouch_grail_handle_; |
| 193 |
| 194 DISALLOW_COPY_AND_ASSIGN(GrailHolder); |
| 195 }; |
| 196 |
| 197 struct GestureRecognizerGrail::Private { |
| 198 typedef std::map<UFDevice, UGSubscription> SubscriptionMap; |
| 199 |
| 200 explicit Private(RootWindow* window) |
| 201 : flags_(0), |
| 202 window_(window) { |
| 203 } |
| 204 |
| 205 ~Private() { |
| 206 SubscriptionMap::iterator it; |
| 207 for (it = subscriptions_.begin(); |
| 208 it != subscriptions_.end(); |
| 209 ++it) { |
| 210 grail_subscription_delete(it->second); |
| 211 } |
| 212 } |
| 213 |
| 214 void ProcessSlice( |
| 215 UGSlice slice, |
| 216 uint64_t time, |
| 217 const TouchEvent& event, |
| 218 GestureRecognizer::Gestures * result) { |
| 219 assert(result != NULL); |
| 220 |
| 221 const UGGestureTypeMask recognized = grail_slice_get_recognized(slice); |
| 222 |
| 223 if (recognized & UGGestureTypePinch) { |
| 224 linked_ptr<GestureEvent> lp(ProcessPinch(slice, event)); |
| 225 if (lp.get() != NULL) |
| 226 result->push_back(lp); |
| 227 } |
| 228 |
| 229 if (recognized & UGGestureTypeDrag) { |
| 230 linked_ptr<GestureEvent> lp(ProcessDrag(slice, event)); |
| 231 if (lp.get() != NULL) |
| 232 result->push_back(lp); |
| 233 } |
| 234 |
| 235 if (recognized & UGGestureTypeTap) { |
| 236 linked_ptr<GestureEvent> lp(ProcessTap(slice, event)); |
| 237 if (lp.get() != NULL) |
| 238 result->push_back(lp); |
| 239 } |
| 240 } |
| 241 |
| 242 linked_ptr<GestureEvent> ProcessDrag(UGSlice slice, |
| 243 const TouchEvent& touch_event) { |
| 244 ui::EventType event_type = ui::ET_UNKNOWN; |
| 245 |
| 246 switch (grail_slice_get_state(slice)) { |
| 247 case UGGestureStateBegin: |
| 248 event_type = ui::ET_GESTURE_SCROLL_BEGIN; |
| 249 break; |
| 250 case UGGestureStateUpdate: |
| 251 event_type = ui::ET_GESTURE_SCROLL_UPDATE; |
| 252 break; |
| 253 case UGGestureStateEnd: |
| 254 event_type = ui::ET_GESTURE_SCROLL_END; |
| 255 break; |
| 256 } |
| 257 |
| 258 const UGTransform *transform = |
| 259 grail_slice_get_transform(slice); |
| 260 |
| 261 GestureEvent::Properties props; |
| 262 props.delta_x = -(*transform)[0][2]; |
| 263 props.delta_y = -(*transform)[1][2]; |
| 264 |
| 265 GestureEvent * result = new GestureEvent(event_type, |
| 266 touch_event.x(), |
| 267 touch_event.y(), |
| 268 touch_event.flags(), |
| 269 base::Time::Now(), |
| 270 props); |
| 271 return linked_ptr<GestureEvent>(result); |
| 272 } |
| 273 |
| 274 linked_ptr<GestureEvent> ProcessPinch(UGSlice slice, |
| 275 const TouchEvent & touch_event) { |
| 276 ui::EventType event_type = ui::ET_UNKNOWN; |
| 277 switch (grail_slice_get_state(slice)) { |
| 278 case UGGestureStateBegin: |
| 279 event_type = ui::ET_GESTURE_PINCH_BEGIN; |
| 280 break; |
| 281 case UGGestureStateUpdate: |
| 282 event_type = ui::ET_GESTURE_PINCH_UPDATE; |
| 283 break; |
| 284 case UGGestureStateEnd: |
| 285 event_type = ui::ET_GESTURE_PINCH_END; |
| 286 break; |
| 287 } |
| 288 |
| 289 const UGTransform *transform = |
| 290 grail_slice_get_cumulative_transform(slice); |
| 291 |
| 292 GestureEvent::Properties props; |
| 293 props.delta_x = (*transform)[0][0]; |
| 294 props.delta_y = (*transform)[1][1]; |
| 295 props.scale_x = (*transform)[0][0]; |
| 296 props.scale_y = (*transform)[1][1]; |
| 297 |
| 298 GestureEvent * result = new GestureEvent(event_type, |
| 299 touch_event.x(), |
| 300 touch_event.y(), |
| 301 touch_event.flags(), |
| 302 base::Time::Now(), |
| 303 props); |
| 304 |
| 305 return linked_ptr<GestureEvent>(result); |
| 306 } |
| 307 |
| 308 linked_ptr<GestureEvent> ProcessTap(UGSlice slice, |
| 309 const TouchEvent & touch_event) { |
| 310 ui::EventType event_type = ui::ET_UNKNOWN; |
| 311 switch (grail_slice_get_state(slice)) { |
| 312 case UGGestureStateBegin: |
| 313 gesture_tap_start_ = base::Time::Now(); |
| 314 return linked_ptr<GestureEvent>(NULL); |
| 315 break; |
| 316 case UGGestureStateUpdate: |
| 317 return linked_ptr<GestureEvent>(NULL); |
| 318 break; |
| 319 case UGGestureStateEnd: { |
| 320 base::Time now = base::Time::Now(); |
| 321 base::TimeDelta dlp = now - gesture_tap_start_; |
| 322 base::TimeDelta ddt = now - last_gesture_tap_completed_; |
| 323 if (dlp >= kLongPressTimeThreshold) { |
| 324 event_type = ui::ET_GESTURE_LONG_PRESS; |
| 325 } else if (ddt < kDoubleTapTimeout) { |
| 326 event_type = ui::ET_GESTURE_DOUBLE_TAP; |
| 327 } else { |
| 328 event_type = ui::ET_GESTURE_TAP; |
| 329 last_gesture_tap_completed_ = now; |
| 330 } |
| 331 gesture_tap_start_ = base::Time::Now(); |
| 332 break; |
| 333 } |
| 334 } |
| 335 |
| 336 return linked_ptr<GestureEvent>(new GestureEvent( |
| 337 event_type, |
| 338 touch_event.x(), |
| 339 touch_event.y(), |
| 340 touch_event.flags(), |
| 341 base::Time::Now(), |
| 342 GestureEvent::Properties())); |
| 343 } |
| 344 |
| 345 int flags_; |
| 346 RootWindow* window_; |
| 347 |
| 348 base::Time last_gesture_tap_completed_; |
| 349 base::Time gesture_tap_start_; |
| 350 |
| 351 SubscriptionMap subscriptions_; |
| 352 }; |
| 353 |
| 354 |
| 355 //////////////////////////////////////////////////////////////////////////////// |
| 356 // GestureRecognizerGrail Public: |
| 357 |
| 358 GestureRecognizerGrail::GestureRecognizerGrail(RootWindow* window) |
| 359 : d_(new Private(window)) { |
| 360 } |
| 361 |
| 362 GestureRecognizer::Gestures* |
| 363 GestureRecognizerGrail::ProcessTouchEventForGesture( |
| 364 const TouchEvent& event, |
| 365 ui::TouchStatus status) { |
| 366 |
| 367 UFEvent ufEvent; |
| 368 while (frame_get_event( |
| 369 ui::TouchFactory::GetInstance()->handle(), |
| 370 &ufEvent) == |
| 371 UFStatusSuccess) { |
| 372 grail_process_frame_event( |
| 373 GrailHolder::GetInstance()->handle(), |
| 374 ufEvent); |
| 375 |
| 376 switch (frame_event_get_type(ufEvent)) { |
| 377 case UFEventTypeDeviceAdded: { |
| 378 UFDevice device = NULL; |
| 379 UFStatus status = frame_event_get_property(ufEvent, |
| 380 UFEventPropertyDevice, |
| 381 &device); |
| 382 |
| 383 if (status != UFStatusSuccess) |
| 384 LOG(ERROR) << "Failed to get device from event."; |
| 385 else |
| 386 SubscribeForGestures( |
| 387 GrailHolder::GetInstance()->handle(), |
| 388 device, |
| 389 ui::TouchFactory::GetInstance()->native_root_window_aura(), |
| 390 d_->subscriptions_[device]); |
| 391 |
| 392 break; |
| 393 } |
| 394 |
| 395 case UFEventTypeDeviceRemoved: { |
| 396 UFDevice device = NULL; |
| 397 UFStatus status = frame_event_get_property(ufEvent, |
| 398 UFEventPropertyDevice, |
| 399 &device); |
| 400 |
| 401 if (status != UFStatusSuccess) { |
| 402 LOG(ERROR) << "Failed to get device from event."; |
| 403 } else { |
| 404 Private::SubscriptionMap::iterator it = |
| 405 d_->subscriptions_.find(device); |
| 406 if (it != d_->subscriptions_.end()) { |
| 407 grail_subscription_delete(it->second); |
| 408 d_->subscriptions_.erase(it); |
| 409 } |
| 410 } |
| 411 break; |
| 412 } |
| 413 default: |
| 414 break; |
| 415 } |
| 416 |
| 417 frame_event_unref(ufEvent); |
| 418 } |
| 419 |
| 420 Gestures * result = new Gestures(); |
| 421 UGEvent ugEvent; |
| 422 while (grail_get_event(GrailHolder::GetInstance()->handle(), &ugEvent) == |
| 423 UGStatusSuccess) { |
| 424 switch (grail_event_get_type(ugEvent)) { |
| 425 case UGEventTypeSlice: { |
| 426 UGSlice slice; |
| 427 UGStatus status; |
| 428 status = grail_event_get_property(ugEvent, |
| 429 UGEventPropertySlice, &slice); |
| 430 if (status != UGStatusSuccess) { |
| 431 break; |
| 432 } |
| 433 |
| 434 d_->ProcessSlice(slice, |
| 435 grail_event_get_time(ugEvent), |
| 436 event, |
| 437 result); |
| 438 break; |
| 439 } |
| 440 default: |
| 441 break; |
| 442 } |
| 443 |
| 444 grail_event_unref(ugEvent); |
| 445 } |
| 446 |
| 447 return result; |
| 448 } |
| 449 |
| 450 // GestureRecognizer, static |
| 451 GestureRecognizer* GestureRecognizer::Create(RootWindow* window) { |
| 452 return new GestureRecognizerGrail(window); |
| 453 } |
| 454 |
| 455 } // namespace aura |
| 456 |
OLD | NEW |