OLD | NEW |
(Empty) | |
| 1 // Copyright 2015 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_builder.h" |
| 6 |
| 7 #if defined(USE_X11) |
| 8 #include <X11/extensions/XInput2.h> |
| 9 #include <X11/Xlib.h> |
| 10 #include <X11/keysym.h> |
| 11 #endif |
| 12 |
| 13 #include "ui/events/event.h" |
| 14 #include "ui/events/event_utils.h" |
| 15 |
| 16 namespace ui { |
| 17 namespace { |
| 18 |
| 19 bool X11EventHasNonStandardState(const base::NativeEvent& event) { |
| 20 #if defined(USE_X11) |
| 21 const unsigned int kAllStateMask = |
| 22 Button1Mask | Button2Mask | Button3Mask | Button4Mask | Button5Mask | |
| 23 Mod1Mask | Mod2Mask | Mod3Mask | Mod4Mask | Mod5Mask | ShiftMask | |
| 24 LockMask | ControlMask | AnyModifier; |
| 25 return event && (event->xkey.state & ~kAllStateMask) != 0; |
| 26 #else |
| 27 return false; |
| 28 #endif |
| 29 } |
| 30 |
| 31 bool IsX11SendEventTrue(const base::NativeEvent& event) { |
| 32 #if defined(USE_X11) |
| 33 return event && event->xany.send_event; |
| 34 #else |
| 35 return false; |
| 36 #endif |
| 37 } |
| 38 |
| 39 KeyEvent* last_key_event_ = nullptr; |
| 40 MouseEvent* last_click_event_ = nullptr; |
| 41 |
| 42 // We can create a MouseEvent for a native event more than once. We set this |
| 43 // to true when the next event either has a different timestamp or we see a |
| 44 // release signalling that the press (click) event was completed. |
| 45 bool last_click_complete_ = false; |
| 46 |
| 47 bool IsRepeated(const base::NativeEvent& native_event, const KeyEvent& event) { |
| 48 // A safe guard in case if there were continous key pressed events that are |
| 49 // not auto repeat. |
| 50 const int kMaxAutoRepeatTimeMs = 2000; |
| 51 // Ignore key events that have non standard state masks as it may be |
| 52 // reposted by an IME. IBUS-GTK uses this field to detect the |
| 53 // re-posted event for example. crbug.com/385873. |
| 54 if (X11EventHasNonStandardState(native_event)) |
| 55 return false; |
| 56 if (event.is_char()) |
| 57 return false; |
| 58 if (event.type() == ui::ET_KEY_RELEASED) { |
| 59 delete last_key_event_; |
| 60 last_key_event_ = NULL; |
| 61 return false; |
| 62 } |
| 63 CHECK_EQ(ui::ET_KEY_PRESSED, event.type()); |
| 64 if (!last_key_event_) { |
| 65 last_key_event_ = new KeyEvent(event); |
| 66 return false; |
| 67 } |
| 68 if (event.key_code() == last_key_event_->key_code() && |
| 69 event.flags() == last_key_event_->flags() && |
| 70 (event.time_stamp() - last_key_event_->time_stamp()).InMilliseconds() < |
| 71 kMaxAutoRepeatTimeMs) { |
| 72 return true; |
| 73 } |
| 74 delete last_key_event_; |
| 75 last_key_event_ = new KeyEvent(event); |
| 76 return false; |
| 77 } |
| 78 |
| 79 } // namespace |
| 80 |
| 81 // static |
| 82 MouseEvent PlatformEventBuilder::BuildMouseEvent( |
| 83 const base::NativeEvent& native_event) { |
| 84 MouseEvent mouse_event; |
| 85 FillEventFrom(native_event, &mouse_event); |
| 86 FillLocatedEventFrom(native_event, &mouse_event); |
| 87 FillMouseEventFrom(native_event, &mouse_event); |
| 88 return mouse_event; |
| 89 } |
| 90 |
| 91 // static |
| 92 MouseWheelEvent PlatformEventBuilder::BuildMouseWheelEvent( |
| 93 const base::NativeEvent& native_event) { |
| 94 MouseWheelEvent mouse_wheel_event; |
| 95 FillEventFrom(native_event, &mouse_wheel_event); |
| 96 FillLocatedEventFrom(native_event, &mouse_wheel_event); |
| 97 FillMouseEventFrom(native_event, &mouse_wheel_event); |
| 98 FillMouseWheelEventFrom(native_event, &mouse_wheel_event); |
| 99 return mouse_wheel_event; |
| 100 } |
| 101 |
| 102 // static |
| 103 TouchEvent PlatformEventBuilder::BuildTouchEvent( |
| 104 const base::NativeEvent& native_event) { |
| 105 TouchEvent touch_event; |
| 106 FillEventFrom(native_event, &touch_event); |
| 107 FillLocatedEventFrom(native_event, &touch_event); |
| 108 FillTouchEventFrom(native_event, &touch_event); |
| 109 return touch_event; |
| 110 } |
| 111 |
| 112 // static |
| 113 KeyEvent PlatformEventBuilder::BuildKeyEvent( |
| 114 const base::NativeEvent& native_event) { |
| 115 KeyEvent key_event; |
| 116 FillEventFrom(native_event, &key_event); |
| 117 FillKeyEventFrom(native_event, &key_event); |
| 118 return key_event; |
| 119 } |
| 120 |
| 121 // static |
| 122 ScrollEvent PlatformEventBuilder::BuildScrollEvent( |
| 123 const base::NativeEvent& native_event) { |
| 124 ScrollEvent scroll_event; |
| 125 FillEventFrom(native_event, &scroll_event); |
| 126 FillLocatedEventFrom(native_event, &scroll_event); |
| 127 FillMouseEventFrom(native_event, &scroll_event); |
| 128 FillScrollEventFrom(native_event, &scroll_event); |
| 129 return scroll_event; |
| 130 } |
| 131 |
| 132 // static |
| 133 int PlatformEventBuilder::GetRepeatCount(const base::NativeEvent& native_event, |
| 134 const MouseEvent& event) { |
| 135 int click_count = 1; |
| 136 if (last_click_event_) { |
| 137 if (event.type() == ui::ET_MOUSE_RELEASED) { |
| 138 if (event.changed_button_flags() == |
| 139 last_click_event_->changed_button_flags()) { |
| 140 last_click_complete_ = true; |
| 141 return last_click_event_->GetClickCount(); |
| 142 } else { |
| 143 // If last_click_event_ has changed since this button was pressed |
| 144 // return a click count of 1. |
| 145 return click_count; |
| 146 } |
| 147 } |
| 148 if (event.time_stamp() != last_click_event_->time_stamp()) |
| 149 last_click_complete_ = true; |
| 150 if (!last_click_complete_ || IsX11SendEventTrue(native_event)) { |
| 151 click_count = last_click_event_->GetClickCount(); |
| 152 } else if (MouseEvent::IsRepeatedClickEvent(*last_click_event_, event)) { |
| 153 click_count = last_click_event_->GetClickCount() + 1; |
| 154 } |
| 155 delete last_click_event_; |
| 156 } |
| 157 last_click_event_ = new MouseEvent(event); |
| 158 last_click_complete_ = false; |
| 159 if (click_count > 3) |
| 160 click_count = 3; |
| 161 last_click_event_->SetClickCount(click_count); |
| 162 return click_count; |
| 163 } |
| 164 |
| 165 // static |
| 166 void PlatformEventBuilder::ResetLastClickForTest() { |
| 167 if (last_click_event_) { |
| 168 delete last_click_event_; |
| 169 last_click_event_ = NULL; |
| 170 last_click_complete_ = false; |
| 171 } |
| 172 } |
| 173 |
| 174 // static |
| 175 void PlatformEventBuilder::FillEventFrom(const base::NativeEvent& native_event, |
| 176 Event* event) { |
| 177 event->set_type(EventTypeFromNative(native_event)); |
| 178 event->set_time_stamp(EventTimeFromNative(native_event)); |
| 179 event->set_flags(EventFlagsFromNative(native_event)); |
| 180 |
| 181 #if defined(USE_X11) |
| 182 if (native_event->type == GenericEvent) { |
| 183 XIDeviceEvent* xiev = |
| 184 static_cast<XIDeviceEvent*>(native_event->xcookie.data); |
| 185 event->set_source_device_id(xiev->sourceid); |
| 186 } |
| 187 #endif |
| 188 } |
| 189 |
| 190 // static |
| 191 void PlatformEventBuilder::FillLocatedEventFrom( |
| 192 const base::NativeEvent& native_event, |
| 193 LocatedEvent* located_event) { |
| 194 gfx::PointF event_location = EventLocationFromNative(native_event); |
| 195 located_event->set_location(event_location); |
| 196 located_event->set_root_location(event_location); |
| 197 located_event->set_screen_location( |
| 198 EventSystemLocationFromNative(native_event)); |
| 199 } |
| 200 |
| 201 // static |
| 202 void PlatformEventBuilder::FillMouseEventFrom( |
| 203 const base::NativeEvent& native_event, |
| 204 MouseEvent* mouse_event) { |
| 205 mouse_event->set_changed_button_flags( |
| 206 GetChangedMouseButtonFlagsFromNative(native_event)); |
| 207 |
| 208 if (mouse_event->type() == ET_MOUSE_PRESSED || |
| 209 mouse_event->type() == ET_MOUSE_RELEASED) { |
| 210 mouse_event->SetClickCount(GetRepeatCount(native_event, *mouse_event)); |
| 211 } |
| 212 } |
| 213 |
| 214 // static |
| 215 void PlatformEventBuilder::FillMouseWheelEventFrom( |
| 216 const base::NativeEvent& native_event, |
| 217 MouseWheelEvent* mouse_wheel_event) { |
| 218 mouse_wheel_event->set_offset(GetMouseWheelOffset(native_event)); |
| 219 } |
| 220 |
| 221 // static |
| 222 void PlatformEventBuilder::FillTouchEventFrom( |
| 223 const base::NativeEvent& native_event, |
| 224 TouchEvent* touch_event) { |
| 225 touch_event->set_touch_id(GetTouchId(native_event)); |
| 226 touch_event->set_radius_x(GetTouchRadiusX(native_event)); |
| 227 touch_event->set_radius_y(GetTouchRadiusY(native_event)); |
| 228 touch_event->set_rotation_angle(GetTouchAngle(native_event)); |
| 229 touch_event->set_force(GetTouchForce(native_event)); |
| 230 } |
| 231 |
| 232 // static |
| 233 void PlatformEventBuilder::FillKeyEventFrom( |
| 234 const base::NativeEvent& native_event, |
| 235 KeyEvent* key_event) { |
| 236 key_event->set_key_code(KeyboardCodeFromNative(native_event)); |
| 237 key_event->set_code(CodeFromNative(native_event)); |
| 238 key_event->set_is_char(IsCharFromNative(native_event)); |
| 239 key_event->set_platform_keycode(PlatformKeycodeFromNative(native_event)); |
| 240 |
| 241 if (IsRepeated(native_event, *key_event)) |
| 242 key_event->set_flags(key_event->flags() | ui::EF_IS_REPEAT); |
| 243 |
| 244 #if defined(USE_X11) |
| 245 key_event->NormalizeFlags(); |
| 246 #endif |
| 247 #if defined(OS_WIN) |
| 248 // Only Windows has native character events. |
| 249 if (key_event->is_char()) |
| 250 key_event->set_character(native_event.wParam); |
| 251 #endif |
| 252 } |
| 253 |
| 254 // static |
| 255 void PlatformEventBuilder::FillScrollEventFrom( |
| 256 const base::NativeEvent& native_event, |
| 257 ScrollEvent* scroll_event) { |
| 258 float x_offset = 0; |
| 259 float y_offset = 0; |
| 260 float x_offset_ordinal = 0; |
| 261 float y_offset_ordinal = 0; |
| 262 int finger_count = 0; |
| 263 |
| 264 if (scroll_event->type() == ET_SCROLL) { |
| 265 GetScrollOffsets(native_event, &x_offset, &y_offset, &x_offset_ordinal, |
| 266 &y_offset_ordinal, &finger_count); |
| 267 scroll_event->set_offset(x_offset, y_offset); |
| 268 scroll_event->set_offset_ordinal(x_offset_ordinal, y_offset_ordinal); |
| 269 scroll_event->set_finger_count(finger_count); |
| 270 } else if (scroll_event->type() == ET_SCROLL_FLING_START || |
| 271 scroll_event->type() == ET_SCROLL_FLING_CANCEL) { |
| 272 GetFlingData(native_event, &x_offset, &y_offset, &x_offset_ordinal, |
| 273 &y_offset_ordinal, NULL); |
| 274 scroll_event->set_offset(x_offset, y_offset); |
| 275 scroll_event->set_offset_ordinal(x_offset_ordinal, y_offset_ordinal); |
| 276 } else { |
| 277 NOTREACHED() << "Unexpected event type " << scroll_event->type() |
| 278 << " when constructing a ScrollEvent."; |
| 279 } |
| 280 } |
| 281 |
| 282 } // namespace ui |
OLD | NEW |