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 13#include "base/logging.h" 14#include "base/memory/singleton.h" 15#include "base/message_loop/message_pump_x11.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 28namespace { 29 30// Scroll amount for each wheelscroll event. 53 is also the value used for GTK+. 31const int kWheelScrollAmount = 53; 32 33const int kMinWheelButton = 4; 34const 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. 39class 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 103bool 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 130int 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 & Mod5Mask) 141 flags |= ui::EF_ALTGR_DOWN; 142 if (state & Button1Mask) 143 flags |= ui::EF_LEFT_MOUSE_BUTTON; 144 if (state & Button2Mask) 145 flags |= ui::EF_MIDDLE_MOUSE_BUTTON; 146 if (state & Button3Mask) 147 flags |= ui::EF_RIGHT_MOUSE_BUTTON; 148 return flags; 149} 150 151// Get the event flag for the button in XButtonEvent. During a ButtonPress 152// event, |state| in XButtonEvent does not include the button that has just been 153// pressed. Instead |state| contains flags for the buttons (if any) that had 154// already been pressed before the current button, and |button| stores the most 155// current pressed button. So, if you press down left mouse button, and while 156// pressing it down, press down the right mouse button, then for the latter 157// event, |state| would have Button1Mask set but not Button3Mask, and |button| 158// would be 3. 159int GetEventFlagsForButton(int button) { 160 switch (button) { 161 case 1: 162 return ui::EF_LEFT_MOUSE_BUTTON; 163 case 2: 164 return ui::EF_MIDDLE_MOUSE_BUTTON; 165 case 3: 166 return ui::EF_RIGHT_MOUSE_BUTTON; 167 default: 168 return 0; 169 } 170} 171 172int GetButtonMaskForX2Event(XIDeviceEvent* xievent) { 173 int buttonflags = 0; 174 for (int i = 0; i < 8 * xievent->buttons.mask_len; i++) { 175 if (XIMaskIsSet(xievent->buttons.mask, i)) { 176 int button = (xievent->sourceid == xievent->deviceid) ? 177 ui::DeviceDataManager::GetInstance()->GetMappedButton(i) : i; 178 buttonflags |= GetEventFlagsForButton(button); 179 } 180 } 181 return buttonflags; 182} 183 184ui::EventType GetTouchEventType(const base::NativeEvent& native_event) { 185 XIDeviceEvent* event = 186 static_cast<XIDeviceEvent*>(native_event->xcookie.data); 187#if defined(USE_XI2_MT) 188 switch(event->evtype) { 189 case XI_TouchBegin: 190 return TouchEventIsGeneratedHack(native_event) ? ui::ET_UNKNOWN : 191 ui::ET_TOUCH_PRESSED; 192 case XI_TouchUpdate: 193 return TouchEventIsGeneratedHack(native_event) ? ui::ET_UNKNOWN : 194 ui::ET_TOUCH_MOVED; 195 case XI_TouchEnd: 196 return TouchEventIsGeneratedHack(native_event) ? ui::ET_TOUCH_CANCELLED : 197 ui::ET_TOUCH_RELEASED; 198 } 199#endif // defined(USE_XI2_MT) 200 201 DCHECK(ui::TouchFactory::GetInstance()->IsTouchDevice(event->sourceid)); 202 switch (event->evtype) { 203 case XI_ButtonPress: 204 return ui::ET_TOUCH_PRESSED; 205 case XI_ButtonRelease: 206 return ui::ET_TOUCH_RELEASED; 207 case XI_Motion: 208 // Should not convert any emulated Motion event from touch device to 209 // touch event. 210 if (!(event->flags & XIPointerEmulated) && 211 GetButtonMaskForX2Event(event)) 212 return ui::ET_TOUCH_MOVED; 213 return ui::ET_UNKNOWN; 214 default: 215 NOTREACHED(); 216 } 217 return ui::ET_UNKNOWN; 218} 219 220double GetTouchParamFromXEvent(XEvent* xev, 221 ui::DeviceDataManager::DataType val, 222 double default_value) { 223 ui::DeviceDataManager::GetInstance()->GetEventData( 224 *xev, val, &default_value); 225 return default_value; 226} 227 228Atom GetNoopEventAtom() { 229 return XInternAtom(gfx::GetXDisplay(), "noop", False); 230} 231 232} // namespace 233 234namespace ui { 235 236void UpdateDeviceList() { 237 XDisplay* display = gfx::GetXDisplay(); 238 DeviceListCacheX::GetInstance()->UpdateDeviceList(display); 239 TouchFactory::GetInstance()->UpdateDeviceList(display); 240 DeviceDataManager::GetInstance()->UpdateDeviceList(display); 241} 242 243EventType EventTypeFromNative(const base::NativeEvent& native_event) { 244 switch (native_event->type) { 245 case KeyPress: 246 return ET_KEY_PRESSED; 247 case KeyRelease: 248 return ET_KEY_RELEASED; 249 case ButtonPress: 250 if (static_cast<int>(native_event->xbutton.button) >= kMinWheelButton && 251 static_cast<int>(native_event->xbutton.button) <= kMaxWheelButton) 252 return ET_MOUSEWHEEL; 253 return ET_MOUSE_PRESSED; 254 case ButtonRelease: 255 // Drop wheel events; we should've already scrolled on the press. 256 if (static_cast<int>(native_event->xbutton.button) >= kMinWheelButton && 257 static_cast<int>(native_event->xbutton.button) <= kMaxWheelButton) 258 return ET_UNKNOWN; 259 return ET_MOUSE_RELEASED; 260 case MotionNotify: 261 if (native_event->xmotion.state & 262 (Button1Mask | Button2Mask | Button3Mask)) 263 return ET_MOUSE_DRAGGED; 264 return ET_MOUSE_MOVED; 265 case EnterNotify: 266 // The standard on Windows is to send a MouseMove event when the mouse 267 // first enters a window instead of sending a special mouse enter event. 268 // To be consistent we follow the same style. 269 return ET_MOUSE_MOVED; 270 case LeaveNotify: 271 return ET_MOUSE_EXITED; 272 case GenericEvent: { 273 TouchFactory* factory = TouchFactory::GetInstance(); 274 if (!factory->ShouldProcessXI2Event(native_event)) 275 return ET_UNKNOWN; 276 277 XIDeviceEvent* xievent = 278 static_cast<XIDeviceEvent*>(native_event->xcookie.data); 279 280 if (factory->IsTouchDevice(xievent->sourceid)) 281 return GetTouchEventType(native_event); 282 283 switch (xievent->evtype) { 284 case XI_ButtonPress: { 285 int button = EventButtonFromNative(native_event); 286 if (button >= kMinWheelButton && button <= kMaxWheelButton) 287 return ET_MOUSEWHEEL; 288 return ET_MOUSE_PRESSED; 289 } 290 case XI_ButtonRelease: { 291 int button = EventButtonFromNative(native_event); 292 // Drop wheel events; we should've already scrolled on the press. 293 if (button >= kMinWheelButton && button <= kMaxWheelButton) 294 return ET_UNKNOWN; 295 return ET_MOUSE_RELEASED; 296 } 297 case XI_Motion: { 298 bool is_cancel; 299 if (GetFlingData(native_event, NULL, NULL, NULL, NULL, &is_cancel)) { 300 return is_cancel ? ET_SCROLL_FLING_CANCEL : ET_SCROLL_FLING_START; 301 } else if (DeviceDataManager::GetInstance()->IsScrollEvent( 302 native_event)) { 303 return IsTouchpadEvent(native_event) ? ET_SCROLL : ET_MOUSEWHEEL; 304 } else if (DeviceDataManager::GetInstance()->IsCMTMetricsEvent( 305 native_event)) { 306 return ET_UMA_DATA; 307 } else if (GetButtonMaskForX2Event(xievent)) { 308 return ET_MOUSE_DRAGGED; 309 } else { 310 return ET_MOUSE_MOVED; 311 } 312 } 313 } 314 } 315 default: 316 break; 317 } 318 return ET_UNKNOWN; 319} 320 321int EventFlagsFromNative(const base::NativeEvent& native_event) { 322 switch (native_event->type) { 323 case KeyPress: 324 case KeyRelease: { 325 XModifierStateWatcher::GetInstance()->UpdateStateFromEvent(native_event); 326 return GetEventFlagsFromXState(native_event->xkey.state); 327 } 328 case ButtonPress: 329 case ButtonRelease: { 330 int flags = GetEventFlagsFromXState(native_event->xbutton.state); 331 const EventType type = EventTypeFromNative(native_event); 332 if (type == ET_MOUSE_PRESSED || type == ET_MOUSE_RELEASED) 333 flags |= GetEventFlagsForButton(native_event->xbutton.button); 334 return flags; 335 } 336 case MotionNotify: 337 return GetEventFlagsFromXState(native_event->xmotion.state); 338 case GenericEvent: { 339 XIDeviceEvent* xievent = 340 static_cast<XIDeviceEvent*>(native_event->xcookie.data); 341 342 switch (xievent->evtype) { 343#if defined(USE_XI2_MT) 344 case XI_TouchBegin: 345 case XI_TouchUpdate: 346 case XI_TouchEnd: 347 return GetButtonMaskForX2Event(xievent) | 348 GetEventFlagsFromXState(xievent->mods.effective) | 349 GetEventFlagsFromXState( 350 XModifierStateWatcher::GetInstance()->state()); 351 break; 352#endif 353 case XI_ButtonPress: 354 case XI_ButtonRelease: { 355 const bool touch = 356 TouchFactory::GetInstance()->IsTouchDevice(xievent->sourceid); 357 int flags = GetButtonMaskForX2Event(xievent) | 358 GetEventFlagsFromXState(xievent->mods.effective); 359 if (touch) { 360 flags |= GetEventFlagsFromXState( 361 XModifierStateWatcher::GetInstance()->state()); 362 } 363 364 const EventType type = EventTypeFromNative(native_event); 365 int button = EventButtonFromNative(native_event); 366 if ((type == ET_MOUSE_PRESSED || type == ET_MOUSE_RELEASED) && !touch) 367 flags |= GetEventFlagsForButton(button); 368 return flags; 369 } 370 case XI_Motion: 371 return GetButtonMaskForX2Event(xievent) | 372 GetEventFlagsFromXState(xievent->mods.effective); 373 } 374 } 375 } 376 return 0; 377} 378 379base::TimeDelta EventTimeFromNative(const base::NativeEvent& native_event) { 380 switch(native_event->type) { 381 case KeyPress: 382 case KeyRelease: 383 return base::TimeDelta::FromMilliseconds(native_event->xkey.time); 384 case ButtonPress: 385 case ButtonRelease: 386 return base::TimeDelta::FromMilliseconds(native_event->xbutton.time); 387 break; 388 case MotionNotify: 389 return base::TimeDelta::FromMilliseconds(native_event->xmotion.time); 390 break; 391 case EnterNotify: 392 case LeaveNotify: 393 return base::TimeDelta::FromMilliseconds(native_event->xcrossing.time); 394 break; 395 case GenericEvent: { 396 double start, end; 397 double touch_timestamp; 398 if (GetGestureTimes(native_event, &start, &end)) { 399 // If the driver supports gesture times, use them. 400 return base::TimeDelta::FromMicroseconds(end * 1000000); 401 } else if (DeviceDataManager::GetInstance()->GetEventData(*native_event, 402 DeviceDataManager::DT_TOUCH_RAW_TIMESTAMP, &touch_timestamp)) { 403 return base::TimeDelta::FromMicroseconds(touch_timestamp * 1000000); 404 } else { 405 XIDeviceEvent* xide = 406 static_cast<XIDeviceEvent*>(native_event->xcookie.data); 407 return base::TimeDelta::FromMilliseconds(xide->time); 408 } 409 break; 410 } 411 } 412 NOTREACHED(); 413 return base::TimeDelta(); 414} 415 416gfx::Point EventLocationFromNative(const base::NativeEvent& native_event) { 417 switch (native_event->type) { 418 case EnterNotify: 419 case LeaveNotify: 420 return gfx::Point(native_event->xcrossing.x, native_event->xcrossing.y); 421 case ButtonPress: 422 case ButtonRelease: 423 return gfx::Point(native_event->xbutton.x, native_event->xbutton.y); 424 case MotionNotify: 425 return gfx::Point(native_event->xmotion.x, native_event->xmotion.y); 426 case GenericEvent: { 427 XIDeviceEvent* xievent = 428 static_cast<XIDeviceEvent*>(native_event->xcookie.data); 429 return gfx::Point(static_cast<int>(xievent->event_x), 430 static_cast<int>(xievent->event_y)); 431 } 432 } 433 return gfx::Point(); 434} 435 436gfx::Point EventSystemLocationFromNative( 437 const base::NativeEvent& native_event) { 438 switch (native_event->type) { 439 case EnterNotify: 440 case LeaveNotify: { 441 return gfx::Point(native_event->xcrossing.x_root, 442 native_event->xcrossing.y_root); 443 } 444 case ButtonPress: 445 case ButtonRelease: { 446 return gfx::Point(native_event->xbutton.x_root, 447 native_event->xbutton.y_root); 448 } 449 case MotionNotify: { 450 return gfx::Point(native_event->xmotion.x_root, 451 native_event->xmotion.y_root); 452 } 453 case GenericEvent: { 454 XIDeviceEvent* xievent = 455 static_cast<XIDeviceEvent*>(native_event->xcookie.data); 456 return gfx::Point(xievent->root_x, xievent->root_y); 457 } 458 } 459 460 return gfx::Point(); 461} 462 463int EventButtonFromNative(const base::NativeEvent& native_event) { 464 CHECK_EQ(GenericEvent, native_event->type); 465 XIDeviceEvent* xievent = 466 static_cast<XIDeviceEvent*>(native_event->xcookie.data); 467 int button = xievent->detail; 468 469 return (xievent->sourceid == xievent->deviceid) ? 470 DeviceDataManager::GetInstance()->GetMappedButton(button) : button; 471} 472 473KeyboardCode KeyboardCodeFromNative(const base::NativeEvent& native_event) { 474 return KeyboardCodeFromXKeyEvent(native_event); 475} 476 477const char* CodeFromNative(const base::NativeEvent& native_event) { 478 return CodeFromXEvent(native_event); 479} 480 481bool IsMouseEvent(const base::NativeEvent& native_event) { 482 if (native_event->type == EnterNotify || 483 native_event->type == LeaveNotify || 484 native_event->type == ButtonPress || 485 native_event->type == ButtonRelease || 486 native_event->type == MotionNotify) 487 return true; 488 if (native_event->type == GenericEvent) { 489 XIDeviceEvent* xievent = 490 static_cast<XIDeviceEvent*>(native_event->xcookie.data); 491 return xievent->evtype == XI_ButtonPress || 492 xievent->evtype == XI_ButtonRelease || 493 xievent->evtype == XI_Motion; 494 } 495 return false; 496} 497 498int GetChangedMouseButtonFlagsFromNative( 499 const base::NativeEvent& native_event) { 500 switch (native_event->type) { 501 case ButtonPress: 502 case ButtonRelease: 503 return GetEventFlagsFromXState(native_event->xbutton.state); 504 case GenericEvent: { 505 XIDeviceEvent* xievent = 506 static_cast<XIDeviceEvent*>(native_event->xcookie.data); 507 switch (xievent->evtype) { 508 case XI_ButtonPress: 509 case XI_ButtonRelease: 510 return GetEventFlagsForButton(EventButtonFromNative(native_event)); 511 default: 512 break; 513 } 514 } 515 default: 516 break; 517 } 518 return 0; 519} 520 521gfx::Vector2d GetMouseWheelOffset(const base::NativeEvent& native_event) { 522 float x_offset, y_offset; 523 if (GetScrollOffsets( 524 native_event, &x_offset, &y_offset, NULL, NULL, NULL)) { 525 return gfx::Vector2d(static_cast<int>(x_offset), 526 static_cast<int>(y_offset)); 527 } 528 529 int button = native_event->type == GenericEvent ? 530 EventButtonFromNative(native_event) : native_event->xbutton.button; 531 532 switch (button) { 533 case 4: 534 return gfx::Vector2d(0, kWheelScrollAmount); 535 case 5: 536 return gfx::Vector2d(0, -kWheelScrollAmount); 537 default: 538 // TODO(derat): Do something for horizontal scrolls (buttons 6 and 7)? 539 return gfx::Vector2d(); 540 } 541} 542 543void ClearTouchIdIfReleased(const base::NativeEvent& xev) { 544 ui::EventType type = ui::EventTypeFromNative(xev); 545 if (type == ui::ET_TOUCH_CANCELLED || 546 type == ui::ET_TOUCH_RELEASED) { 547 ui::TouchFactory* factory = ui::TouchFactory::GetInstance(); 548 ui::DeviceDataManager* manager = ui::DeviceDataManager::GetInstance(); 549 double tracking_id; 550 if (manager->GetEventData( 551 *xev, ui::DeviceDataManager::DT_TOUCH_TRACKING_ID, &tracking_id)) { 552 factory->ReleaseSlotForTrackingID(tracking_id); 553 } 554 } 555} 556 557int GetTouchId(const base::NativeEvent& xev) { 558 double slot = 0; 559 ui::DeviceDataManager* manager = ui::DeviceDataManager::GetInstance(); 560 double tracking_id; 561 if (!manager->GetEventData( 562 *xev, ui::DeviceDataManager::DT_TOUCH_TRACKING_ID, &tracking_id)) { 563 LOG(ERROR) << "Could not get the tracking ID for the event. Using 0."; 564 } else { 565 ui::TouchFactory* factory = ui::TouchFactory::GetInstance(); 566 slot = factory->GetSlotForTrackingID(tracking_id); 567 } 568 return slot; 569} 570 571float GetTouchRadiusX(const base::NativeEvent& native_event) { 572 return GetTouchParamFromXEvent(native_event, 573 ui::DeviceDataManager::DT_TOUCH_MAJOR, 0.0) / 2.0; 574} 575 576float GetTouchRadiusY(const base::NativeEvent& native_event) { 577 return GetTouchParamFromXEvent(native_event, 578 ui::DeviceDataManager::DT_TOUCH_MINOR, 0.0) / 2.0; 579} 580 581float GetTouchAngle(const base::NativeEvent& native_event) { 582 return GetTouchParamFromXEvent(native_event, 583 ui::DeviceDataManager::DT_TOUCH_ORIENTATION, 0.0) / 2.0; 584} 585 586float GetTouchForce(const base::NativeEvent& native_event) { 587 double force = 0.0; 588 force = GetTouchParamFromXEvent(native_event, 589 ui::DeviceDataManager::DT_TOUCH_PRESSURE, 0.0); 590 unsigned int deviceid = 591 static_cast<XIDeviceEvent*>(native_event->xcookie.data)->sourceid; 592 // Force is normalized to fall into [0, 1] 593 if (!ui::DeviceDataManager::GetInstance()->NormalizeData( 594 deviceid, ui::DeviceDataManager::DT_TOUCH_PRESSURE, &force)) 595 force = 0.0; 596 return force; 597} 598 599bool GetScrollOffsets(const base::NativeEvent& native_event, 600 float* x_offset, 601 float* y_offset, 602 float* x_offset_ordinal, 603 float* y_offset_ordinal, 604 int* finger_count) { 605 if (!DeviceDataManager::GetInstance()->IsScrollEvent(native_event)) 606 return false; 607 608 // Temp values to prevent passing NULLs to DeviceDataManager. 609 float x_offset_, y_offset_; 610 float x_offset_ordinal_, y_offset_ordinal_; 611 int finger_count_; 612 if (!x_offset) 613 x_offset = &x_offset_; 614 if (!y_offset) 615 y_offset = &y_offset_; 616 if (!x_offset_ordinal) 617 x_offset_ordinal = &x_offset_ordinal_; 618 if (!y_offset_ordinal) 619 y_offset_ordinal = &y_offset_ordinal_; 620 if (!finger_count) 621 finger_count = &finger_count_; 622 623 DeviceDataManager::GetInstance()->GetScrollOffsets( 624 native_event, 625 x_offset, y_offset, 626 x_offset_ordinal, y_offset_ordinal, 627 finger_count); 628 return true; 629} 630 631bool GetFlingData(const base::NativeEvent& native_event, 632 float* vx, 633 float* vy, 634 float* vx_ordinal, 635 float* vy_ordinal, 636 bool* is_cancel) { 637 if (!DeviceDataManager::GetInstance()->IsFlingEvent(native_event)) 638 return false; 639 640 float vx_, vy_; 641 float vx_ordinal_, vy_ordinal_; 642 bool is_cancel_; 643 if (!vx) 644 vx = &vx_; 645 if (!vy) 646 vy = &vy_; 647 if (!vx_ordinal) 648 vx_ordinal = &vx_ordinal_; 649 if (!vy_ordinal) 650 vy_ordinal = &vy_ordinal_; 651 if (!is_cancel) 652 is_cancel = &is_cancel_; 653 654 DeviceDataManager::GetInstance()->GetFlingData( 655 native_event, vx, vy, vx_ordinal, vy_ordinal, is_cancel); 656 return true; 657} 658 659bool GetGestureTimes(const base::NativeEvent& native_event, 660 double* start_time, 661 double* end_time) { 662 if (!DeviceDataManager::GetInstance()->HasGestureTimes(native_event)) 663 return false; 664 665 double start_time_, end_time_; 666 if (!start_time) 667 start_time = &start_time_; 668 if (!end_time) 669 end_time = &end_time_; 670 671 DeviceDataManager::GetInstance()->GetGestureTimes( 672 native_event, start_time, end_time); 673 return true; 674} 675 676void SetNaturalScroll(bool enabled) { 677 DeviceDataManager::GetInstance()->set_natural_scroll_enabled(enabled); 678} 679 680bool IsNaturalScrollEnabled() { 681 return DeviceDataManager::GetInstance()->natural_scroll_enabled(); 682} 683 684bool IsTouchpadEvent(const base::NativeEvent& event) { 685 return DeviceDataManager::GetInstance()->IsTouchpadXInputEvent(event); 686} 687 688bool IsNoopEvent(const base::NativeEvent& event) { 689 return (event->type == ClientMessage && 690 event->xclient.message_type == GetNoopEventAtom()); 691} 692 693base::NativeEvent CreateNoopEvent() { 694 static XEvent* noop = NULL; 695 if (!noop) { 696 noop = new XEvent(); 697 memset(noop, 0, sizeof(XEvent)); 698 noop->xclient.type = ClientMessage; 699 noop->xclient.window = None; 700 noop->xclient.format = 8; 701 DCHECK(!noop->xclient.display); 702 } 703 // Make sure we use atom from current xdisplay, which may 704 // change during the test. 705 noop->xclient.message_type = GetNoopEventAtom(); 706 return noop; 707} 708 709} // namespace ui 710