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