| 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/base/events/event.h" | |
| 6 | |
| 7 #if defined(USE_X11) | |
| 8 #include <X11/Xlib.h> | |
| 9 #endif | |
| 10 | |
| 11 #include <cstring> | |
| 12 | |
| 13 #include "ui/base/keycodes/keyboard_code_conversion.h" | |
| 14 #include "ui/gfx/interpolated_transform.h" | |
| 15 #include "ui/gfx/point3.h" | |
| 16 #include "ui/gfx/transform.h" | |
| 17 | |
| 18 #if defined(USE_X11) | |
| 19 #include "ui/base/keycodes/keyboard_code_conversion_x.h" | |
| 20 #endif | |
| 21 | |
| 22 namespace { | |
| 23 | |
| 24 base::NativeEvent CopyNativeEvent(const base::NativeEvent& event) { | |
| 25 #if defined(USE_X11) | |
| 26 if (!event || event->type == GenericEvent) | |
| 27 return NULL; | |
| 28 XEvent* copy = new XEvent; | |
| 29 *copy = *event; | |
| 30 return copy; | |
| 31 #elif defined(OS_WIN) | |
| 32 return event; | |
| 33 #else | |
| 34 NOTREACHED() << | |
| 35 "Don't know how to copy base::NativeEvent for this platform"; | |
| 36 return NULL; | |
| 37 #endif | |
| 38 } | |
| 39 | |
| 40 } // namespace | |
| 41 | |
| 42 namespace ui { | |
| 43 | |
| 44 //////////////////////////////////////////////////////////////////////////////// | |
| 45 // Event | |
| 46 | |
| 47 Event::~Event() { | |
| 48 #if defined(USE_X11) | |
| 49 if (delete_native_event_) | |
| 50 delete native_event_; | |
| 51 #endif | |
| 52 } | |
| 53 | |
| 54 bool Event::HasNativeEvent() const { | |
| 55 base::NativeEvent null_event; | |
| 56 std::memset(&null_event, 0, sizeof(null_event)); | |
| 57 return !!std::memcmp(&native_event_, &null_event, sizeof(null_event)); | |
| 58 } | |
| 59 | |
| 60 Event::Event(EventType type, int flags) | |
| 61 : type_(type), | |
| 62 time_stamp_(base::Time::NowFromSystemTime() - base::Time()), | |
| 63 flags_(flags), | |
| 64 delete_native_event_(false) { | |
| 65 Init(); | |
| 66 } | |
| 67 | |
| 68 Event::Event(const base::NativeEvent& native_event, | |
| 69 EventType type, | |
| 70 int flags) | |
| 71 : type_(type), | |
| 72 time_stamp_(EventTimeFromNative(native_event)), | |
| 73 flags_(flags), | |
| 74 delete_native_event_(false) { | |
| 75 InitWithNativeEvent(native_event); | |
| 76 } | |
| 77 | |
| 78 Event::Event(const Event& copy) | |
| 79 : native_event_(::CopyNativeEvent(copy.native_event_)), | |
| 80 type_(copy.type_), | |
| 81 time_stamp_(copy.time_stamp_), | |
| 82 flags_(copy.flags_), | |
| 83 delete_native_event_(false) { | |
| 84 #if defined(USE_X11) | |
| 85 if (native_event_) | |
| 86 delete_native_event_ = true; | |
| 87 #endif | |
| 88 } | |
| 89 | |
| 90 void Event::Init() { | |
| 91 std::memset(&native_event_, 0, sizeof(native_event_)); | |
| 92 } | |
| 93 | |
| 94 void Event::InitWithNativeEvent(const base::NativeEvent& native_event) { | |
| 95 native_event_ = native_event; | |
| 96 } | |
| 97 | |
| 98 //////////////////////////////////////////////////////////////////////////////// | |
| 99 // LocatedEvent | |
| 100 | |
| 101 LocatedEvent::~LocatedEvent() { | |
| 102 } | |
| 103 | |
| 104 LocatedEvent::LocatedEvent(const base::NativeEvent& native_event) | |
| 105 : Event(native_event, | |
| 106 EventTypeFromNative(native_event), | |
| 107 EventFlagsFromNative(native_event)), | |
| 108 location_(EventLocationFromNative(native_event)), | |
| 109 root_location_(location_), | |
| 110 valid_system_location_(true), | |
| 111 system_location_(ui::EventSystemLocationFromNative(native_event)) { | |
| 112 } | |
| 113 | |
| 114 LocatedEvent::LocatedEvent(EventType type, | |
| 115 const gfx::Point& location, | |
| 116 const gfx::Point& root_location, | |
| 117 int flags) | |
| 118 : Event(type, flags), | |
| 119 location_(location), | |
| 120 root_location_(root_location), | |
| 121 valid_system_location_(false), | |
| 122 system_location_(0, 0) { | |
| 123 } | |
| 124 | |
| 125 void LocatedEvent::UpdateForRootTransform(const Transform& root_transform) { | |
| 126 // Transform has to be done at root level. | |
| 127 DCHECK_EQ(root_location_.x(), location_.x()); | |
| 128 DCHECK_EQ(root_location_.y(), location_.y()); | |
| 129 gfx::Point3f p(location_); | |
| 130 root_transform.TransformPointReverse(p); | |
| 131 root_location_ = location_ = p.AsPoint(); | |
| 132 } | |
| 133 | |
| 134 //////////////////////////////////////////////////////////////////////////////// | |
| 135 // MouseEvent | |
| 136 | |
| 137 MouseEvent::MouseEvent(const base::NativeEvent& native_event) | |
| 138 : LocatedEvent(native_event), | |
| 139 changed_button_flags_( | |
| 140 GetChangedMouseButtonFlagsFromNative(native_event)) { | |
| 141 if (type() == ET_MOUSE_PRESSED) | |
| 142 SetClickCount(GetRepeatCount(*this)); | |
| 143 } | |
| 144 | |
| 145 MouseEvent::MouseEvent(EventType type, | |
| 146 const gfx::Point& location, | |
| 147 const gfx::Point& root_location, | |
| 148 int flags) | |
| 149 : LocatedEvent(type, location, root_location, flags), | |
| 150 changed_button_flags_(0) { | |
| 151 } | |
| 152 | |
| 153 // static | |
| 154 bool MouseEvent::IsRepeatedClickEvent( | |
| 155 const MouseEvent& event1, | |
| 156 const MouseEvent& event2) { | |
| 157 // These values match the Windows defaults. | |
| 158 static const int kDoubleClickTimeMS = 500; | |
| 159 static const int kDoubleClickWidth = 4; | |
| 160 static const int kDoubleClickHeight = 4; | |
| 161 | |
| 162 if (event1.type() != ET_MOUSE_PRESSED || | |
| 163 event2.type() != ET_MOUSE_PRESSED) | |
| 164 return false; | |
| 165 | |
| 166 // Compare flags, but ignore EF_IS_DOUBLE_CLICK to allow triple clicks. | |
| 167 if ((event1.flags() & ~EF_IS_DOUBLE_CLICK) != | |
| 168 (event2.flags() & ~EF_IS_DOUBLE_CLICK)) | |
| 169 return false; | |
| 170 | |
| 171 base::TimeDelta time_difference = event2.time_stamp() - event1.time_stamp(); | |
| 172 | |
| 173 if (time_difference.InMilliseconds() > kDoubleClickTimeMS) | |
| 174 return false; | |
| 175 | |
| 176 if (abs(event2.x() - event1.x()) > kDoubleClickWidth / 2) | |
| 177 return false; | |
| 178 | |
| 179 if (abs(event2.y() - event1.y()) > kDoubleClickHeight / 2) | |
| 180 return false; | |
| 181 | |
| 182 return true; | |
| 183 } | |
| 184 | |
| 185 // static | |
| 186 int MouseEvent::GetRepeatCount(const MouseEvent& event) { | |
| 187 int click_count = 1; | |
| 188 if (last_click_event_) { | |
| 189 if (IsRepeatedClickEvent(*last_click_event_, event)) | |
| 190 click_count = last_click_event_->GetClickCount() + 1; | |
| 191 delete last_click_event_; | |
| 192 } | |
| 193 last_click_event_ = new MouseEvent(event); | |
| 194 if (click_count > 3) | |
| 195 click_count = 3; | |
| 196 last_click_event_->SetClickCount(click_count); | |
| 197 return click_count; | |
| 198 } | |
| 199 | |
| 200 // static | |
| 201 MouseEvent* MouseEvent::last_click_event_ = NULL; | |
| 202 | |
| 203 int MouseEvent::GetClickCount() const { | |
| 204 if (type() != ET_MOUSE_PRESSED) | |
| 205 return 0; | |
| 206 | |
| 207 if (flags() & EF_IS_TRIPLE_CLICK) | |
| 208 return 3; | |
| 209 else if (flags() & EF_IS_DOUBLE_CLICK) | |
| 210 return 2; | |
| 211 else | |
| 212 return 1; | |
| 213 } | |
| 214 | |
| 215 void MouseEvent::SetClickCount(int click_count) { | |
| 216 if (type() != ET_MOUSE_PRESSED) | |
| 217 return; | |
| 218 | |
| 219 DCHECK(click_count > 0); | |
| 220 DCHECK(click_count <= 3); | |
| 221 | |
| 222 int f = flags(); | |
| 223 switch (click_count) { | |
| 224 case 1: | |
| 225 f &= ~EF_IS_DOUBLE_CLICK; | |
| 226 f &= ~EF_IS_TRIPLE_CLICK; | |
| 227 break; | |
| 228 case 2: | |
| 229 f |= EF_IS_DOUBLE_CLICK; | |
| 230 f &= ~EF_IS_TRIPLE_CLICK; | |
| 231 break; | |
| 232 case 3: | |
| 233 f &= ~EF_IS_DOUBLE_CLICK; | |
| 234 f |= EF_IS_TRIPLE_CLICK; | |
| 235 break; | |
| 236 } | |
| 237 set_flags(f); | |
| 238 } | |
| 239 | |
| 240 //////////////////////////////////////////////////////////////////////////////// | |
| 241 // MouseWheelEvent | |
| 242 | |
| 243 MouseWheelEvent::MouseWheelEvent(const base::NativeEvent& native_event) | |
| 244 : MouseEvent(native_event), | |
| 245 offset_(GetMouseWheelOffset(native_event)) { | |
| 246 } | |
| 247 | |
| 248 MouseWheelEvent::MouseWheelEvent(const ScrollEvent& scroll_event) | |
| 249 : MouseEvent(scroll_event), | |
| 250 offset_(scroll_event.y_offset()) { | |
| 251 set_type(ET_MOUSEWHEEL); | |
| 252 } | |
| 253 | |
| 254 #if defined(OS_WIN) | |
| 255 // This value matches windows WHEEL_DELTA. | |
| 256 // static | |
| 257 const int MouseWheelEvent::kWheelDelta = 120; | |
| 258 #else | |
| 259 // This value matches GTK+ wheel scroll amount. | |
| 260 const int MouseWheelEvent::kWheelDelta = 53; | |
| 261 #endif | |
| 262 | |
| 263 //////////////////////////////////////////////////////////////////////////////// | |
| 264 // TouchEvent | |
| 265 | |
| 266 TouchEvent::TouchEvent(const base::NativeEvent& native_event) | |
| 267 : LocatedEvent(native_event), | |
| 268 touch_id_(GetTouchId(native_event)), | |
| 269 radius_x_(GetTouchRadiusX(native_event)), | |
| 270 radius_y_(GetTouchRadiusY(native_event)), | |
| 271 rotation_angle_(GetTouchAngle(native_event)), | |
| 272 force_(GetTouchForce(native_event)) { | |
| 273 } | |
| 274 | |
| 275 TouchEvent::TouchEvent(EventType type, | |
| 276 const gfx::Point& location, | |
| 277 int touch_id, | |
| 278 base::TimeDelta time_stamp) | |
| 279 : LocatedEvent(type, location, location, 0), | |
| 280 touch_id_(touch_id), | |
| 281 radius_x_(0.0f), | |
| 282 radius_y_(0.0f), | |
| 283 rotation_angle_(0.0f), | |
| 284 force_(0.0f) { | |
| 285 set_time_stamp(time_stamp); | |
| 286 } | |
| 287 | |
| 288 TouchEvent::~TouchEvent() { | |
| 289 } | |
| 290 | |
| 291 void TouchEvent::UpdateForRootTransform(const Transform& root_transform) { | |
| 292 LocatedEvent::UpdateForRootTransform(root_transform); | |
| 293 gfx::Point3f scale; | |
| 294 InterpolatedTransform::FactorTRS(root_transform, NULL, NULL, &scale); | |
| 295 if (scale.x()) | |
| 296 radius_x_ /= scale.x(); | |
| 297 if (scale.y()) | |
| 298 radius_y_ /= scale.y(); | |
| 299 } | |
| 300 | |
| 301 //////////////////////////////////////////////////////////////////////////////// | |
| 302 // TestTouchEvent | |
| 303 | |
| 304 TestTouchEvent::TestTouchEvent(EventType type, | |
| 305 int x, | |
| 306 int y, | |
| 307 int flags, | |
| 308 int touch_id, | |
| 309 float radius_x, | |
| 310 float radius_y, | |
| 311 float angle, | |
| 312 float force) | |
| 313 : TouchEvent(type, gfx::Point(x, y), touch_id, base::TimeDelta()) { | |
| 314 set_flags(flags); | |
| 315 set_radius(radius_x, radius_y); | |
| 316 set_rotation_angle(angle); | |
| 317 set_force(force); | |
| 318 } | |
| 319 | |
| 320 //////////////////////////////////////////////////////////////////////////////// | |
| 321 // KeyEvent | |
| 322 | |
| 323 KeyEvent::KeyEvent(const base::NativeEvent& native_event, bool is_char) | |
| 324 : Event(native_event, | |
| 325 EventTypeFromNative(native_event), | |
| 326 EventFlagsFromNative(native_event)), | |
| 327 key_code_(KeyboardCodeFromNative(native_event)), | |
| 328 is_char_(is_char), | |
| 329 character_(0), | |
| 330 unmodified_character_(0) { | |
| 331 #if defined(USE_X11) | |
| 332 NormalizeFlags(); | |
| 333 #endif | |
| 334 } | |
| 335 | |
| 336 KeyEvent::KeyEvent(EventType type, | |
| 337 KeyboardCode key_code, | |
| 338 int flags) | |
| 339 : Event(type, flags), | |
| 340 key_code_(key_code), | |
| 341 is_char_(false), | |
| 342 character_(GetCharacterFromKeyCode(key_code, flags)), | |
| 343 unmodified_character_(0) { | |
| 344 } | |
| 345 | |
| 346 uint16 KeyEvent::GetCharacter() const { | |
| 347 if (character_) | |
| 348 return character_; | |
| 349 | |
| 350 #if defined(OS_WIN) | |
| 351 return (native_event().message == WM_CHAR) ? key_code_ : | |
| 352 GetCharacterFromKeyCode(key_code_, flags()); | |
| 353 #elif defined(USE_X11) | |
| 354 if (!native_event()) | |
| 355 return GetCharacterFromKeyCode(key_code_, flags()); | |
| 356 | |
| 357 DCHECK(native_event()->type == KeyPress || | |
| 358 native_event()->type == KeyRelease); | |
| 359 | |
| 360 uint16 ch = 0; | |
| 361 if (!IsControlDown()) | |
| 362 ch = GetCharacterFromXEvent(native_event()); | |
| 363 return ch ? ch : GetCharacterFromKeyCode(key_code_, flags()); | |
| 364 #else | |
| 365 NOTIMPLEMENTED(); | |
| 366 return 0; | |
| 367 #endif | |
| 368 } | |
| 369 | |
| 370 uint16 KeyEvent::GetUnmodifiedCharacter() const { | |
| 371 if (unmodified_character_) | |
| 372 return unmodified_character_; | |
| 373 | |
| 374 #if defined(OS_WIN) | |
| 375 // Looks like there is no way to get unmodified character on Windows. | |
| 376 return (native_event().message == WM_CHAR) ? key_code_ : | |
| 377 GetCharacterFromKeyCode(key_code_, flags() & EF_SHIFT_DOWN); | |
| 378 #elif defined(USE_X11) | |
| 379 if (!native_event()) | |
| 380 return GetCharacterFromKeyCode(key_code_, flags() & EF_SHIFT_DOWN); | |
| 381 | |
| 382 DCHECK(native_event()->type == KeyPress || | |
| 383 native_event()->type == KeyRelease); | |
| 384 | |
| 385 static const unsigned int kIgnoredModifiers = ControlMask | LockMask | | |
| 386 Mod1Mask | Mod2Mask | Mod3Mask | Mod4Mask | Mod5Mask; | |
| 387 | |
| 388 XKeyEvent copy = native_event()->xkey; // bit-wise copy is safe. | |
| 389 // We can't use things like (native_event()->xkey.state & ShiftMask), as it | |
| 390 // may mask out bits used by X11 internally. | |
| 391 copy.state &= ~kIgnoredModifiers; | |
| 392 uint16 ch = GetCharacterFromXEvent(reinterpret_cast<XEvent*>(©)); | |
| 393 return ch ? ch : GetCharacterFromKeyCode(key_code_, flags() & EF_SHIFT_DOWN); | |
| 394 #else | |
| 395 NOTIMPLEMENTED(); | |
| 396 return 0; | |
| 397 #endif | |
| 398 } | |
| 399 | |
| 400 KeyEvent* KeyEvent::Copy() { | |
| 401 KeyEvent* copy = new KeyEvent(::CopyNativeEvent(native_event()), is_char()); | |
| 402 #if defined(USE_X11) | |
| 403 copy->set_delete_native_event(true); | |
| 404 #endif | |
| 405 return copy; | |
| 406 } | |
| 407 | |
| 408 void KeyEvent::NormalizeFlags() { | |
| 409 int mask = 0; | |
| 410 switch (key_code()) { | |
| 411 case ui::VKEY_CONTROL: | |
| 412 mask = ui::EF_CONTROL_DOWN; | |
| 413 break; | |
| 414 case ui::VKEY_SHIFT: | |
| 415 mask = ui::EF_SHIFT_DOWN; | |
| 416 break; | |
| 417 case ui::VKEY_MENU: | |
| 418 mask = ui::EF_ALT_DOWN; | |
| 419 break; | |
| 420 case ui::VKEY_CAPITAL: | |
| 421 mask = ui::EF_CAPS_LOCK_DOWN; | |
| 422 break; | |
| 423 default: | |
| 424 return; | |
| 425 } | |
| 426 if (type() == ui::ET_KEY_PRESSED) | |
| 427 set_flags(flags() | mask); | |
| 428 else | |
| 429 set_flags(flags() & ~mask); | |
| 430 } | |
| 431 | |
| 432 //////////////////////////////////////////////////////////////////////////////// | |
| 433 // TranslatedKeyEvent | |
| 434 | |
| 435 TranslatedKeyEvent::TranslatedKeyEvent(const base::NativeEvent& native_event, | |
| 436 bool is_char) | |
| 437 : KeyEvent(native_event, is_char) { | |
| 438 set_type(type() == ET_KEY_PRESSED ? | |
| 439 ET_TRANSLATED_KEY_PRESS : ET_TRANSLATED_KEY_RELEASE); | |
| 440 } | |
| 441 | |
| 442 TranslatedKeyEvent::TranslatedKeyEvent(bool is_press, | |
| 443 KeyboardCode key_code, | |
| 444 int flags) | |
| 445 : KeyEvent((is_press ? ET_TRANSLATED_KEY_PRESS : ET_TRANSLATED_KEY_RELEASE), | |
| 446 key_code, | |
| 447 flags) { | |
| 448 } | |
| 449 | |
| 450 void TranslatedKeyEvent::ConvertToKeyEvent() { | |
| 451 set_type(type() == ET_TRANSLATED_KEY_PRESS ? | |
| 452 ET_KEY_PRESSED : ET_KEY_RELEASED); | |
| 453 } | |
| 454 | |
| 455 //////////////////////////////////////////////////////////////////////////////// | |
| 456 // ScrollEvent | |
| 457 | |
| 458 ScrollEvent::ScrollEvent(const base::NativeEvent& native_event) | |
| 459 : MouseEvent(native_event) { | |
| 460 if (type() == ET_SCROLL) { | |
| 461 GetScrollOffsets(native_event, &x_offset_, &y_offset_); | |
| 462 double start, end; | |
| 463 GetGestureTimes(native_event, &start, &end); | |
| 464 } else if (type() == ET_SCROLL_FLING_START) { | |
| 465 bool is_cancel; | |
| 466 GetFlingData(native_event, &x_offset_, &y_offset_, &is_cancel); | |
| 467 } | |
| 468 } | |
| 469 | |
| 470 //////////////////////////////////////////////////////////////////////////////// | |
| 471 // GestureEvent | |
| 472 | |
| 473 GestureEvent::GestureEvent(EventType type, | |
| 474 int x, | |
| 475 int y, | |
| 476 int flags, | |
| 477 base::TimeDelta time_stamp, | |
| 478 const GestureEventDetails& details, | |
| 479 unsigned int touch_ids_bitfield) | |
| 480 : LocatedEvent(type, gfx::Point(x, y), gfx::Point(x, y), flags), | |
| 481 details_(details), | |
| 482 touch_ids_bitfield_(touch_ids_bitfield) { | |
| 483 set_time_stamp(time_stamp); | |
| 484 } | |
| 485 | |
| 486 GestureEvent::~GestureEvent() { | |
| 487 } | |
| 488 | |
| 489 int GestureEvent::GetLowestTouchId() const { | |
| 490 if (touch_ids_bitfield_ == 0) | |
| 491 return -1; | |
| 492 int i = -1; | |
| 493 // Find the index of the least significant 1 bit | |
| 494 while (!(1 << ++i & touch_ids_bitfield_)); | |
| 495 return i; | |
| 496 } | |
| 497 | |
| 498 } // namespace ui | |
| OLD | NEW |