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 |