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