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/events/platform/platform_event_utils.h" | |
6 | |
7 #include <string.h> | |
8 #include <X11/extensions/XInput.h> | |
9 #include <X11/extensions/XInput2.h> | |
10 #include <X11/XKBlib.h> | |
11 #include <X11/Xlib.h> | |
12 #include <X11/Xutil.h> | |
13 #include <cmath> | |
14 | |
15 #include "base/logging.h" | |
16 #include "base/memory/singleton.h" | |
17 #include "ui/events/event.h" | |
18 #include "ui/events/event_constants.h" | |
19 #include "ui/events/event_utils.h" | |
20 #include "ui/events/platform/x11/device_data_manager_x11.h" | |
21 #include "ui/events/platform/x11/device_list_cache_x.h" | |
22 #include "ui/events/platform/x11/keyboard_code_conversion_x11.h" | |
23 #include "ui/events/platform/x11/touch_factory_x11.h" | |
24 #include "ui/gfx/display.h" | |
25 #include "ui/gfx/point.h" | |
26 #include "ui/gfx/rect.h" | |
27 #include "ui/gfx/x/x11_atom_cache.h" | |
28 #include "ui/gfx/x/x11_types.h" | |
29 | |
30 namespace { | |
31 | |
32 // Scroll amount for each wheelscroll event. 53 is also the value used for GTK+. | |
33 const int kWheelScrollAmount = 53; | |
34 | |
35 const int kMinWheelButton = 4; | |
36 const int kMaxWheelButton = 7; | |
37 | |
38 // A class to track current modifier state on master device. Only track ctrl, | |
39 // alt, shift and caps lock keys currently. The tracked state can then be used | |
40 // by floating device. | |
41 class XModifierStateWatcher { | |
42 public: | |
43 static XModifierStateWatcher* GetInstance() { | |
44 return Singleton<XModifierStateWatcher>::get(); | |
45 } | |
46 | |
47 int StateFromKeyboardCode(ui::KeyboardCode keyboard_code) { | |
48 switch (keyboard_code) { | |
49 case ui::VKEY_CONTROL: | |
50 return ControlMask; | |
51 case ui::VKEY_SHIFT: | |
52 return ShiftMask; | |
53 case ui::VKEY_MENU: | |
54 return Mod1Mask; | |
55 case ui::VKEY_CAPITAL: | |
56 return LockMask; | |
57 default: | |
58 return 0; | |
59 } | |
60 } | |
61 | |
62 void UpdateStateFromXEvent(const base::NativeEvent& native_event) { | |
63 ui::KeyboardCode keyboard_code = ui::KeyboardCodeFromNative(native_event); | |
64 unsigned int mask = StateFromKeyboardCode(keyboard_code); | |
65 // Floating device can't access the modifer state from master device. | |
66 // We need to track the states of modifier keys in a singleton for | |
67 // floating devices such as touch screen. Issue 106426 is one example | |
68 // of why we need the modifier states for floating device. | |
69 switch (native_event->type) { | |
70 case KeyPress: | |
71 state_ = native_event->xkey.state | mask; | |
72 break; | |
73 case KeyRelease: | |
74 state_ = native_event->xkey.state & ~mask; | |
75 break; | |
76 case GenericEvent: { | |
77 XIDeviceEvent* xievent = | |
78 static_cast<XIDeviceEvent*>(native_event->xcookie.data); | |
79 switch (xievent->evtype) { | |
80 case XI_KeyPress: | |
81 state_ = xievent->mods.effective |= mask; | |
82 break; | |
83 case XI_KeyRelease: | |
84 state_ = xievent->mods.effective &= ~mask; | |
85 break; | |
86 default: | |
87 NOTREACHED(); | |
88 break; | |
89 } | |
90 break; | |
91 } | |
92 default: | |
93 NOTREACHED(); | |
94 break; | |
95 } | |
96 } | |
97 | |
98 // Returns the current modifer state in master device. It only contains the | |
99 // state of ctrl, shift, alt and caps lock keys. | |
100 unsigned int state() { return state_; } | |
101 | |
102 private: | |
103 friend struct DefaultSingletonTraits<XModifierStateWatcher>; | |
104 | |
105 XModifierStateWatcher() : state_(0) {} | |
106 | |
107 unsigned int state_; | |
108 | |
109 DISALLOW_COPY_AND_ASSIGN(XModifierStateWatcher); | |
110 }; | |
111 | |
112 #if defined(USE_XI2_MT) | |
113 // Detects if a touch event is a driver-generated 'special event'. | |
114 // A 'special event' is a touch event with maximum radius and pressure at | |
115 // location (0, 0). | |
116 // This needs to be done in a cleaner way: http://crbug.com/169256 | |
117 bool TouchEventIsGeneratedHack(const base::NativeEvent& native_event) { | |
118 XIDeviceEvent* event = | |
119 static_cast<XIDeviceEvent*>(native_event->xcookie.data); | |
120 CHECK(event->evtype == XI_TouchBegin || event->evtype == XI_TouchUpdate || | |
121 event->evtype == XI_TouchEnd); | |
122 | |
123 // Force is normalized to [0, 1]. | |
124 if (ui::GetTouchForce(native_event) < 1.0f) | |
125 return false; | |
126 | |
127 if (ui::EventLocationFromNative(native_event) != gfx::Point()) | |
128 return false; | |
129 | |
130 // Radius is in pixels, and the valuator is the diameter in pixels. | |
131 double radius = ui::GetTouchRadiusX(native_event), min, max; | |
132 unsigned int deviceid = | |
133 static_cast<XIDeviceEvent*>(native_event->xcookie.data)->sourceid; | |
134 if (!ui::DeviceDataManagerX11::GetInstance()->GetDataRange( | |
135 deviceid, ui::DeviceDataManagerX11::DT_TOUCH_MAJOR, &min, &max)) { | |
136 return false; | |
137 } | |
138 | |
139 return radius * 2 == max; | |
140 } | |
141 #endif | |
142 | |
143 int GetEventFlagsFromXState(unsigned int state) { | |
144 int flags = 0; | |
145 if (state & ControlMask) | |
146 flags |= ui::EF_CONTROL_DOWN; | |
147 if (state & ShiftMask) | |
148 flags |= ui::EF_SHIFT_DOWN; | |
149 if (state & Mod1Mask) | |
150 flags |= ui::EF_ALT_DOWN; | |
151 if (state & LockMask) | |
152 flags |= ui::EF_CAPS_LOCK_DOWN; | |
153 if (state & Mod3Mask) | |
154 flags |= ui::EF_MOD3_DOWN; | |
155 if (state & Mod4Mask) | |
156 flags |= ui::EF_COMMAND_DOWN; | |
157 if (state & Mod5Mask) | |
158 flags |= ui::EF_ALTGR_DOWN; | |
159 if (state & Button1Mask) | |
160 flags |= ui::EF_LEFT_MOUSE_BUTTON; | |
161 if (state & Button2Mask) | |
162 flags |= ui::EF_MIDDLE_MOUSE_BUTTON; | |
163 if (state & Button3Mask) | |
164 flags |= ui::EF_RIGHT_MOUSE_BUTTON; | |
165 return flags; | |
166 } | |
167 | |
168 int GetEventFlagsFromXKeyEvent(XEvent* xevent) { | |
169 DCHECK(xevent->type == KeyPress || xevent->type == KeyRelease); | |
170 | |
171 #if defined(OS_CHROMEOS) | |
172 const int ime_fabricated_flag = 0; | |
173 #else | |
174 // XIM fabricates key events for the character compositions by XK_Multi_key. | |
175 // For example, when a user hits XK_Multi_key, XK_apostrophe, and XK_e in | |
176 // order to input "é", then XIM generates a key event with keycode=0 and | |
177 // state=0 for the composition, and the sequence of X11 key events will be | |
178 // XK_Multi_key, XK_apostrophe, **NoSymbol**, and XK_e. If the user used | |
179 // shift key and/or caps lock key, state can be ShiftMask, LockMask or both. | |
180 // | |
181 // We have to send these fabricated key events to XIM so it can correctly | |
182 // handle the character compositions. | |
183 const unsigned int shift_lock_mask = ShiftMask | LockMask; | |
184 const bool fabricated_by_xim = | |
185 xevent->xkey.keycode == 0 && (xevent->xkey.state & ~shift_lock_mask) == 0; | |
186 const int ime_fabricated_flag = | |
187 fabricated_by_xim ? ui::EF_IME_FABRICATED_KEY : 0; | |
188 #endif | |
189 | |
190 return GetEventFlagsFromXState(xevent->xkey.state) | | |
191 (xevent->xkey.send_event ? ui::EF_FINAL : 0) | | |
192 (IsKeypadKey(XLookupKeysym(&xevent->xkey, 0)) ? ui::EF_NUMPAD_KEY | |
193 : 0) | | |
194 (IsFunctionKey(XLookupKeysym(&xevent->xkey, 0)) ? ui::EF_FUNCTION_KEY | |
195 : 0) | | |
196 ime_fabricated_flag; | |
197 } | |
198 | |
199 int GetEventFlagsFromXGenericEvent(XEvent* xevent) { | |
200 DCHECK(xevent->type == GenericEvent); | |
201 XIDeviceEvent* xievent = static_cast<XIDeviceEvent*>(xevent->xcookie.data); | |
202 DCHECK((xievent->evtype == XI_KeyPress) || | |
203 (xievent->evtype == XI_KeyRelease)); | |
204 return GetEventFlagsFromXState(xievent->mods.effective) | | |
205 (xevent->xkey.send_event ? ui::EF_FINAL : 0) | | |
206 (IsKeypadKey( | |
207 XkbKeycodeToKeysym(xievent->display, xievent->detail, 0, 0)) | |
208 ? ui::EF_NUMPAD_KEY | |
209 : 0); | |
210 } | |
211 | |
212 // Get the event flag for the button in XButtonEvent. During a ButtonPress | |
213 // event, |state| in XButtonEvent does not include the button that has just been | |
214 // pressed. Instead |state| contains flags for the buttons (if any) that had | |
215 // already been pressed before the current button, and |button| stores the most | |
216 // current pressed button. So, if you press down left mouse button, and while | |
217 // pressing it down, press down the right mouse button, then for the latter | |
218 // event, |state| would have Button1Mask set but not Button3Mask, and |button| | |
219 // would be 3. | |
220 int GetEventFlagsForButton(int button) { | |
221 switch (button) { | |
222 case 1: | |
223 return ui::EF_LEFT_MOUSE_BUTTON; | |
224 case 2: | |
225 return ui::EF_MIDDLE_MOUSE_BUTTON; | |
226 case 3: | |
227 return ui::EF_RIGHT_MOUSE_BUTTON; | |
228 default: | |
229 return 0; | |
230 } | |
231 } | |
232 | |
233 int GetButtonMaskForX2Event(XIDeviceEvent* xievent) { | |
234 int buttonflags = 0; | |
235 for (int i = 0; i < 8 * xievent->buttons.mask_len; i++) { | |
236 if (XIMaskIsSet(xievent->buttons.mask, i)) { | |
237 int button = | |
238 (xievent->sourceid == xievent->deviceid) | |
239 ? ui::DeviceDataManagerX11::GetInstance()->GetMappedButton(i) | |
240 : i; | |
241 buttonflags |= GetEventFlagsForButton(button); | |
242 } | |
243 } | |
244 return buttonflags; | |
245 } | |
246 | |
247 ui::EventType GetTouchEventType(const base::NativeEvent& native_event) { | |
248 XIDeviceEvent* event = | |
249 static_cast<XIDeviceEvent*>(native_event->xcookie.data); | |
250 #if defined(USE_XI2_MT) | |
251 switch (event->evtype) { | |
252 case XI_TouchBegin: | |
253 return TouchEventIsGeneratedHack(native_event) ? ui::ET_UNKNOWN | |
254 : ui::ET_TOUCH_PRESSED; | |
255 case XI_TouchUpdate: | |
256 return TouchEventIsGeneratedHack(native_event) ? ui::ET_UNKNOWN | |
257 : ui::ET_TOUCH_MOVED; | |
258 case XI_TouchEnd: | |
259 return TouchEventIsGeneratedHack(native_event) ? ui::ET_TOUCH_CANCELLED | |
260 : ui::ET_TOUCH_RELEASED; | |
261 } | |
262 #endif // defined(USE_XI2_MT) | |
263 | |
264 DCHECK(ui::TouchFactory::GetInstance()->IsTouchDevice(event->sourceid)); | |
265 switch (event->evtype) { | |
266 case XI_ButtonPress: | |
267 return ui::ET_TOUCH_PRESSED; | |
268 case XI_ButtonRelease: | |
269 return ui::ET_TOUCH_RELEASED; | |
270 case XI_Motion: | |
271 // Should not convert any emulated Motion event from touch device to | |
272 // touch event. | |
273 if (!(event->flags & XIPointerEmulated) && GetButtonMaskForX2Event(event)) | |
274 return ui::ET_TOUCH_MOVED; | |
275 return ui::ET_UNKNOWN; | |
276 default: | |
277 NOTREACHED(); | |
278 } | |
279 return ui::ET_UNKNOWN; | |
280 } | |
281 | |
282 double GetTouchParamFromXEvent(XEvent* xev, | |
283 ui::DeviceDataManagerX11::DataType val, | |
284 double default_value) { | |
285 ui::DeviceDataManagerX11::GetInstance()->GetEventData(*xev, val, | |
286 &default_value); | |
287 return default_value; | |
288 } | |
289 | |
290 void ScaleTouchRadius(XEvent* xev, double* radius) { | |
291 DCHECK_EQ(GenericEvent, xev->type); | |
292 XIDeviceEvent* xiev = static_cast<XIDeviceEvent*>(xev->xcookie.data); | |
293 ui::DeviceDataManagerX11::GetInstance()->ApplyTouchRadiusScale(xiev->sourceid, | |
294 radius); | |
295 } | |
296 | |
297 bool GetGestureTimes(const base::NativeEvent& native_event, | |
298 double* start_time, | |
299 double* end_time) { | |
300 if (!ui::DeviceDataManagerX11::GetInstance()->HasGestureTimes(native_event)) | |
301 return false; | |
302 | |
303 double start_time_, end_time_; | |
304 if (!start_time) | |
305 start_time = &start_time_; | |
306 if (!end_time) | |
307 end_time = &end_time_; | |
308 | |
309 ui::DeviceDataManagerX11::GetInstance()->GetGestureTimes( | |
310 native_event, start_time, end_time); | |
311 return true; | |
312 } | |
313 | |
314 } // namespace | |
315 | |
316 namespace ui { | |
317 | |
318 void UpdateDeviceList() { | |
319 XDisplay* display = gfx::GetXDisplay(); | |
320 DeviceListCacheX::GetInstance()->UpdateDeviceList(display); | |
321 TouchFactory::GetInstance()->UpdateDeviceList(display); | |
322 DeviceDataManagerX11::GetInstance()->UpdateDeviceList(display); | |
323 } | |
324 | |
325 EventType EventTypeFromNative(const base::NativeEvent& native_event) { | |
326 // Allow the DeviceDataManager to block the event. If blocked return | |
327 // ET_UNKNOWN as the type so this event will not be further processed. | |
328 // NOTE: During some events unittests there is no device data manager. | |
329 if (DeviceDataManager::HasInstance() && | |
330 static_cast<DeviceDataManagerX11*>(DeviceDataManager::GetInstance()) | |
331 ->IsEventBlocked(native_event)) { | |
332 return ET_UNKNOWN; | |
333 } | |
334 | |
335 switch (native_event->type) { | |
336 case KeyPress: | |
337 return ET_KEY_PRESSED; | |
338 case KeyRelease: | |
339 return ET_KEY_RELEASED; | |
340 case ButtonPress: | |
341 if (static_cast<int>(native_event->xbutton.button) >= kMinWheelButton && | |
342 static_cast<int>(native_event->xbutton.button) <= kMaxWheelButton) | |
343 return ET_MOUSEWHEEL; | |
344 return ET_MOUSE_PRESSED; | |
345 case ButtonRelease: | |
346 // Drop wheel events; we should've already scrolled on the press. | |
347 if (static_cast<int>(native_event->xbutton.button) >= kMinWheelButton && | |
348 static_cast<int>(native_event->xbutton.button) <= kMaxWheelButton) | |
349 return ET_UNKNOWN; | |
350 return ET_MOUSE_RELEASED; | |
351 case MotionNotify: | |
352 if (native_event->xmotion.state & | |
353 (Button1Mask | Button2Mask | Button3Mask)) | |
354 return ET_MOUSE_DRAGGED; | |
355 return ET_MOUSE_MOVED; | |
356 case EnterNotify: | |
357 // The standard on Windows is to send a MouseMove event when the mouse | |
358 // first enters a window instead of sending a special mouse enter event. | |
359 // To be consistent we follow the same style. | |
360 return ET_MOUSE_MOVED; | |
361 case LeaveNotify: | |
362 return ET_MOUSE_EXITED; | |
363 case GenericEvent: { | |
364 TouchFactory* factory = TouchFactory::GetInstance(); | |
365 if (!factory->ShouldProcessXI2Event(native_event)) | |
366 return ET_UNKNOWN; | |
367 | |
368 XIDeviceEvent* xievent = | |
369 static_cast<XIDeviceEvent*>(native_event->xcookie.data); | |
370 | |
371 // This check works only for master and floating slave devices. That is | |
372 // why it is necessary to check for the XI_Touch* events in the following | |
373 // switch statement to account for attached-slave touchscreens. | |
374 if (factory->IsTouchDevice(xievent->sourceid)) | |
375 return GetTouchEventType(native_event); | |
376 | |
377 switch (xievent->evtype) { | |
378 case XI_TouchBegin: | |
379 return ui::ET_TOUCH_PRESSED; | |
380 case XI_TouchUpdate: | |
381 return ui::ET_TOUCH_MOVED; | |
382 case XI_TouchEnd: | |
383 return ui::ET_TOUCH_RELEASED; | |
384 case XI_ButtonPress: { | |
385 int button = EventButtonFromNative(native_event); | |
386 if (button >= kMinWheelButton && button <= kMaxWheelButton) | |
387 return ET_MOUSEWHEEL; | |
388 return ET_MOUSE_PRESSED; | |
389 } | |
390 case XI_ButtonRelease: { | |
391 int button = EventButtonFromNative(native_event); | |
392 // Drop wheel events; we should've already scrolled on the press. | |
393 if (button >= kMinWheelButton && button <= kMaxWheelButton) | |
394 return ET_UNKNOWN; | |
395 return ET_MOUSE_RELEASED; | |
396 } | |
397 case XI_Motion: { | |
398 bool is_cancel; | |
399 DeviceDataManagerX11* devices = DeviceDataManagerX11::GetInstance(); | |
400 if (GetFlingData(native_event, NULL, NULL, NULL, NULL, &is_cancel)) | |
401 return is_cancel ? ET_SCROLL_FLING_CANCEL : ET_SCROLL_FLING_START; | |
402 if (devices->IsScrollEvent(native_event)) { | |
403 return devices->IsTouchpadXInputEvent(native_event) ? ET_SCROLL | |
404 : ET_MOUSEWHEEL; | |
405 } | |
406 if (devices->IsCMTMetricsEvent(native_event)) | |
407 return ET_UMA_DATA; | |
408 if (GetButtonMaskForX2Event(xievent)) | |
409 return ET_MOUSE_DRAGGED; | |
410 return ET_MOUSE_MOVED; | |
411 } | |
412 case XI_KeyPress: | |
413 return ET_KEY_PRESSED; | |
414 case XI_KeyRelease: | |
415 return ET_KEY_RELEASED; | |
416 } | |
417 } | |
418 default: | |
419 break; | |
420 } | |
421 return ET_UNKNOWN; | |
422 } | |
423 | |
424 int EventFlagsFromNative(const base::NativeEvent& native_event) { | |
425 switch (native_event->type) { | |
426 case KeyPress: | |
427 case KeyRelease: { | |
428 XModifierStateWatcher::GetInstance()->UpdateStateFromXEvent(native_event); | |
429 return GetEventFlagsFromXKeyEvent(native_event); | |
430 } | |
431 case ButtonPress: | |
432 case ButtonRelease: { | |
433 int flags = GetEventFlagsFromXState(native_event->xbutton.state); | |
434 const EventType type = EventTypeFromNative(native_event); | |
435 if (type == ET_MOUSE_PRESSED || type == ET_MOUSE_RELEASED) | |
436 flags |= GetEventFlagsForButton(native_event->xbutton.button); | |
437 return flags; | |
438 } | |
439 case EnterNotify: | |
440 case LeaveNotify: | |
441 return GetEventFlagsFromXState(native_event->xcrossing.state); | |
442 case MotionNotify: | |
443 return GetEventFlagsFromXState(native_event->xmotion.state); | |
444 case GenericEvent: { | |
445 XIDeviceEvent* xievent = | |
446 static_cast<XIDeviceEvent*>(native_event->xcookie.data); | |
447 | |
448 switch (xievent->evtype) { | |
449 #if defined(USE_XI2_MT) | |
450 case XI_TouchBegin: | |
451 case XI_TouchUpdate: | |
452 case XI_TouchEnd: | |
453 return GetButtonMaskForX2Event(xievent) | | |
454 GetEventFlagsFromXState(xievent->mods.effective) | | |
455 GetEventFlagsFromXState( | |
456 XModifierStateWatcher::GetInstance()->state()); | |
457 break; | |
458 #endif | |
459 case XI_ButtonPress: | |
460 case XI_ButtonRelease: { | |
461 const bool touch = | |
462 TouchFactory::GetInstance()->IsTouchDevice(xievent->sourceid); | |
463 int flags = GetButtonMaskForX2Event(xievent) | | |
464 GetEventFlagsFromXState(xievent->mods.effective); | |
465 if (touch) { | |
466 flags |= GetEventFlagsFromXState( | |
467 XModifierStateWatcher::GetInstance()->state()); | |
468 } | |
469 | |
470 const EventType type = EventTypeFromNative(native_event); | |
471 int button = EventButtonFromNative(native_event); | |
472 if ((type == ET_MOUSE_PRESSED || type == ET_MOUSE_RELEASED) && !touch) | |
473 flags |= GetEventFlagsForButton(button); | |
474 return flags; | |
475 } | |
476 case XI_Motion: | |
477 return GetButtonMaskForX2Event(xievent) | | |
478 GetEventFlagsFromXState(xievent->mods.effective); | |
479 case XI_KeyPress: | |
480 case XI_KeyRelease: { | |
481 XModifierStateWatcher::GetInstance()->UpdateStateFromXEvent( | |
482 native_event); | |
483 return GetEventFlagsFromXGenericEvent(native_event); | |
484 } | |
485 } | |
486 } | |
487 } | |
488 return 0; | |
489 } | |
490 | |
491 base::TimeDelta EventTimeFromNative(const base::NativeEvent& native_event) { | |
492 switch (native_event->type) { | |
493 case KeyPress: | |
494 case KeyRelease: | |
495 return base::TimeDelta::FromMilliseconds(native_event->xkey.time); | |
496 case ButtonPress: | |
497 case ButtonRelease: | |
498 return base::TimeDelta::FromMilliseconds(native_event->xbutton.time); | |
499 break; | |
500 case MotionNotify: | |
501 return base::TimeDelta::FromMilliseconds(native_event->xmotion.time); | |
502 break; | |
503 case EnterNotify: | |
504 case LeaveNotify: | |
505 return base::TimeDelta::FromMilliseconds(native_event->xcrossing.time); | |
506 break; | |
507 case GenericEvent: { | |
508 double start, end; | |
509 double touch_timestamp; | |
510 if (GetGestureTimes(native_event, &start, &end)) { | |
511 // If the driver supports gesture times, use them. | |
512 return base::TimeDelta::FromMicroseconds(end * 1000000); | |
513 } else if (DeviceDataManagerX11::GetInstance()->GetEventData( | |
514 *native_event, | |
515 DeviceDataManagerX11::DT_TOUCH_RAW_TIMESTAMP, | |
516 &touch_timestamp)) { | |
517 return base::TimeDelta::FromMicroseconds(touch_timestamp * 1000000); | |
518 } else { | |
519 XIDeviceEvent* xide = | |
520 static_cast<XIDeviceEvent*>(native_event->xcookie.data); | |
521 return base::TimeDelta::FromMilliseconds(xide->time); | |
522 } | |
523 break; | |
524 } | |
525 } | |
526 NOTREACHED(); | |
527 return base::TimeDelta(); | |
528 } | |
529 | |
530 gfx::Point EventLocationFromNative(const base::NativeEvent& native_event) { | |
531 switch (native_event->type) { | |
532 case EnterNotify: | |
533 case LeaveNotify: | |
534 return gfx::Point(native_event->xcrossing.x, native_event->xcrossing.y); | |
535 case ButtonPress: | |
536 case ButtonRelease: | |
537 return gfx::Point(native_event->xbutton.x, native_event->xbutton.y); | |
538 case MotionNotify: | |
539 return gfx::Point(native_event->xmotion.x, native_event->xmotion.y); | |
540 case GenericEvent: { | |
541 XIDeviceEvent* xievent = | |
542 static_cast<XIDeviceEvent*>(native_event->xcookie.data); | |
543 float x = xievent->event_x; | |
544 float y = xievent->event_y; | |
545 #if defined(OS_CHROMEOS) | |
546 switch (xievent->evtype) { | |
547 case XI_TouchBegin: | |
548 case XI_TouchUpdate: | |
549 case XI_TouchEnd: | |
550 ui::DeviceDataManagerX11::GetInstance()->ApplyTouchTransformer( | |
551 xievent->deviceid, &x, &y); | |
552 break; | |
553 default: | |
554 break; | |
555 } | |
556 #endif // defined(OS_CHROMEOS) | |
557 return gfx::Point(static_cast<int>(x), static_cast<int>(y)); | |
558 } | |
559 } | |
560 return gfx::Point(); | |
561 } | |
562 | |
563 gfx::Point EventSystemLocationFromNative( | |
564 const base::NativeEvent& native_event) { | |
565 switch (native_event->type) { | |
566 case EnterNotify: | |
567 case LeaveNotify: { | |
568 return gfx::Point(native_event->xcrossing.x_root, | |
569 native_event->xcrossing.y_root); | |
570 } | |
571 case ButtonPress: | |
572 case ButtonRelease: { | |
573 return gfx::Point(native_event->xbutton.x_root, | |
574 native_event->xbutton.y_root); | |
575 } | |
576 case MotionNotify: { | |
577 return gfx::Point(native_event->xmotion.x_root, | |
578 native_event->xmotion.y_root); | |
579 } | |
580 case GenericEvent: { | |
581 XIDeviceEvent* xievent = | |
582 static_cast<XIDeviceEvent*>(native_event->xcookie.data); | |
583 return gfx::Point(xievent->root_x, xievent->root_y); | |
584 } | |
585 } | |
586 | |
587 return gfx::Point(); | |
588 } | |
589 | |
590 int EventButtonFromNative(const base::NativeEvent& native_event) { | |
591 CHECK_EQ(GenericEvent, native_event->type); | |
592 XIDeviceEvent* xievent = | |
593 static_cast<XIDeviceEvent*>(native_event->xcookie.data); | |
594 int button = xievent->detail; | |
595 | |
596 return (xievent->sourceid == xievent->deviceid) | |
597 ? DeviceDataManagerX11::GetInstance()->GetMappedButton(button) | |
598 : button; | |
599 } | |
600 | |
601 KeyboardCode KeyboardCodeFromNative(const base::NativeEvent& native_event) { | |
602 return KeyboardCodeFromXKeyEvent(native_event); | |
603 } | |
604 | |
605 const char* CodeFromNative(const base::NativeEvent& native_event) { | |
606 return CodeFromXEvent(native_event); | |
607 } | |
608 | |
609 uint32 PlatformKeycodeFromNative(const base::NativeEvent& native_event) { | |
610 XKeyEvent* xkey = NULL; | |
611 XEvent xkey_from_xi2; | |
612 switch (native_event->type) { | |
613 case KeyPress: | |
614 case KeyRelease: | |
615 xkey = &native_event->xkey; | |
616 break; | |
617 case GenericEvent: { | |
618 XIDeviceEvent* xievent = | |
619 static_cast<XIDeviceEvent*>(native_event->xcookie.data); | |
620 switch (xievent->evtype) { | |
621 case XI_KeyPress: | |
622 case XI_KeyRelease: | |
623 // Build an XKeyEvent corresponding to the XI2 event, | |
624 // so that we can call XLookupString on it. | |
625 InitXKeyEventFromXIDeviceEvent(*native_event, &xkey_from_xi2); | |
626 xkey = &xkey_from_xi2.xkey; | |
627 break; | |
628 default: | |
629 NOTREACHED(); | |
630 break; | |
631 } | |
632 break; | |
633 } | |
634 default: | |
635 NOTREACHED(); | |
636 break; | |
637 } | |
638 KeySym keysym = XK_VoidSymbol; | |
639 if (xkey) | |
640 XLookupString(xkey, NULL, 0, &keysym, NULL); | |
641 return keysym; | |
642 } | |
643 | |
644 bool IsCharFromNative(const base::NativeEvent& native_event) { | |
645 return false; | |
646 } | |
647 | |
648 int GetChangedMouseButtonFlagsFromNative( | |
649 const base::NativeEvent& native_event) { | |
650 switch (native_event->type) { | |
651 case ButtonPress: | |
652 case ButtonRelease: | |
653 return GetEventFlagsFromXState(native_event->xbutton.state); | |
654 case GenericEvent: { | |
655 XIDeviceEvent* xievent = | |
656 static_cast<XIDeviceEvent*>(native_event->xcookie.data); | |
657 switch (xievent->evtype) { | |
658 case XI_ButtonPress: | |
659 case XI_ButtonRelease: | |
660 return GetEventFlagsForButton(EventButtonFromNative(native_event)); | |
661 default: | |
662 break; | |
663 } | |
664 } | |
665 default: | |
666 break; | |
667 } | |
668 return 0; | |
669 } | |
670 | |
671 gfx::Vector2d GetMouseWheelOffset(const base::NativeEvent& native_event) { | |
672 float x_offset, y_offset; | |
673 if (GetScrollOffsets(native_event, &x_offset, &y_offset, NULL, NULL, NULL)) { | |
674 return gfx::Vector2d(static_cast<int>(x_offset), | |
675 static_cast<int>(y_offset)); | |
676 } | |
677 | |
678 int button = native_event->type == GenericEvent | |
679 ? EventButtonFromNative(native_event) | |
680 : native_event->xbutton.button; | |
681 | |
682 switch (button) { | |
683 case 4: | |
684 return gfx::Vector2d(0, kWheelScrollAmount); | |
685 case 5: | |
686 return gfx::Vector2d(0, -kWheelScrollAmount); | |
687 case 6: | |
688 return gfx::Vector2d(kWheelScrollAmount, 0); | |
689 case 7: | |
690 return gfx::Vector2d(-kWheelScrollAmount, 0); | |
691 default: | |
692 return gfx::Vector2d(); | |
693 } | |
694 } | |
695 | |
696 void IncrementTouchIdRefCount(const base::NativeEvent& xev) { | |
697 ui::DeviceDataManagerX11* manager = ui::DeviceDataManagerX11::GetInstance(); | |
698 double tracking_id; | |
699 if (!manager->GetEventData( | |
700 *xev, ui::DeviceDataManagerX11::DT_TOUCH_TRACKING_ID, &tracking_id)) { | |
701 return; | |
702 } | |
703 | |
704 ui::TouchFactory* factory = ui::TouchFactory::GetInstance(); | |
705 factory->AcquireSlotForTrackingID(tracking_id); | |
706 } | |
707 | |
708 void ClearTouchIdIfReleased(const base::NativeEvent& xev) { | |
709 ui::EventType type = ui::EventTypeFromNative(xev); | |
710 if (type == ui::ET_TOUCH_CANCELLED || type == ui::ET_TOUCH_RELEASED) { | |
711 ui::TouchFactory* factory = ui::TouchFactory::GetInstance(); | |
712 ui::DeviceDataManagerX11* manager = ui::DeviceDataManagerX11::GetInstance(); | |
713 double tracking_id; | |
714 if (manager->GetEventData(*xev, | |
715 ui::DeviceDataManagerX11::DT_TOUCH_TRACKING_ID, | |
716 &tracking_id)) { | |
717 factory->ReleaseSlotForTrackingID(tracking_id); | |
718 } | |
719 } | |
720 } | |
721 | |
722 int GetTouchId(const base::NativeEvent& xev) { | |
723 double slot = 0; | |
724 ui::DeviceDataManagerX11* manager = ui::DeviceDataManagerX11::GetInstance(); | |
725 double tracking_id; | |
726 if (!manager->GetEventData( | |
727 *xev, ui::DeviceDataManagerX11::DT_TOUCH_TRACKING_ID, &tracking_id)) { | |
728 LOG(ERROR) << "Could not get the tracking ID for the event. Using 0."; | |
729 } else { | |
730 ui::TouchFactory* factory = ui::TouchFactory::GetInstance(); | |
731 slot = factory->GetSlotForTrackingID(tracking_id); | |
732 } | |
733 return slot; | |
734 } | |
735 | |
736 float GetTouchRadiusX(const base::NativeEvent& native_event) { | |
737 double radius = | |
738 GetTouchParamFromXEvent(native_event, | |
739 ui::DeviceDataManagerX11::DT_TOUCH_MAJOR, 0.0) / | |
740 2.0; | |
741 ScaleTouchRadius(native_event, &radius); | |
742 return radius; | |
743 } | |
744 | |
745 float GetTouchRadiusY(const base::NativeEvent& native_event) { | |
746 double radius = | |
747 GetTouchParamFromXEvent(native_event, | |
748 ui::DeviceDataManagerX11::DT_TOUCH_MINOR, 0.0) / | |
749 2.0; | |
750 ScaleTouchRadius(native_event, &radius); | |
751 return radius; | |
752 } | |
753 | |
754 float GetTouchAngle(const base::NativeEvent& native_event) { | |
755 return GetTouchParamFromXEvent(native_event, | |
756 ui::DeviceDataManagerX11::DT_TOUCH_ORIENTATION, | |
757 0.0) / | |
758 2.0; | |
759 } | |
760 | |
761 float GetTouchForce(const base::NativeEvent& native_event) { | |
762 double force = 0.0; | |
763 force = GetTouchParamFromXEvent( | |
764 native_event, ui::DeviceDataManagerX11::DT_TOUCH_PRESSURE, 0.0); | |
765 unsigned int deviceid = | |
766 static_cast<XIDeviceEvent*>(native_event->xcookie.data)->sourceid; | |
767 // Force is normalized to fall into [0, 1] | |
768 if (!ui::DeviceDataManagerX11::GetInstance()->NormalizeData( | |
769 deviceid, ui::DeviceDataManagerX11::DT_TOUCH_PRESSURE, &force)) | |
770 force = 0.0; | |
771 return force; | |
772 } | |
773 | |
774 bool GetScrollOffsets(const base::NativeEvent& native_event, | |
775 float* x_offset, | |
776 float* y_offset, | |
777 float* x_offset_ordinal, | |
778 float* y_offset_ordinal, | |
779 int* finger_count) { | |
780 if (!DeviceDataManagerX11::GetInstance()->IsScrollEvent(native_event)) | |
781 return false; | |
782 | |
783 // Temp values to prevent passing NULLs to DeviceDataManager. | |
784 float x_offset_, y_offset_; | |
785 float x_offset_ordinal_, y_offset_ordinal_; | |
786 int finger_count_; | |
787 if (!x_offset) | |
788 x_offset = &x_offset_; | |
789 if (!y_offset) | |
790 y_offset = &y_offset_; | |
791 if (!x_offset_ordinal) | |
792 x_offset_ordinal = &x_offset_ordinal_; | |
793 if (!y_offset_ordinal) | |
794 y_offset_ordinal = &y_offset_ordinal_; | |
795 if (!finger_count) | |
796 finger_count = &finger_count_; | |
797 | |
798 DeviceDataManagerX11::GetInstance()->GetScrollOffsets( | |
799 native_event, x_offset, y_offset, x_offset_ordinal, y_offset_ordinal, | |
800 finger_count); | |
801 return true; | |
802 } | |
803 | |
804 bool GetFlingData(const base::NativeEvent& native_event, | |
805 float* vx, | |
806 float* vy, | |
807 float* vx_ordinal, | |
808 float* vy_ordinal, | |
809 bool* is_cancel) { | |
810 if (!DeviceDataManagerX11::GetInstance()->IsFlingEvent(native_event)) | |
811 return false; | |
812 | |
813 float vx_, vy_; | |
814 float vx_ordinal_, vy_ordinal_; | |
815 bool is_cancel_; | |
816 if (!vx) | |
817 vx = &vx_; | |
818 if (!vy) | |
819 vy = &vy_; | |
820 if (!vx_ordinal) | |
821 vx_ordinal = &vx_ordinal_; | |
822 if (!vy_ordinal) | |
823 vy_ordinal = &vy_ordinal_; | |
824 if (!is_cancel) | |
825 is_cancel = &is_cancel_; | |
826 | |
827 DeviceDataManagerX11::GetInstance()->GetFlingData( | |
828 native_event, vx, vy, vx_ordinal, vy_ordinal, is_cancel); | |
829 return true; | |
830 } | |
831 | |
832 } // namespace ui | |
OLD | NEW |