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.
5 #include "ui/events/event_constants.h"
8 #include <X11/extensions/XInput.h>
9 #include <X11/extensions/XInput2.h>
10 #include <X11/XKBlib.h>
12 #include <X11/Xutil.h>
15 #include "base/logging.h"
16 #include "base/memory/singleton.h"
17 #include "ui/events/devices/x11/device_data_manager_x11.h"
18 #include "ui/events/devices/x11/device_list_cache_x11.h"
19 #include "ui/events/devices/x11/touch_factory_x11.h"
20 #include "ui/events/event.h"
21 #include "ui/events/event_utils.h"
22 #include "ui/events/keycodes/keyboard_code_conversion_x.h"
23 #include "ui/gfx/display.h"
24 #include "ui/gfx/geometry/point.h"
25 #include "ui/gfx/geometry/rect.h"
26 #include "ui/gfx/screen.h"
27 #include "ui/gfx/x/x11_atom_cache.h"
28 #include "ui/gfx/x/x11_types.h"
32 // Scroll amount for each wheelscroll event. 53 is also the value used for GTK+.
33 const int kWheelScrollAmount
= 53;
35 const int kMinWheelButton
= 4;
36 const int kMaxWheelButton
= 7;
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
{
43 static XModifierStateWatcher
* GetInstance() {
44 return Singleton
<XModifierStateWatcher
>::get();
47 int StateFromKeyboardCode(ui::KeyboardCode keyboard_code
) {
48 switch (keyboard_code
) {
49 case ui::VKEY_CONTROL
:
55 case ui::VKEY_CAPITAL
:
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
) {
71 state_
= native_event
->xkey
.state
| mask
;
74 state_
= native_event
->xkey
.state
& ~mask
;
77 XIDeviceEvent
* xievent
=
78 static_cast<XIDeviceEvent
*>(native_event
->xcookie
.data
);
79 switch (xievent
->evtype
) {
81 state_
= xievent
->mods
.effective
|= mask
;
84 state_
= xievent
->mods
.effective
&= ~mask
;
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_
; }
103 friend struct DefaultSingletonTraits
<XModifierStateWatcher
>;
105 XModifierStateWatcher() : state_(0) { }
109 DISALLOW_COPY_AND_ASSIGN(XModifierStateWatcher
);
112 // Detects if a touch event is a driver-generated 'special event'.
113 // A 'special event' is a touch event with maximum radius and pressure at
115 // This needs to be done in a cleaner way: http://crbug.com/169256
116 bool TouchEventIsGeneratedHack(const base::NativeEvent
& native_event
) {
117 XIDeviceEvent
* event
=
118 static_cast<XIDeviceEvent
*>(native_event
->xcookie
.data
);
119 CHECK(event
->evtype
== XI_TouchBegin
||
120 event
->evtype
== XI_TouchUpdate
||
121 event
->evtype
== XI_TouchEnd
);
123 // Force is normalized to [0, 1].
124 if (ui::GetTouchForce(native_event
) < 1.0f
)
127 if (ui::EventLocationFromNative(native_event
) != gfx::Point())
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
)) {
139 return radius
* 2 == max
;
142 int GetEventFlagsFromXState(unsigned int state
) {
144 if (state
& ControlMask
)
145 flags
|= ui::EF_CONTROL_DOWN
;
146 if (state
& ShiftMask
)
147 flags
|= ui::EF_SHIFT_DOWN
;
148 if (state
& Mod1Mask
)
149 flags
|= ui::EF_ALT_DOWN
;
150 if (state
& LockMask
)
151 flags
|= ui::EF_CAPS_LOCK_DOWN
;
152 if (state
& Mod3Mask
)
153 flags
|= ui::EF_MOD3_DOWN
;
154 if (state
& Mod4Mask
)
155 flags
|= ui::EF_COMMAND_DOWN
;
156 if (state
& Mod5Mask
)
157 flags
|= ui::EF_ALTGR_DOWN
;
158 if (state
& Button1Mask
)
159 flags
|= ui::EF_LEFT_MOUSE_BUTTON
;
160 if (state
& Button2Mask
)
161 flags
|= ui::EF_MIDDLE_MOUSE_BUTTON
;
162 if (state
& Button3Mask
)
163 flags
|= ui::EF_RIGHT_MOUSE_BUTTON
;
164 // There are no masks for EF_BACK_MOUSE_BUTTON and
165 // EF_FORWARD_MOUSE_BUTTON.
169 int GetEventFlagsFromXKeyEvent(XEvent
* xevent
) {
170 DCHECK(xevent
->type
== KeyPress
|| xevent
->type
== KeyRelease
);
172 #if defined(OS_CHROMEOS)
173 const int ime_fabricated_flag
= 0;
175 // XIM fabricates key events for the character compositions by XK_Multi_key.
176 // For example, when a user hits XK_Multi_key, XK_apostrophe, and XK_e in
177 // order to input "é", then XIM generates a key event with keycode=0 and
178 // state=0 for the composition, and the sequence of X11 key events will be
179 // XK_Multi_key, XK_apostrophe, **NoSymbol**, and XK_e. If the user used
180 // shift key and/or caps lock key, state can be ShiftMask, LockMask or both.
182 // We have to send these fabricated key events to XIM so it can correctly
183 // handle the character compositions.
184 const unsigned int shift_lock_mask
= ShiftMask
| LockMask
;
185 const bool fabricated_by_xim
=
186 xevent
->xkey
.keycode
== 0 &&
187 (xevent
->xkey
.state
& ~shift_lock_mask
) == 0;
188 const int ime_fabricated_flag
=
189 fabricated_by_xim
? ui::EF_IME_FABRICATED_KEY
: 0;
192 return GetEventFlagsFromXState(xevent
->xkey
.state
) |
193 (xevent
->xkey
.send_event
? ui::EF_FINAL
: 0) |
194 (IsKeypadKey(XLookupKeysym(&xevent
->xkey
, 0)) ? ui::EF_NUMPAD_KEY
: 0) |
195 (IsFunctionKey(XLookupKeysym(&xevent
->xkey
, 0)) ?
196 ui::EF_FUNCTION_KEY
: 0) |
200 int GetEventFlagsFromXGenericEvent(XEvent
* xevent
) {
201 DCHECK(xevent
->type
== GenericEvent
);
202 XIDeviceEvent
* xievent
= static_cast<XIDeviceEvent
*>(xevent
->xcookie
.data
);
203 DCHECK((xievent
->evtype
== XI_KeyPress
) ||
204 (xievent
->evtype
== XI_KeyRelease
));
205 return GetEventFlagsFromXState(xievent
->mods
.effective
) |
206 (xevent
->xkey
.send_event
? ui::EF_FINAL
: 0) |
208 XkbKeycodeToKeysym(xievent
->display
, xievent
->detail
, 0, 0))
213 // Get the event flag for the button in XButtonEvent. During a ButtonPress
214 // event, |state| in XButtonEvent does not include the button that has just been
215 // pressed. Instead |state| contains flags for the buttons (if any) that had
216 // already been pressed before the current button, and |button| stores the most
217 // current pressed button. So, if you press down left mouse button, and while
218 // pressing it down, press down the right mouse button, then for the latter
219 // event, |state| would have Button1Mask set but not Button3Mask, and |button|
221 int GetEventFlagsForButton(int button
) {
224 return ui::EF_LEFT_MOUSE_BUTTON
;
226 return ui::EF_MIDDLE_MOUSE_BUTTON
;
228 return ui::EF_RIGHT_MOUSE_BUTTON
;
230 return ui::EF_BACK_MOUSE_BUTTON
;
232 return ui::EF_FORWARD_MOUSE_BUTTON
;
238 int GetButtonMaskForX2Event(XIDeviceEvent
* xievent
) {
240 for (int i
= 0; i
< 8 * xievent
->buttons
.mask_len
; i
++) {
241 if (XIMaskIsSet(xievent
->buttons
.mask
, i
)) {
242 int button
= (xievent
->sourceid
== xievent
->deviceid
) ?
243 ui::DeviceDataManagerX11::GetInstance()->GetMappedButton(i
) : i
;
244 buttonflags
|= GetEventFlagsForButton(button
);
250 ui::EventType
GetTouchEventType(const base::NativeEvent
& native_event
) {
251 XIDeviceEvent
* event
=
252 static_cast<XIDeviceEvent
*>(native_event
->xcookie
.data
);
253 switch(event
->evtype
) {
255 return TouchEventIsGeneratedHack(native_event
) ? ui::ET_UNKNOWN
:
256 ui::ET_TOUCH_PRESSED
;
258 return TouchEventIsGeneratedHack(native_event
) ? ui::ET_UNKNOWN
:
261 return TouchEventIsGeneratedHack(native_event
) ? ui::ET_TOUCH_CANCELLED
:
262 ui::ET_TOUCH_RELEASED
;
265 DCHECK(ui::TouchFactory::GetInstance()->IsTouchDevice(event
->sourceid
));
266 switch (event
->evtype
) {
268 return ui::ET_TOUCH_PRESSED
;
269 case XI_ButtonRelease
:
270 return ui::ET_TOUCH_RELEASED
;
272 // Should not convert any emulated Motion event from touch device to
274 if (!(event
->flags
& XIPointerEmulated
) &&
275 GetButtonMaskForX2Event(event
))
276 return ui::ET_TOUCH_MOVED
;
277 return ui::ET_UNKNOWN
;
281 return ui::ET_UNKNOWN
;
284 double GetTouchParamFromXEvent(XEvent
* xev
,
285 ui::DeviceDataManagerX11::DataType val
,
286 double default_value
) {
287 ui::DeviceDataManagerX11::GetInstance()->GetEventData(
288 *xev
, val
, &default_value
);
289 return default_value
;
292 void ScaleTouchRadius(XEvent
* xev
, double* radius
) {
293 DCHECK_EQ(GenericEvent
, xev
->type
);
294 XIDeviceEvent
* xiev
= static_cast<XIDeviceEvent
*>(xev
->xcookie
.data
);
295 ui::DeviceDataManagerX11::GetInstance()->ApplyTouchRadiusScale(
296 xiev
->sourceid
, radius
);
299 unsigned int UpdateX11EventFlags(int ui_flags
, unsigned int old_x_flags
) {
304 {ui::EF_CONTROL_DOWN
, ControlMask
},
305 {ui::EF_SHIFT_DOWN
, ShiftMask
},
306 {ui::EF_ALT_DOWN
, Mod1Mask
},
307 {ui::EF_CAPS_LOCK_DOWN
, LockMask
},
308 {ui::EF_ALTGR_DOWN
, Mod5Mask
},
309 {ui::EF_COMMAND_DOWN
, Mod4Mask
},
310 {ui::EF_MOD3_DOWN
, Mod3Mask
},
311 {ui::EF_NUMPAD_KEY
, Mod2Mask
},
312 {ui::EF_LEFT_MOUSE_BUTTON
, Button1Mask
},
313 {ui::EF_MIDDLE_MOUSE_BUTTON
, Button2Mask
},
314 {ui::EF_RIGHT_MOUSE_BUTTON
, Button3Mask
},
316 unsigned int new_x_flags
= old_x_flags
;
317 for (size_t i
= 0; i
< arraysize(flags
); ++i
) {
318 if (ui_flags
& flags
[i
].ui
)
319 new_x_flags
|= flags
[i
].x
;
321 new_x_flags
&= ~flags
[i
].x
;
326 unsigned int UpdateX11EventButton(int ui_flag
, unsigned int old_x_button
) {
328 case ui::EF_LEFT_MOUSE_BUTTON
:
330 case ui::EF_MIDDLE_MOUSE_BUTTON
:
332 case ui::EF_RIGHT_MOUSE_BUTTON
:
340 bool GetGestureTimes(const base::NativeEvent
& native_event
,
343 if (!ui::DeviceDataManagerX11::GetInstance()->HasGestureTimes(native_event
))
346 double start_time_
, end_time_
;
348 start_time
= &start_time_
;
350 end_time
= &end_time_
;
352 ui::DeviceDataManagerX11::GetInstance()->GetGestureTimes(
353 native_event
, start_time
, end_time
);
361 void UpdateDeviceList() {
362 XDisplay
* display
= gfx::GetXDisplay();
363 DeviceListCacheX11::GetInstance()->UpdateDeviceList(display
);
364 TouchFactory::GetInstance()->UpdateDeviceList(display
);
365 DeviceDataManagerX11::GetInstance()->UpdateDeviceList(display
);
368 EventType
EventTypeFromNative(const base::NativeEvent
& native_event
) {
369 // Allow the DeviceDataManager to block the event. If blocked return
370 // ET_UNKNOWN as the type so this event will not be further processed.
371 // NOTE: During some events unittests there is no device data manager.
372 if (DeviceDataManager::HasInstance() &&
373 static_cast<DeviceDataManagerX11
*>(DeviceDataManager::GetInstance())->
374 IsEventBlocked(native_event
)) {
378 switch (native_event
->type
) {
380 return ET_KEY_PRESSED
;
382 return ET_KEY_RELEASED
;
384 if (static_cast<int>(native_event
->xbutton
.button
) >= kMinWheelButton
&&
385 static_cast<int>(native_event
->xbutton
.button
) <= kMaxWheelButton
)
386 return ET_MOUSEWHEEL
;
387 return ET_MOUSE_PRESSED
;
389 // Drop wheel events; we should've already scrolled on the press.
390 if (static_cast<int>(native_event
->xbutton
.button
) >= kMinWheelButton
&&
391 static_cast<int>(native_event
->xbutton
.button
) <= kMaxWheelButton
)
393 return ET_MOUSE_RELEASED
;
395 if (native_event
->xmotion
.state
&
396 (Button1Mask
| Button2Mask
| Button3Mask
))
397 return ET_MOUSE_DRAGGED
;
398 return ET_MOUSE_MOVED
;
400 // The standard on Windows is to send a MouseMove event when the mouse
401 // first enters a window instead of sending a special mouse enter event.
402 // To be consistent we follow the same style.
403 return ET_MOUSE_MOVED
;
405 return ET_MOUSE_EXITED
;
407 TouchFactory
* factory
= TouchFactory::GetInstance();
408 if (!factory
->ShouldProcessXI2Event(native_event
))
411 XIDeviceEvent
* xievent
=
412 static_cast<XIDeviceEvent
*>(native_event
->xcookie
.data
);
414 // This check works only for master and floating slave devices. That is
415 // why it is necessary to check for the XI_Touch* events in the following
416 // switch statement to account for attached-slave touchscreens.
417 if (factory
->IsTouchDevice(xievent
->sourceid
))
418 return GetTouchEventType(native_event
);
420 switch (xievent
->evtype
) {
422 return ui::ET_TOUCH_PRESSED
;
424 return ui::ET_TOUCH_MOVED
;
426 return ui::ET_TOUCH_RELEASED
;
427 case XI_ButtonPress
: {
428 int button
= EventButtonFromNative(native_event
);
429 if (button
>= kMinWheelButton
&& button
<= kMaxWheelButton
)
430 return ET_MOUSEWHEEL
;
431 return ET_MOUSE_PRESSED
;
433 case XI_ButtonRelease
: {
434 int button
= EventButtonFromNative(native_event
);
435 // Drop wheel events; we should've already scrolled on the press.
436 if (button
>= kMinWheelButton
&& button
<= kMaxWheelButton
)
438 return ET_MOUSE_RELEASED
;
442 DeviceDataManagerX11
* devices
= DeviceDataManagerX11::GetInstance();
443 if (GetFlingData(native_event
, NULL
, NULL
, NULL
, NULL
, &is_cancel
))
444 return is_cancel
? ET_SCROLL_FLING_CANCEL
: ET_SCROLL_FLING_START
;
445 if (devices
->IsScrollEvent(native_event
)) {
446 return devices
->IsTouchpadXInputEvent(native_event
) ? ET_SCROLL
449 if (devices
->IsCMTMetricsEvent(native_event
))
451 if (GetButtonMaskForX2Event(xievent
))
452 return ET_MOUSE_DRAGGED
;
453 return ET_MOUSE_MOVED
;
456 return ET_KEY_PRESSED
;
458 return ET_KEY_RELEASED
;
467 int EventFlagsFromNative(const base::NativeEvent
& native_event
) {
468 switch (native_event
->type
) {
471 XModifierStateWatcher::GetInstance()->UpdateStateFromXEvent(native_event
);
472 return GetEventFlagsFromXKeyEvent(native_event
);
475 case ButtonRelease
: {
476 int flags
= GetEventFlagsFromXState(native_event
->xbutton
.state
);
477 const EventType type
= EventTypeFromNative(native_event
);
478 if (type
== ET_MOUSE_PRESSED
|| type
== ET_MOUSE_RELEASED
)
479 flags
|= GetEventFlagsForButton(native_event
->xbutton
.button
);
484 return GetEventFlagsFromXState(native_event
->xcrossing
.state
);
486 return GetEventFlagsFromXState(native_event
->xmotion
.state
);
488 XIDeviceEvent
* xievent
=
489 static_cast<XIDeviceEvent
*>(native_event
->xcookie
.data
);
491 switch (xievent
->evtype
) {
495 return GetButtonMaskForX2Event(xievent
) |
496 GetEventFlagsFromXState(xievent
->mods
.effective
) |
497 GetEventFlagsFromXState(
498 XModifierStateWatcher::GetInstance()->state());
501 case XI_ButtonRelease
: {
503 TouchFactory::GetInstance()->IsTouchDevice(xievent
->sourceid
);
504 int flags
= GetButtonMaskForX2Event(xievent
) |
505 GetEventFlagsFromXState(xievent
->mods
.effective
);
507 flags
|= GetEventFlagsFromXState(
508 XModifierStateWatcher::GetInstance()->state());
511 const EventType type
= EventTypeFromNative(native_event
);
512 int button
= EventButtonFromNative(native_event
);
513 if ((type
== ET_MOUSE_PRESSED
|| type
== ET_MOUSE_RELEASED
) && !touch
)
514 flags
|= GetEventFlagsForButton(button
);
518 return GetButtonMaskForX2Event(xievent
) |
519 GetEventFlagsFromXState(xievent
->mods
.effective
);
521 case XI_KeyRelease
: {
522 XModifierStateWatcher::GetInstance()->UpdateStateFromXEvent(
524 return GetEventFlagsFromXGenericEvent(native_event
);
532 base::TimeDelta
EventTimeFromNative(const base::NativeEvent
& native_event
) {
533 switch(native_event
->type
) {
536 return base::TimeDelta::FromMilliseconds(native_event
->xkey
.time
);
539 return base::TimeDelta::FromMilliseconds(native_event
->xbutton
.time
);
542 return base::TimeDelta::FromMilliseconds(native_event
->xmotion
.time
);
546 return base::TimeDelta::FromMilliseconds(native_event
->xcrossing
.time
);
550 double touch_timestamp
;
551 if (GetGestureTimes(native_event
, &start
, &end
)) {
552 // If the driver supports gesture times, use them.
553 return base::TimeDelta::FromMicroseconds(end
* 1000000);
554 } else if (DeviceDataManagerX11::GetInstance()->GetEventData(
556 DeviceDataManagerX11::DT_TOUCH_RAW_TIMESTAMP
,
558 return base::TimeDelta::FromMicroseconds(touch_timestamp
* 1000000);
560 XIDeviceEvent
* xide
=
561 static_cast<XIDeviceEvent
*>(native_event
->xcookie
.data
);
562 return base::TimeDelta::FromMilliseconds(xide
->time
);
568 return base::TimeDelta();
571 gfx::Point
EventLocationFromNative(const base::NativeEvent
& native_event
) {
572 switch (native_event
->type
) {
575 return gfx::Point(native_event
->xcrossing
.x
, native_event
->xcrossing
.y
);
578 return gfx::Point(native_event
->xbutton
.x
, native_event
->xbutton
.y
);
580 return gfx::Point(native_event
->xmotion
.x
, native_event
->xmotion
.y
);
582 XIDeviceEvent
* xievent
=
583 static_cast<XIDeviceEvent
*>(native_event
->xcookie
.data
);
584 float x
= xievent
->event_x
;
585 float y
= xievent
->event_y
;
586 #if defined(OS_CHROMEOS)
587 switch (xievent
->evtype
) {
591 ui::DeviceDataManagerX11::GetInstance()->ApplyTouchTransformer(
592 xievent
->deviceid
, &x
, &y
);
597 #endif // defined(OS_CHROMEOS)
598 return gfx::Point(static_cast<int>(x
), static_cast<int>(y
));
604 gfx::Point
EventSystemLocationFromNative(
605 const base::NativeEvent
& native_event
) {
606 switch (native_event
->type
) {
609 return gfx::Point(native_event
->xcrossing
.x_root
,
610 native_event
->xcrossing
.y_root
);
613 case ButtonRelease
: {
614 return gfx::Point(native_event
->xbutton
.x_root
,
615 native_event
->xbutton
.y_root
);
618 return gfx::Point(native_event
->xmotion
.x_root
,
619 native_event
->xmotion
.y_root
);
622 XIDeviceEvent
* xievent
=
623 static_cast<XIDeviceEvent
*>(native_event
->xcookie
.data
);
624 return gfx::Point(xievent
->root_x
, xievent
->root_y
);
631 int EventButtonFromNative(const base::NativeEvent
& native_event
) {
632 CHECK_EQ(GenericEvent
, native_event
->type
);
633 XIDeviceEvent
* xievent
=
634 static_cast<XIDeviceEvent
*>(native_event
->xcookie
.data
);
635 int button
= xievent
->detail
;
637 return (xievent
->sourceid
== xievent
->deviceid
) ?
638 DeviceDataManagerX11::GetInstance()->GetMappedButton(button
) : button
;
641 KeyboardCode
KeyboardCodeFromNative(const base::NativeEvent
& native_event
) {
642 return KeyboardCodeFromXKeyEvent(native_event
);
645 DomCode
CodeFromNative(const base::NativeEvent
& native_event
) {
646 return CodeFromXEvent(native_event
);
649 uint32
PlatformKeycodeFromNative(const base::NativeEvent
& native_event
) {
650 XKeyEvent
* xkey
= NULL
;
651 XEvent xkey_from_xi2
;
652 switch (native_event
->type
) {
655 xkey
= &native_event
->xkey
;
658 XIDeviceEvent
* xievent
=
659 static_cast<XIDeviceEvent
*>(native_event
->xcookie
.data
);
660 switch (xievent
->evtype
) {
663 // Build an XKeyEvent corresponding to the XI2 event,
664 // so that we can call XLookupString on it.
665 InitXKeyEventFromXIDeviceEvent(*native_event
, &xkey_from_xi2
);
666 xkey
= &xkey_from_xi2
.xkey
;
678 KeySym keysym
= XK_VoidSymbol
;
680 XLookupString(xkey
, NULL
, 0, &keysym
, NULL
);
684 bool IsCharFromNative(const base::NativeEvent
& native_event
) {
688 int GetChangedMouseButtonFlagsFromNative(
689 const base::NativeEvent
& native_event
) {
690 switch (native_event
->type
) {
693 return GetEventFlagsForButton(native_event
->xbutton
.button
);
695 XIDeviceEvent
* xievent
=
696 static_cast<XIDeviceEvent
*>(native_event
->xcookie
.data
);
697 switch (xievent
->evtype
) {
699 case XI_ButtonRelease
:
700 return GetEventFlagsForButton(EventButtonFromNative(native_event
));
711 gfx::Vector2d
GetMouseWheelOffset(const base::NativeEvent
& native_event
) {
712 float x_offset
, y_offset
;
713 if (GetScrollOffsets(
714 native_event
, &x_offset
, &y_offset
, NULL
, NULL
, NULL
)) {
715 return gfx::Vector2d(static_cast<int>(x_offset
),
716 static_cast<int>(y_offset
));
719 int button
= native_event
->type
== GenericEvent
?
720 EventButtonFromNative(native_event
) : native_event
->xbutton
.button
;
724 return gfx::Vector2d(0, kWheelScrollAmount
);
726 return gfx::Vector2d(0, -kWheelScrollAmount
);
728 return gfx::Vector2d(kWheelScrollAmount
, 0);
730 return gfx::Vector2d(-kWheelScrollAmount
, 0);
732 return gfx::Vector2d();
736 base::NativeEvent
CopyNativeEvent(const base::NativeEvent
& event
) {
737 if (!event
|| event
->type
== GenericEvent
)
739 XEvent
* copy
= new XEvent
;
744 void ReleaseCopiedNativeEvent(const base::NativeEvent
& event
) {
748 void ClearTouchIdIfReleased(const base::NativeEvent
& xev
) {
749 ui::EventType type
= ui::EventTypeFromNative(xev
);
750 if (type
== ui::ET_TOUCH_CANCELLED
||
751 type
== ui::ET_TOUCH_RELEASED
) {
752 ui::TouchFactory
* factory
= ui::TouchFactory::GetInstance();
753 ui::DeviceDataManagerX11
* manager
= ui::DeviceDataManagerX11::GetInstance();
755 if (manager
->GetEventData(
756 *xev
, ui::DeviceDataManagerX11::DT_TOUCH_TRACKING_ID
, &tracking_id
)) {
757 factory
->ReleaseSlotForTrackingID(tracking_id
);
762 int GetTouchId(const base::NativeEvent
& xev
) {
764 ui::DeviceDataManagerX11
* manager
= ui::DeviceDataManagerX11::GetInstance();
766 if (!manager
->GetEventData(
767 *xev
, ui::DeviceDataManagerX11::DT_TOUCH_TRACKING_ID
, &tracking_id
)) {
768 LOG(ERROR
) << "Could not get the tracking ID for the event. Using 0.";
770 ui::TouchFactory
* factory
= ui::TouchFactory::GetInstance();
771 slot
= factory
->GetSlotForTrackingID(tracking_id
);
776 float GetTouchRadiusX(const base::NativeEvent
& native_event
) {
777 double radius
= GetTouchParamFromXEvent(native_event
,
778 ui::DeviceDataManagerX11::DT_TOUCH_MAJOR
, 0.0) / 2.0;
779 ScaleTouchRadius(native_event
, &radius
);
783 float GetTouchRadiusY(const base::NativeEvent
& native_event
) {
784 double radius
= GetTouchParamFromXEvent(native_event
,
785 ui::DeviceDataManagerX11::DT_TOUCH_MINOR
, 0.0) / 2.0;
786 ScaleTouchRadius(native_event
, &radius
);
790 float GetTouchAngle(const base::NativeEvent
& native_event
) {
791 return GetTouchParamFromXEvent(native_event
,
792 ui::DeviceDataManagerX11::DT_TOUCH_ORIENTATION
, 0.0) / 2.0;
795 float GetTouchForce(const base::NativeEvent
& native_event
) {
797 force
= GetTouchParamFromXEvent(native_event
,
798 ui::DeviceDataManagerX11::DT_TOUCH_PRESSURE
, 0.0);
799 unsigned int deviceid
=
800 static_cast<XIDeviceEvent
*>(native_event
->xcookie
.data
)->sourceid
;
801 // Force is normalized to fall into [0, 1]
802 if (!ui::DeviceDataManagerX11::GetInstance()->NormalizeData(
803 deviceid
, ui::DeviceDataManagerX11::DT_TOUCH_PRESSURE
, &force
))
808 bool GetScrollOffsets(const base::NativeEvent
& native_event
,
811 float* x_offset_ordinal
,
812 float* y_offset_ordinal
,
814 if (!DeviceDataManagerX11::GetInstance()->IsScrollEvent(native_event
))
817 // Temp values to prevent passing NULLs to DeviceDataManager.
818 float x_offset_
, y_offset_
;
819 float x_offset_ordinal_
, y_offset_ordinal_
;
822 x_offset
= &x_offset_
;
824 y_offset
= &y_offset_
;
825 if (!x_offset_ordinal
)
826 x_offset_ordinal
= &x_offset_ordinal_
;
827 if (!y_offset_ordinal
)
828 y_offset_ordinal
= &y_offset_ordinal_
;
830 finger_count
= &finger_count_
;
832 DeviceDataManagerX11::GetInstance()->GetScrollOffsets(
835 x_offset_ordinal
, y_offset_ordinal
,
840 bool GetFlingData(const base::NativeEvent
& native_event
,
846 if (!DeviceDataManagerX11::GetInstance()->IsFlingEvent(native_event
))
850 float vx_ordinal_
, vy_ordinal_
;
857 vx_ordinal
= &vx_ordinal_
;
859 vy_ordinal
= &vy_ordinal_
;
861 is_cancel
= &is_cancel_
;
863 DeviceDataManagerX11::GetInstance()->GetFlingData(
864 native_event
, vx
, vy
, vx_ordinal
, vy_ordinal
, is_cancel
);
868 void UpdateX11EventForFlags(Event
* event
) {
869 XEvent
* xev
= event
->native_event();
875 xev
->xkey
.state
= UpdateX11EventFlags(event
->flags(), xev
->xkey
.state
);
880 UpdateX11EventFlags(event
->flags(), xev
->xbutton
.state
);
883 XIDeviceEvent
* xievent
= static_cast<XIDeviceEvent
*>(xev
->xcookie
.data
);
885 xievent
->mods
.effective
=
886 UpdateX11EventFlags(event
->flags(), xievent
->mods
.effective
);
894 void UpdateX11EventForChangedButtonFlags(MouseEvent
* event
) {
895 XEvent
* xev
= event
->native_event();
901 xev
->xbutton
.button
= UpdateX11EventButton(event
->changed_button_flags(),
902 xev
->xbutton
.button
);
905 XIDeviceEvent
* xievent
= static_cast<XIDeviceEvent
*>(xev
->xcookie
.data
);
906 CHECK(xievent
&& (xievent
->evtype
== XI_ButtonPress
||
907 xievent
->evtype
== XI_ButtonRelease
));
909 UpdateX11EventButton(event
->changed_button_flags(), xievent
->detail
);