| 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/platform/platform_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 } | |
| 248 | |
| 249 // static | |
| 250 void PlatformEventBuilder::FillScrollEventFrom( | |
| 251 const base::NativeEvent& native_event, | |
| 252 ScrollEvent* scroll_event) { | |
| 253 float x_offset = 0; | |
| 254 float y_offset = 0; | |
| 255 float x_offset_ordinal = 0; | |
| 256 float y_offset_ordinal = 0; | |
| 257 int finger_count = 0; | |
| 258 | |
| 259 if (scroll_event->type() == ET_SCROLL) { | |
| 260 GetScrollOffsets(native_event, &x_offset, &y_offset, &x_offset_ordinal, | |
| 261 &y_offset_ordinal, &finger_count); | |
| 262 scroll_event->set_offset(x_offset, y_offset); | |
| 263 scroll_event->set_offset_ordinal(x_offset_ordinal, y_offset_ordinal); | |
| 264 scroll_event->set_finger_count(finger_count); | |
| 265 } else if (scroll_event->type() == ET_SCROLL_FLING_START || | |
| 266 scroll_event->type() == ET_SCROLL_FLING_CANCEL) { | |
| 267 GetFlingData(native_event, &x_offset, &y_offset, &x_offset_ordinal, | |
| 268 &y_offset_ordinal, NULL); | |
| 269 scroll_event->set_offset(x_offset, y_offset); | |
| 270 scroll_event->set_offset_ordinal(x_offset_ordinal, y_offset_ordinal); | |
| 271 } else { | |
| 272 NOTREACHED() << "Unexpected event type " << scroll_event->type() | |
| 273 << " when constructing a ScrollEvent."; | |
| 274 } | |
| 275 } | |
| 276 | |
| 277 } // namespace ui | |
| OLD | NEW |