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/events/event_constants.h" 6 7 #include <cmath> 8 #include <string.h> 9 #include <X11/extensions/XInput.h> 10 #include <X11/extensions/XInput2.h> 11 #include <X11/Xlib.h> 12 #include <X11/Xutil.h> 13 14 #include "base/logging.h" 15 #include "base/memory/singleton.h" 16 #include "ui/events/event_utils.h" 17 #include "ui/events/keycodes/keyboard_code_conversion_x.h" 18 #include "ui/events/x/device_data_manager.h" 19 #include "ui/events/x/device_list_cache_x.h" 20 #include "ui/events/x/touch_factory_x11.h" 21 #include "ui/gfx/display.h" 22 #include "ui/gfx/point.h" 23 #include "ui/gfx/rect.h" 24 #include "ui/gfx/screen.h" 25 #include "ui/gfx/x/x11_atom_cache.h" 26 #include "ui/gfx/x/x11_types.h" 27 28 namespace { 29 30 // Scroll amount for each wheelscroll event. 53 is also the value used for GTK+. 31 const int kWheelScrollAmount = 53; 32 33 const int kMinWheelButton = 4; 34 const int kMaxWheelButton = 7; 35 36 // A class to track current modifier state on master device. Only track ctrl, 37 // alt, shift and caps lock keys currently. The tracked state can then be used 38 // by floating device. 39 class XModifierStateWatcher{ 40 public: 41 static XModifierStateWatcher* GetInstance() { 42 return Singleton<XModifierStateWatcher>::get(); 43 } 44 45 void UpdateStateFromEvent(const base::NativeEvent& native_event) { 46 // Floating device can't access the modifer state from master device. 47 // We need to track the states of modifier keys in a singleton for 48 // floating devices such as touch screen. Issue 106426 is one example 49 // of why we need the modifier states for floating device. 50 state_ = native_event->xkey.state; 51 // master_state is the state before key press. We need to track the 52 // state after key press for floating device. Currently only ctrl, 53 // shift, alt and caps lock keys are tracked. 54 ui::KeyboardCode keyboard_code = ui::KeyboardCodeFromNative(native_event); 55 unsigned int mask = 0; 56 57 switch (keyboard_code) { 58 case ui::VKEY_CONTROL: { 59 mask = ControlMask; 60 break; 61 } 62 case ui::VKEY_SHIFT: { 63 mask = ShiftMask; 64 break; 65 } 66 case ui::VKEY_MENU: { 67 mask = Mod1Mask; 68 break; 69 } 70 case ui::VKEY_CAPITAL: { 71 mask = LockMask; 72 break; 73 } 74 default: 75 break; 76 } 77 78 if (native_event->type == KeyPress) 79 state_ |= mask; 80 else 81 state_ &= ~mask; 82 } 83 84 // Returns the current modifer state in master device. It only contains the 85 // state of ctrl, shift, alt and caps lock keys. 86 unsigned int state() { return state_; } 87 88 private: 89 friend struct DefaultSingletonTraits<XModifierStateWatcher>; 90 91 XModifierStateWatcher() : state_(0) { } 92 93 unsigned int state_; 94 95 DISALLOW_COPY_AND_ASSIGN(XModifierStateWatcher); 96 }; 97 98 #if defined(USE_XI2_MT) 99 // Detects if a touch event is a driver-generated 'special event'. 100 // A 'special event' is a touch event with maximum radius and pressure at 101 // location (0, 0). 102 // This needs to be done in a cleaner way: http://crbug.com/169256 103 bool TouchEventIsGeneratedHack(const base::NativeEvent& native_event) { 104 XIDeviceEvent* event = 105 static_cast<XIDeviceEvent*>(native_event->xcookie.data); 106 CHECK(event->evtype == XI_TouchBegin || 107 event->evtype == XI_TouchUpdate || 108 event->evtype == XI_TouchEnd); 109 110 // Force is normalized to [0, 1]. 111 if (ui::GetTouchForce(native_event) < 1.0f) 112 return false; 113 114 if (ui::EventLocationFromNative(native_event) != gfx::Point()) 115 return false; 116 117 // Radius is in pixels, and the valuator is the diameter in pixels. 118 double radius = ui::GetTouchRadiusX(native_event), min, max; 119 unsigned int deviceid = 120 static_cast<XIDeviceEvent*>(native_event->xcookie.data)->sourceid; 121 if (!ui::DeviceDataManager::GetInstance()->GetDataRange( 122 deviceid, ui::DeviceDataManager::DT_TOUCH_MAJOR, &min, &max)) { 123 return false; 124 } 125 126 return radius * 2 == max; 127 } 128 #endif 129 130 int GetEventFlagsFromXState(unsigned int state) { 131 int flags = 0; 132 if (state & ControlMask) 133 flags |= ui::EF_CONTROL_DOWN; 134 if (state & ShiftMask) 135 flags |= ui::EF_SHIFT_DOWN; 136 if (state & Mod1Mask) 137 flags |= ui::EF_ALT_DOWN; 138 if (state & LockMask) 139 flags |= ui::EF_CAPS_LOCK_DOWN; 140 if (state & Mod3Mask) 141 flags |= ui::EF_MOD3_DOWN; 142 if (state & Mod4Mask) 143 flags |= ui::EF_COMMAND_DOWN; 144 if (state & Mod5Mask) 145 flags |= ui::EF_ALTGR_DOWN; 146 if (state & Button1Mask) 147 flags |= ui::EF_LEFT_MOUSE_BUTTON; 148 if (state & Button2Mask) 149 flags |= ui::EF_MIDDLE_MOUSE_BUTTON; 150 if (state & Button3Mask) 151 flags |= ui::EF_RIGHT_MOUSE_BUTTON; 152 return flags; 153 } 154 155 int GetEventFlagsFromXKeyEvent(XEvent* xevent) { 156 DCHECK(xevent->type == KeyPress || xevent->type == KeyRelease); 157 158 #if defined(OS_CHROMEOS) 159 const int ime_fabricated_flag = 0; 160 #else 161 // XIM fabricates key events for the character compositions by XK_Multi_key. 162 // For example, when a user hits XK_Multi_key, XK_apostrophe, and XK_e in 163 // order to input "", then XIM generates a key event with keycode=0 and 164 // state=0 for the composition, and the sequence of X11 key events will be 165 // XK_Multi_key, XK_apostrophe, **NoSymbol**, and XK_e. If the user used 166 // shift key and/or caps lock key, state can be ShiftMask, LockMask or both. 167 // 168 // We have to send these fabricated key events to XIM so it can correctly 169 // handle the character compositions. 170 const unsigned int shift_lock_mask = ShiftMask | LockMask; 171 const bool fabricated_by_xim = 172 xevent->xkey.keycode == 0 && 173 (xevent->xkey.state & ~shift_lock_mask) == 0; 174 const int ime_fabricated_flag = 175 fabricated_by_xim ? ui::EF_IME_FABRICATED_KEY : 0; 176 #endif 177 178 return GetEventFlagsFromXState(xevent->xkey.state) | 179 (IsKeypadKey(XLookupKeysym(&xevent->xkey, 0)) ? ui::EF_NUMPAD_KEY : 0) | 180 (IsFunctionKey(XLookupKeysym(&xevent->xkey, 0)) ? 181 ui::EF_FUNCTION_KEY : 0) | 182 ime_fabricated_flag; 183 } 184 185 // Get the event flag for the button in XButtonEvent. During a ButtonPress 186 // event, |state| in XButtonEvent does not include the button that has just been 187 // pressed. Instead |state| contains flags for the buttons (if any) that had 188 // already been pressed before the current button, and |button| stores the most 189 // current pressed button. So, if you press down left mouse button, and while 190 // pressing it down, press down the right mouse button, then for the latter 191 // event, |state| would have Button1Mask set but not Button3Mask, and |button| 192 // would be 3. 193 int GetEventFlagsForButton(int button) { 194 switch (button) { 195 case 1: 196 return ui::EF_LEFT_MOUSE_BUTTON; 197 case 2: 198 return ui::EF_MIDDLE_MOUSE_BUTTON; 199 case 3: 200 return ui::EF_RIGHT_MOUSE_BUTTON; 201 default: 202 return 0; 203 } 204 } 205 206 int GetButtonMaskForX2Event(XIDeviceEvent* xievent) { 207 int buttonflags = 0; 208 for (int i = 0; i < 8 * xievent->buttons.mask_len; i++) { 209 if (XIMaskIsSet(xievent->buttons.mask, i)) { 210 int button = (xievent->sourceid == xievent->deviceid) ? 211 ui::DeviceDataManager::GetInstance()->GetMappedButton(i) : i; 212 buttonflags |= GetEventFlagsForButton(button); 213 } 214 } 215 return buttonflags; 216 } 217 218 ui::EventType GetTouchEventType(const base::NativeEvent& native_event) { 219 XIDeviceEvent* event = 220 static_cast<XIDeviceEvent*>(native_event->xcookie.data); 221 #if defined(USE_XI2_MT) 222 switch(event->evtype) { 223 case XI_TouchBegin: 224 return TouchEventIsGeneratedHack(native_event) ? ui::ET_UNKNOWN : 225 ui::ET_TOUCH_PRESSED; 226 case XI_TouchUpdate: 227 return TouchEventIsGeneratedHack(native_event) ? ui::ET_UNKNOWN : 228 ui::ET_TOUCH_MOVED; 229 case XI_TouchEnd: 230 return TouchEventIsGeneratedHack(native_event) ? ui::ET_TOUCH_CANCELLED : 231 ui::ET_TOUCH_RELEASED; 232 } 233 #endif // defined(USE_XI2_MT) 234 235 DCHECK(ui::TouchFactory::GetInstance()->IsTouchDevice(event->sourceid)); 236 switch (event->evtype) { 237 case XI_ButtonPress: 238 return ui::ET_TOUCH_PRESSED; 239 case XI_ButtonRelease: 240 return ui::ET_TOUCH_RELEASED; 241 case XI_Motion: 242 // Should not convert any emulated Motion event from touch device to 243 // touch event. 244 if (!(event->flags & XIPointerEmulated) && 245 GetButtonMaskForX2Event(event)) 246 return ui::ET_TOUCH_MOVED; 247 return ui::ET_UNKNOWN; 248 default: 249 NOTREACHED(); 250 } 251 return ui::ET_UNKNOWN; 252 } 253 254 double GetTouchParamFromXEvent(XEvent* xev, 255 ui::DeviceDataManager::DataType val, 256 double default_value) { 257 ui::DeviceDataManager::GetInstance()->GetEventData( 258 *xev, val, &default_value); 259 return default_value; 260 } 261 262 } // namespace 263 264 namespace ui { 265 266 void UpdateDeviceList() { 267 XDisplay* display = gfx::GetXDisplay(); 268 DeviceListCacheX::GetInstance()->UpdateDeviceList(display); 269 TouchFactory::GetInstance()->UpdateDeviceList(display); 270 DeviceDataManager::GetInstance()->UpdateDeviceList(display); 271 } 272 273 EventType EventTypeFromNative(const base::NativeEvent& native_event) { 274 switch (native_event->type) { 275 case KeyPress: 276 return ET_KEY_PRESSED; 277 case KeyRelease: 278 return ET_KEY_RELEASED; 279 case ButtonPress: 280 if (static_cast<int>(native_event->xbutton.button) >= kMinWheelButton && 281 static_cast<int>(native_event->xbutton.button) <= kMaxWheelButton) 282 return ET_MOUSEWHEEL; 283 return ET_MOUSE_PRESSED; 284 case ButtonRelease: 285 // Drop wheel events; we should've already scrolled on the press. 286 if (static_cast<int>(native_event->xbutton.button) >= kMinWheelButton && 287 static_cast<int>(native_event->xbutton.button) <= kMaxWheelButton) 288 return ET_UNKNOWN; 289 return ET_MOUSE_RELEASED; 290 case MotionNotify: 291 if (native_event->xmotion.state & 292 (Button1Mask | Button2Mask | Button3Mask)) 293 return ET_MOUSE_DRAGGED; 294 return ET_MOUSE_MOVED; 295 case EnterNotify: 296 // The standard on Windows is to send a MouseMove event when the mouse 297 // first enters a window instead of sending a special mouse enter event. 298 // To be consistent we follow the same style. 299 return ET_MOUSE_MOVED; 300 case LeaveNotify: 301 return ET_MOUSE_EXITED; 302 case GenericEvent: { 303 TouchFactory* factory = TouchFactory::GetInstance(); 304 if (!factory->ShouldProcessXI2Event(native_event)) 305 return ET_UNKNOWN; 306 307 XIDeviceEvent* xievent = 308 static_cast<XIDeviceEvent*>(native_event->xcookie.data); 309 310 // This check works only for master and floating slave devices. That is 311 // why it is necessary to check for the XI_Touch* events in the following 312 // switch statement to account for attached-slave touchscreens. 313 if (factory->IsTouchDevice(xievent->sourceid)) 314 return GetTouchEventType(native_event); 315 316 switch (xievent->evtype) { 317 case XI_TouchBegin: 318 return ui::ET_TOUCH_PRESSED; 319 case XI_TouchUpdate: 320 return ui::ET_TOUCH_MOVED; 321 case XI_TouchEnd: 322 return ui::ET_TOUCH_RELEASED; 323 case XI_ButtonPress: { 324 int button = EventButtonFromNative(native_event); 325 if (button >= kMinWheelButton && button <= kMaxWheelButton) 326 return ET_MOUSEWHEEL; 327 return ET_MOUSE_PRESSED; 328 } 329 case XI_ButtonRelease: { 330 int button = EventButtonFromNative(native_event); 331 // Drop wheel events; we should've already scrolled on the press. 332 if (button >= kMinWheelButton && button <= kMaxWheelButton) 333 return ET_UNKNOWN; 334 return ET_MOUSE_RELEASED; 335 } 336 case XI_Motion: { 337 bool is_cancel; 338 if (GetFlingData(native_event, NULL, NULL, NULL, NULL, &is_cancel)) { 339 return is_cancel ? ET_SCROLL_FLING_CANCEL : ET_SCROLL_FLING_START; 340 } else if (DeviceDataManager::GetInstance()->IsScrollEvent( 341 native_event)) { 342 return IsTouchpadEvent(native_event) ? ET_SCROLL : ET_MOUSEWHEEL; 343 } else if (DeviceDataManager::GetInstance()->IsCMTMetricsEvent( 344 native_event)) { 345 return ET_UMA_DATA; 346 } else if (GetButtonMaskForX2Event(xievent)) { 347 return ET_MOUSE_DRAGGED; 348 } else { 349 return ET_MOUSE_MOVED; 350 } 351 } 352 } 353 } 354 default: 355 break; 356 } 357 return ET_UNKNOWN; 358 } 359 360 int EventFlagsFromNative(const base::NativeEvent& native_event) { 361 switch (native_event->type) { 362 case KeyPress: 363 case KeyRelease: { 364 XModifierStateWatcher::GetInstance()->UpdateStateFromEvent(native_event); 365 return GetEventFlagsFromXKeyEvent(native_event); 366 } 367 case ButtonPress: 368 case ButtonRelease: { 369 int flags = GetEventFlagsFromXState(native_event->xbutton.state); 370 const EventType type = EventTypeFromNative(native_event); 371 if (type == ET_MOUSE_PRESSED || type == ET_MOUSE_RELEASED) 372 flags |= GetEventFlagsForButton(native_event->xbutton.button); 373 return flags; 374 } 375 case EnterNotify: 376 case LeaveNotify: 377 return GetEventFlagsFromXState(native_event->xcrossing.state); 378 case MotionNotify: 379 return GetEventFlagsFromXState(native_event->xmotion.state); 380 case GenericEvent: { 381 XIDeviceEvent* xievent = 382 static_cast<XIDeviceEvent*>(native_event->xcookie.data); 383 384 switch (xievent->evtype) { 385 #if defined(USE_XI2_MT) 386 case XI_TouchBegin: 387 case XI_TouchUpdate: 388 case XI_TouchEnd: 389 return GetButtonMaskForX2Event(xievent) | 390 GetEventFlagsFromXState(xievent->mods.effective) | 391 GetEventFlagsFromXState( 392 XModifierStateWatcher::GetInstance()->state()); 393 break; 394 #endif 395 case XI_ButtonPress: 396 case XI_ButtonRelease: { 397 const bool touch = 398 TouchFactory::GetInstance()->IsTouchDevice(xievent->sourceid); 399 int flags = GetButtonMaskForX2Event(xievent) | 400 GetEventFlagsFromXState(xievent->mods.effective); 401 if (touch) { 402 flags |= GetEventFlagsFromXState( 403 XModifierStateWatcher::GetInstance()->state()); 404 } 405 406 const EventType type = EventTypeFromNative(native_event); 407 int button = EventButtonFromNative(native_event); 408 if ((type == ET_MOUSE_PRESSED || type == ET_MOUSE_RELEASED) && !touch) 409 flags |= GetEventFlagsForButton(button); 410 return flags; 411 } 412 case XI_Motion: 413 return GetButtonMaskForX2Event(xievent) | 414 GetEventFlagsFromXState(xievent->mods.effective); 415 } 416 } 417 } 418 return 0; 419 } 420 421 base::TimeDelta EventTimeFromNative(const base::NativeEvent& native_event) { 422 switch(native_event->type) { 423 case KeyPress: 424 case KeyRelease: 425 return base::TimeDelta::FromMilliseconds(native_event->xkey.time); 426 case ButtonPress: 427 case ButtonRelease: 428 return base::TimeDelta::FromMilliseconds(native_event->xbutton.time); 429 break; 430 case MotionNotify: 431 return base::TimeDelta::FromMilliseconds(native_event->xmotion.time); 432 break; 433 case EnterNotify: 434 case LeaveNotify: 435 return base::TimeDelta::FromMilliseconds(native_event->xcrossing.time); 436 break; 437 case GenericEvent: { 438 double start, end; 439 double touch_timestamp; 440 if (GetGestureTimes(native_event, &start, &end)) { 441 // If the driver supports gesture times, use them. 442 return base::TimeDelta::FromMicroseconds(end * 1000000); 443 } else if (DeviceDataManager::GetInstance()->GetEventData(*native_event, 444 DeviceDataManager::DT_TOUCH_RAW_TIMESTAMP, &touch_timestamp)) { 445 return base::TimeDelta::FromMicroseconds(touch_timestamp * 1000000); 446 } else { 447 XIDeviceEvent* xide = 448 static_cast<XIDeviceEvent*>(native_event->xcookie.data); 449 return base::TimeDelta::FromMilliseconds(xide->time); 450 } 451 break; 452 } 453 } 454 NOTREACHED(); 455 return base::TimeDelta(); 456 } 457 458 gfx::Point EventLocationFromNative(const base::NativeEvent& native_event) { 459 switch (native_event->type) { 460 case EnterNotify: 461 case LeaveNotify: 462 return gfx::Point(native_event->xcrossing.x, native_event->xcrossing.y); 463 case ButtonPress: 464 case ButtonRelease: 465 return gfx::Point(native_event->xbutton.x, native_event->xbutton.y); 466 case MotionNotify: 467 return gfx::Point(native_event->xmotion.x, native_event->xmotion.y); 468 case GenericEvent: { 469 XIDeviceEvent* xievent = 470 static_cast<XIDeviceEvent*>(native_event->xcookie.data); 471 float x = xievent->event_x; 472 float y = xievent->event_y; 473 #if defined(OS_CHROMEOS) 474 switch (xievent->evtype) { 475 case XI_TouchBegin: 476 case XI_TouchUpdate: 477 case XI_TouchEnd: 478 ui::DeviceDataManager::GetInstance()->ApplyTouchTransformer( 479 xievent->deviceid, &x, &y); 480 break; 481 default: 482 break; 483 } 484 #endif // defined(OS_CHROMEOS) 485 return gfx::Point(static_cast<int>(x), static_cast<int>(y)); 486 } 487 } 488 return gfx::Point(); 489 } 490 491 gfx::Point EventSystemLocationFromNative( 492 const base::NativeEvent& native_event) { 493 switch (native_event->type) { 494 case EnterNotify: 495 case LeaveNotify: { 496 return gfx::Point(native_event->xcrossing.x_root, 497 native_event->xcrossing.y_root); 498 } 499 case ButtonPress: 500 case ButtonRelease: { 501 return gfx::Point(native_event->xbutton.x_root, 502 native_event->xbutton.y_root); 503 } 504 case MotionNotify: { 505 return gfx::Point(native_event->xmotion.x_root, 506 native_event->xmotion.y_root); 507 } 508 case GenericEvent: { 509 XIDeviceEvent* xievent = 510 static_cast<XIDeviceEvent*>(native_event->xcookie.data); 511 return gfx::Point(xievent->root_x, xievent->root_y); 512 } 513 } 514 515 return gfx::Point(); 516 } 517 518 int EventButtonFromNative(const base::NativeEvent& native_event) { 519 CHECK_EQ(GenericEvent, native_event->type); 520 XIDeviceEvent* xievent = 521 static_cast<XIDeviceEvent*>(native_event->xcookie.data); 522 int button = xievent->detail; 523 524 return (xievent->sourceid == xievent->deviceid) ? 525 DeviceDataManager::GetInstance()->GetMappedButton(button) : button; 526 } 527 528 KeyboardCode KeyboardCodeFromNative(const base::NativeEvent& native_event) { 529 return KeyboardCodeFromXKeyEvent(native_event); 530 } 531 532 const char* CodeFromNative(const base::NativeEvent& native_event) { 533 return CodeFromXEvent(native_event); 534 } 535 536 uint32 PlatformKeycodeFromNative(const base::NativeEvent& native_event) { 537 KeySym keysym; 538 XLookupString(&native_event->xkey, NULL, 0, &keysym, NULL); 539 return keysym; 540 } 541 542 int GetChangedMouseButtonFlagsFromNative( 543 const base::NativeEvent& native_event) { 544 switch (native_event->type) { 545 case ButtonPress: 546 case ButtonRelease: 547 return GetEventFlagsFromXState(native_event->xbutton.state); 548 case GenericEvent: { 549 XIDeviceEvent* xievent = 550 static_cast<XIDeviceEvent*>(native_event->xcookie.data); 551 switch (xievent->evtype) { 552 case XI_ButtonPress: 553 case XI_ButtonRelease: 554 return GetEventFlagsForButton(EventButtonFromNative(native_event)); 555 default: 556 break; 557 } 558 } 559 default: 560 break; 561 } 562 return 0; 563 } 564 565 gfx::Vector2d GetMouseWheelOffset(const base::NativeEvent& native_event) { 566 float x_offset, y_offset; 567 if (GetScrollOffsets( 568 native_event, &x_offset, &y_offset, NULL, NULL, NULL)) { 569 return gfx::Vector2d(static_cast<int>(x_offset), 570 static_cast<int>(y_offset)); 571 } 572 573 int button = native_event->type == GenericEvent ? 574 EventButtonFromNative(native_event) : native_event->xbutton.button; 575 576 switch (button) { 577 case 4: 578 return gfx::Vector2d(0, kWheelScrollAmount); 579 case 5: 580 return gfx::Vector2d(0, -kWheelScrollAmount); 581 case 6: 582 return gfx::Vector2d(kWheelScrollAmount, 0); 583 case 7: 584 return gfx::Vector2d(-kWheelScrollAmount, 0); 585 default: 586 return gfx::Vector2d(); 587 } 588 } 589 590 base::NativeEvent CopyNativeEvent(const base::NativeEvent& event) { 591 if (!event || event->type == GenericEvent) 592 return NULL; 593 XEvent* copy = new XEvent; 594 *copy = *event; 595 return copy; 596 } 597 598 void ReleaseCopiedNativeEvent(const base::NativeEvent& event) { 599 delete event; 600 } 601 602 void ClearTouchIdIfReleased(const base::NativeEvent& xev) { 603 ui::EventType type = ui::EventTypeFromNative(xev); 604 if (type == ui::ET_TOUCH_CANCELLED || 605 type == ui::ET_TOUCH_RELEASED) { 606 ui::TouchFactory* factory = ui::TouchFactory::GetInstance(); 607 ui::DeviceDataManager* manager = ui::DeviceDataManager::GetInstance(); 608 double tracking_id; 609 if (manager->GetEventData( 610 *xev, ui::DeviceDataManager::DT_TOUCH_TRACKING_ID, &tracking_id)) { 611 factory->ReleaseSlotForTrackingID(tracking_id); 612 } 613 } 614 } 615 616 int GetTouchId(const base::NativeEvent& xev) { 617 double slot = 0; 618 ui::DeviceDataManager* manager = ui::DeviceDataManager::GetInstance(); 619 double tracking_id; 620 if (!manager->GetEventData( 621 *xev, ui::DeviceDataManager::DT_TOUCH_TRACKING_ID, &tracking_id)) { 622 LOG(ERROR) << "Could not get the tracking ID for the event. Using 0."; 623 } else { 624 ui::TouchFactory* factory = ui::TouchFactory::GetInstance(); 625 slot = factory->GetSlotForTrackingID(tracking_id); 626 } 627 return slot; 628 } 629 630 float GetTouchRadiusX(const base::NativeEvent& native_event) { 631 return GetTouchParamFromXEvent(native_event, 632 ui::DeviceDataManager::DT_TOUCH_MAJOR, 0.0) / 2.0; 633 } 634 635 float GetTouchRadiusY(const base::NativeEvent& native_event) { 636 return GetTouchParamFromXEvent(native_event, 637 ui::DeviceDataManager::DT_TOUCH_MINOR, 0.0) / 2.0; 638 } 639 640 float GetTouchAngle(const base::NativeEvent& native_event) { 641 return GetTouchParamFromXEvent(native_event, 642 ui::DeviceDataManager::DT_TOUCH_ORIENTATION, 0.0) / 2.0; 643 } 644 645 float GetTouchForce(const base::NativeEvent& native_event) { 646 double force = 0.0; 647 force = GetTouchParamFromXEvent(native_event, 648 ui::DeviceDataManager::DT_TOUCH_PRESSURE, 0.0); 649 unsigned int deviceid = 650 static_cast<XIDeviceEvent*>(native_event->xcookie.data)->sourceid; 651 // Force is normalized to fall into [0, 1] 652 if (!ui::DeviceDataManager::GetInstance()->NormalizeData( 653 deviceid, ui::DeviceDataManager::DT_TOUCH_PRESSURE, &force)) 654 force = 0.0; 655 return force; 656 } 657 658 bool GetScrollOffsets(const base::NativeEvent& native_event, 659 float* x_offset, 660 float* y_offset, 661 float* x_offset_ordinal, 662 float* y_offset_ordinal, 663 int* finger_count) { 664 if (!DeviceDataManager::GetInstance()->IsScrollEvent(native_event)) 665 return false; 666 667 // Temp values to prevent passing NULLs to DeviceDataManager. 668 float x_offset_, y_offset_; 669 float x_offset_ordinal_, y_offset_ordinal_; 670 int finger_count_; 671 if (!x_offset) 672 x_offset = &x_offset_; 673 if (!y_offset) 674 y_offset = &y_offset_; 675 if (!x_offset_ordinal) 676 x_offset_ordinal = &x_offset_ordinal_; 677 if (!y_offset_ordinal) 678 y_offset_ordinal = &y_offset_ordinal_; 679 if (!finger_count) 680 finger_count = &finger_count_; 681 682 DeviceDataManager::GetInstance()->GetScrollOffsets( 683 native_event, 684 x_offset, y_offset, 685 x_offset_ordinal, y_offset_ordinal, 686 finger_count); 687 return true; 688 } 689 690 bool GetFlingData(const base::NativeEvent& native_event, 691 float* vx, 692 float* vy, 693 float* vx_ordinal, 694 float* vy_ordinal, 695 bool* is_cancel) { 696 if (!DeviceDataManager::GetInstance()->IsFlingEvent(native_event)) 697 return false; 698 699 float vx_, vy_; 700 float vx_ordinal_, vy_ordinal_; 701 bool is_cancel_; 702 if (!vx) 703 vx = &vx_; 704 if (!vy) 705 vy = &vy_; 706 if (!vx_ordinal) 707 vx_ordinal = &vx_ordinal_; 708 if (!vy_ordinal) 709 vy_ordinal = &vy_ordinal_; 710 if (!is_cancel) 711 is_cancel = &is_cancel_; 712 713 DeviceDataManager::GetInstance()->GetFlingData( 714 native_event, vx, vy, vx_ordinal, vy_ordinal, is_cancel); 715 return true; 716 } 717 718 bool GetGestureTimes(const base::NativeEvent& native_event, 719 double* start_time, 720 double* end_time) { 721 if (!DeviceDataManager::GetInstance()->HasGestureTimes(native_event)) 722 return false; 723 724 double start_time_, end_time_; 725 if (!start_time) 726 start_time = &start_time_; 727 if (!end_time) 728 end_time = &end_time_; 729 730 DeviceDataManager::GetInstance()->GetGestureTimes( 731 native_event, start_time, end_time); 732 return true; 733 } 734 735 bool IsTouchpadEvent(const base::NativeEvent& event) { 736 return DeviceDataManager::GetInstance()->IsTouchpadXInputEvent(event); 737 } 738 739 } // namespace ui 740