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"
9 #include <X11/extensions/XInput.h>
10 #include <X11/extensions/XInput2.h>
12 #include <X11/Xutil.h>
14 #include "base/logging.h"
15 #include "base/memory/singleton.h"
16 #include "ui/events/event_utils.h"
17 #include "ui/events/keycodes/keyboard_code_conversion_x.h"
18 #include "ui/events/x/device_data_manager.h"
19 #include "ui/events/x/device_list_cache_x.h"
20 #include "ui/events/x/touch_factory_x11.h"
21 #include "ui/gfx/display.h"
22 #include "ui/gfx/point.h"
23 #include "ui/gfx/rect.h"
24 #include "ui/gfx/screen.h"
25 #include "ui/gfx/x/x11_atom_cache.h"
26 #include "ui/gfx/x/x11_types.h"
30 // Scroll amount for each wheelscroll event. 53 is also the value used for GTK+.
31 const int kWheelScrollAmount = 53;
33 const int kMinWheelButton = 4;
34 const int kMaxWheelButton = 7;
36 // A class to track current modifier state on master device. Only track ctrl,
37 // alt, shift and caps lock keys currently. The tracked state can then be used
38 // by floating device.
39 class XModifierStateWatcher{
41 static XModifierStateWatcher* GetInstance() {
42 return Singleton<XModifierStateWatcher>::get();
45 void UpdateStateFromEvent(const base::NativeEvent& native_event) {
46 // Floating device can't access the modifer state from master device.
47 // We need to track the states of modifier keys in a singleton for
48 // floating devices such as touch screen. Issue 106426 is one example
49 // of why we need the modifier states for floating device.
50 state_ = native_event->xkey.state;
51 // master_state is the state before key press. We need to track the
52 // state after key press for floating device. Currently only ctrl,
53 // shift, alt and caps lock keys are tracked.
54 ui::KeyboardCode keyboard_code = ui::KeyboardCodeFromNative(native_event);
55 unsigned int mask = 0;
57 switch (keyboard_code) {
58 case ui::VKEY_CONTROL: {
62 case ui::VKEY_SHIFT: {
70 case ui::VKEY_CAPITAL: {
78 if (native_event->type == KeyPress)
84 // Returns the current modifer state in master device. It only contains the
85 // state of ctrl, shift, alt and caps lock keys.
86 unsigned int state() { return state_; }
89 friend struct DefaultSingletonTraits<XModifierStateWatcher>;
91 XModifierStateWatcher() : state_(0) { }
95 DISALLOW_COPY_AND_ASSIGN(XModifierStateWatcher);
98 #if defined(USE_XI2_MT)
99 // Detects if a touch event is a driver-generated 'special event'.
100 // A 'special event' is a touch event with maximum radius and pressure at
102 // This needs to be done in a cleaner way: http://crbug.com/169256
103 bool TouchEventIsGeneratedHack(const base::NativeEvent& native_event) {
104 XIDeviceEvent* event =
105 static_cast<XIDeviceEvent*>(native_event->xcookie.data);
106 CHECK(event->evtype == XI_TouchBegin ||
107 event->evtype == XI_TouchUpdate ||
108 event->evtype == XI_TouchEnd);
110 // Force is normalized to [0, 1].
111 if (ui::GetTouchForce(native_event) < 1.0f)
114 if (ui::EventLocationFromNative(native_event) != gfx::Point())
117 // Radius is in pixels, and the valuator is the diameter in pixels.
118 double radius = ui::GetTouchRadiusX(native_event), min, max;
119 unsigned int deviceid =
120 static_cast<XIDeviceEvent*>(native_event->xcookie.data)->sourceid;
121 if (!ui::DeviceDataManager::GetInstance()->GetDataRange(
122 deviceid, ui::DeviceDataManager::DT_TOUCH_MAJOR, &min, &max)) {
126 return radius * 2 == max;
130 int GetEventFlagsFromXState(unsigned int state) {
132 if (state & ControlMask)
133 flags |= ui::EF_CONTROL_DOWN;
134 if (state & ShiftMask)
135 flags |= ui::EF_SHIFT_DOWN;
136 if (state & Mod1Mask)
137 flags |= ui::EF_ALT_DOWN;
138 if (state & LockMask)
139 flags |= ui::EF_CAPS_LOCK_DOWN;
140 if (state & Mod3Mask)
141 flags |= ui::EF_MOD3_DOWN;
142 if (state & Mod4Mask)
143 flags |= ui::EF_COMMAND_DOWN;
144 if (state & Mod5Mask)
145 flags |= ui::EF_ALTGR_DOWN;
146 if (state & Button1Mask)
147 flags |= ui::EF_LEFT_MOUSE_BUTTON;
148 if (state & Button2Mask)
149 flags |= ui::EF_MIDDLE_MOUSE_BUTTON;
150 if (state & Button3Mask)
151 flags |= ui::EF_RIGHT_MOUSE_BUTTON;
155 int GetEventFlagsFromXKeyEvent(XEvent* xevent) {
156 DCHECK(xevent->type == KeyPress || xevent->type == KeyRelease);
158 #if defined(OS_CHROMEOS)
159 const int ime_fabricated_flag = 0;
161 // XIM fabricates key events for the character compositions by XK_Multi_key.
162 // For example, when a user hits XK_Multi_key, XK_apostrophe, and XK_e in
163 // order to input "é", then XIM generates a key event with keycode=0 and
164 // state=0 for the composition, and the sequence of X11 key events will be
165 // XK_Multi_key, XK_apostrophe, **NoSymbol**, and XK_e. If the user used
166 // shift key and/or caps lock key, state can be ShiftMask, LockMask or both.
168 // We have to send these fabricated key events to XIM so it can correctly
169 // handle the character compositions.
170 const unsigned int shift_lock_mask = ShiftMask | LockMask;
171 const bool fabricated_by_xim =
172 xevent->xkey.keycode == 0 &&
173 (xevent->xkey.state & ~shift_lock_mask) == 0;
174 const int ime_fabricated_flag =
175 fabricated_by_xim ? ui::EF_IME_FABRICATED_KEY : 0;
178 return GetEventFlagsFromXState(xevent->xkey.state) |
179 (IsKeypadKey(XLookupKeysym(&xevent->xkey, 0)) ? ui::EF_NUMPAD_KEY : 0) |
180 (IsFunctionKey(XLookupKeysym(&xevent->xkey, 0)) ?
181 ui::EF_FUNCTION_KEY : 0) |
185 // Get the event flag for the button in XButtonEvent. During a ButtonPress
186 // event, |state| in XButtonEvent does not include the button that has just been
187 // pressed. Instead |state| contains flags for the buttons (if any) that had
188 // already been pressed before the current button, and |button| stores the most
189 // current pressed button. So, if you press down left mouse button, and while
190 // pressing it down, press down the right mouse button, then for the latter
191 // event, |state| would have Button1Mask set but not Button3Mask, and |button|
193 int GetEventFlagsForButton(int button) {
196 return ui::EF_LEFT_MOUSE_BUTTON;
198 return ui::EF_MIDDLE_MOUSE_BUTTON;
200 return ui::EF_RIGHT_MOUSE_BUTTON;
206 int GetButtonMaskForX2Event(XIDeviceEvent* xievent) {
208 for (int i = 0; i < 8 * xievent->buttons.mask_len; i++) {
209 if (XIMaskIsSet(xievent->buttons.mask, i)) {
210 int button = (xievent->sourceid == xievent->deviceid) ?
211 ui::DeviceDataManager::GetInstance()->GetMappedButton(i) : i;
212 buttonflags |= GetEventFlagsForButton(button);
218 ui::EventType GetTouchEventType(const base::NativeEvent& native_event) {
219 XIDeviceEvent* event =
220 static_cast<XIDeviceEvent*>(native_event->xcookie.data);
221 #if defined(USE_XI2_MT)
222 switch(event->evtype) {
224 return TouchEventIsGeneratedHack(native_event) ? ui::ET_UNKNOWN :
225 ui::ET_TOUCH_PRESSED;
227 return TouchEventIsGeneratedHack(native_event) ? ui::ET_UNKNOWN :
230 return TouchEventIsGeneratedHack(native_event) ? ui::ET_TOUCH_CANCELLED :
231 ui::ET_TOUCH_RELEASED;
233 #endif // defined(USE_XI2_MT)
235 DCHECK(ui::TouchFactory::GetInstance()->IsTouchDevice(event->sourceid));
236 switch (event->evtype) {
238 return ui::ET_TOUCH_PRESSED;
239 case XI_ButtonRelease:
240 return ui::ET_TOUCH_RELEASED;
242 // Should not convert any emulated Motion event from touch device to
244 if (!(event->flags & XIPointerEmulated) &&
245 GetButtonMaskForX2Event(event))
246 return ui::ET_TOUCH_MOVED;
247 return ui::ET_UNKNOWN;
251 return ui::ET_UNKNOWN;
254 double GetTouchParamFromXEvent(XEvent* xev,
255 ui::DeviceDataManager::DataType val,
256 double default_value) {
257 ui::DeviceDataManager::GetInstance()->GetEventData(
258 *xev, val, &default_value);
259 return default_value;
266 void UpdateDeviceList() {
267 XDisplay* display = gfx::GetXDisplay();
268 DeviceListCacheX::GetInstance()->UpdateDeviceList(display);
269 TouchFactory::GetInstance()->UpdateDeviceList(display);
270 DeviceDataManager::GetInstance()->UpdateDeviceList(display);
273 EventType EventTypeFromNative(const base::NativeEvent& native_event) {
274 switch (native_event->type) {
276 return ET_KEY_PRESSED;
278 return ET_KEY_RELEASED;
280 if (static_cast<int>(native_event->xbutton.button) >= kMinWheelButton &&
281 static_cast<int>(native_event->xbutton.button) <= kMaxWheelButton)
282 return ET_MOUSEWHEEL;
283 return ET_MOUSE_PRESSED;
285 // Drop wheel events; we should've already scrolled on the press.
286 if (static_cast<int>(native_event->xbutton.button) >= kMinWheelButton &&
287 static_cast<int>(native_event->xbutton.button) <= kMaxWheelButton)
289 return ET_MOUSE_RELEASED;
291 if (native_event->xmotion.state &
292 (Button1Mask | Button2Mask | Button3Mask))
293 return ET_MOUSE_DRAGGED;
294 return ET_MOUSE_MOVED;
296 // The standard on Windows is to send a MouseMove event when the mouse
297 // first enters a window instead of sending a special mouse enter event.
298 // To be consistent we follow the same style.
299 return ET_MOUSE_MOVED;
301 return ET_MOUSE_EXITED;
303 TouchFactory* factory = TouchFactory::GetInstance();
304 if (!factory->ShouldProcessXI2Event(native_event))
307 XIDeviceEvent* xievent =
308 static_cast<XIDeviceEvent*>(native_event->xcookie.data);
310 // This check works only for master and floating slave devices. That is
311 // why it is necessary to check for the XI_Touch* events in the following
312 // switch statement to account for attached-slave touchscreens.
313 if (factory->IsTouchDevice(xievent->sourceid))
314 return GetTouchEventType(native_event);
316 switch (xievent->evtype) {
318 return ui::ET_TOUCH_PRESSED;
320 return ui::ET_TOUCH_MOVED;
322 return ui::ET_TOUCH_RELEASED;
323 case XI_ButtonPress: {
324 int button = EventButtonFromNative(native_event);
325 if (button >= kMinWheelButton && button <= kMaxWheelButton)
326 return ET_MOUSEWHEEL;
327 return ET_MOUSE_PRESSED;
329 case XI_ButtonRelease: {
330 int button = EventButtonFromNative(native_event);
331 // Drop wheel events; we should've already scrolled on the press.
332 if (button >= kMinWheelButton && button <= kMaxWheelButton)
334 return ET_MOUSE_RELEASED;
338 if (GetFlingData(native_event, NULL, NULL, NULL, NULL, &is_cancel)) {
339 return is_cancel ? ET_SCROLL_FLING_CANCEL : ET_SCROLL_FLING_START;
340 } else if (DeviceDataManager::GetInstance()->IsScrollEvent(
342 return IsTouchpadEvent(native_event) ? ET_SCROLL : ET_MOUSEWHEEL;
343 } else if (DeviceDataManager::GetInstance()->IsCMTMetricsEvent(
346 } else if (GetButtonMaskForX2Event(xievent)) {
347 return ET_MOUSE_DRAGGED;
349 return ET_MOUSE_MOVED;
360 int EventFlagsFromNative(const base::NativeEvent& native_event) {
361 switch (native_event->type) {
364 XModifierStateWatcher::GetInstance()->UpdateStateFromEvent(native_event);
365 return GetEventFlagsFromXKeyEvent(native_event);
368 case ButtonRelease: {
369 int flags = GetEventFlagsFromXState(native_event->xbutton.state);
370 const EventType type = EventTypeFromNative(native_event);
371 if (type == ET_MOUSE_PRESSED || type == ET_MOUSE_RELEASED)
372 flags |= GetEventFlagsForButton(native_event->xbutton.button);
377 return GetEventFlagsFromXState(native_event->xcrossing.state);
379 return GetEventFlagsFromXState(native_event->xmotion.state);
381 XIDeviceEvent* xievent =
382 static_cast<XIDeviceEvent*>(native_event->xcookie.data);
384 switch (xievent->evtype) {
385 #if defined(USE_XI2_MT)
389 return GetButtonMaskForX2Event(xievent) |
390 GetEventFlagsFromXState(xievent->mods.effective) |
391 GetEventFlagsFromXState(
392 XModifierStateWatcher::GetInstance()->state());
396 case XI_ButtonRelease: {
398 TouchFactory::GetInstance()->IsTouchDevice(xievent->sourceid);
399 int flags = GetButtonMaskForX2Event(xievent) |
400 GetEventFlagsFromXState(xievent->mods.effective);
402 flags |= GetEventFlagsFromXState(
403 XModifierStateWatcher::GetInstance()->state());
406 const EventType type = EventTypeFromNative(native_event);
407 int button = EventButtonFromNative(native_event);
408 if ((type == ET_MOUSE_PRESSED || type == ET_MOUSE_RELEASED) && !touch)
409 flags |= GetEventFlagsForButton(button);
413 return GetButtonMaskForX2Event(xievent) |
414 GetEventFlagsFromXState(xievent->mods.effective);
421 base::TimeDelta EventTimeFromNative(const base::NativeEvent& native_event) {
422 switch(native_event->type) {
425 return base::TimeDelta::FromMilliseconds(native_event->xkey.time);
428 return base::TimeDelta::FromMilliseconds(native_event->xbutton.time);
431 return base::TimeDelta::FromMilliseconds(native_event->xmotion.time);
435 return base::TimeDelta::FromMilliseconds(native_event->xcrossing.time);
439 double touch_timestamp;
440 if (GetGestureTimes(native_event, &start, &end)) {
441 // If the driver supports gesture times, use them.
442 return base::TimeDelta::FromMicroseconds(end * 1000000);
443 } else if (DeviceDataManager::GetInstance()->GetEventData(*native_event,
444 DeviceDataManager::DT_TOUCH_RAW_TIMESTAMP, &touch_timestamp)) {
445 return base::TimeDelta::FromMicroseconds(touch_timestamp * 1000000);
447 XIDeviceEvent* xide =
448 static_cast<XIDeviceEvent*>(native_event->xcookie.data);
449 return base::TimeDelta::FromMilliseconds(xide->time);
455 return base::TimeDelta();
458 gfx::Point EventLocationFromNative(const base::NativeEvent& native_event) {
459 switch (native_event->type) {
462 return gfx::Point(native_event->xcrossing.x, native_event->xcrossing.y);
465 return gfx::Point(native_event->xbutton.x, native_event->xbutton.y);
467 return gfx::Point(native_event->xmotion.x, native_event->xmotion.y);
469 XIDeviceEvent* xievent =
470 static_cast<XIDeviceEvent*>(native_event->xcookie.data);
471 float x = xievent->event_x;
472 float y = xievent->event_y;
473 #if defined(OS_CHROMEOS)
474 switch (xievent->evtype) {
478 ui::DeviceDataManager::GetInstance()->ApplyTouchTransformer(
479 xievent->deviceid, &x, &y);
484 #endif // defined(OS_CHROMEOS)
485 return gfx::Point(static_cast<int>(x), static_cast<int>(y));
491 gfx::Point EventSystemLocationFromNative(
492 const base::NativeEvent& native_event) {
493 switch (native_event->type) {
496 return gfx::Point(native_event->xcrossing.x_root,
497 native_event->xcrossing.y_root);
500 case ButtonRelease: {
501 return gfx::Point(native_event->xbutton.x_root,
502 native_event->xbutton.y_root);
505 return gfx::Point(native_event->xmotion.x_root,
506 native_event->xmotion.y_root);
509 XIDeviceEvent* xievent =
510 static_cast<XIDeviceEvent*>(native_event->xcookie.data);
511 return gfx::Point(xievent->root_x, xievent->root_y);
518 int EventButtonFromNative(const base::NativeEvent& native_event) {
519 CHECK_EQ(GenericEvent, native_event->type);
520 XIDeviceEvent* xievent =
521 static_cast<XIDeviceEvent*>(native_event->xcookie.data);
522 int button = xievent->detail;
524 return (xievent->sourceid == xievent->deviceid) ?
525 DeviceDataManager::GetInstance()->GetMappedButton(button) : button;
528 KeyboardCode KeyboardCodeFromNative(const base::NativeEvent& native_event) {
529 return KeyboardCodeFromXKeyEvent(native_event);
532 const char* CodeFromNative(const base::NativeEvent& native_event) {
533 return CodeFromXEvent(native_event);
536 uint32 PlatformKeycodeFromNative(const base::NativeEvent& native_event) {
538 XLookupString(&native_event->xkey, NULL, 0, &keysym, NULL);
542 int GetChangedMouseButtonFlagsFromNative(
543 const base::NativeEvent& native_event) {
544 switch (native_event->type) {
547 return GetEventFlagsFromXState(native_event->xbutton.state);
549 XIDeviceEvent* xievent =
550 static_cast<XIDeviceEvent*>(native_event->xcookie.data);
551 switch (xievent->evtype) {
553 case XI_ButtonRelease:
554 return GetEventFlagsForButton(EventButtonFromNative(native_event));
565 gfx::Vector2d GetMouseWheelOffset(const base::NativeEvent& native_event) {
566 float x_offset, y_offset;
567 if (GetScrollOffsets(
568 native_event, &x_offset, &y_offset, NULL, NULL, NULL)) {
569 return gfx::Vector2d(static_cast<int>(x_offset),
570 static_cast<int>(y_offset));
573 int button = native_event->type == GenericEvent ?
574 EventButtonFromNative(native_event) : native_event->xbutton.button;
578 return gfx::Vector2d(0, kWheelScrollAmount);
580 return gfx::Vector2d(0, -kWheelScrollAmount);
582 return gfx::Vector2d(kWheelScrollAmount, 0);
584 return gfx::Vector2d(-kWheelScrollAmount, 0);
586 return gfx::Vector2d();
590 base::NativeEvent CopyNativeEvent(const base::NativeEvent& event) {
591 if (!event || event->type == GenericEvent)
593 XEvent* copy = new XEvent;
598 void ReleaseCopiedNativeEvent(const base::NativeEvent& event) {
602 void ClearTouchIdIfReleased(const base::NativeEvent& xev) {
603 ui::EventType type = ui::EventTypeFromNative(xev);
604 if (type == ui::ET_TOUCH_CANCELLED ||
605 type == ui::ET_TOUCH_RELEASED) {
606 ui::TouchFactory* factory = ui::TouchFactory::GetInstance();
607 ui::DeviceDataManager* manager = ui::DeviceDataManager::GetInstance();
609 if (manager->GetEventData(
610 *xev, ui::DeviceDataManager::DT_TOUCH_TRACKING_ID, &tracking_id)) {
611 factory->ReleaseSlotForTrackingID(tracking_id);
616 int GetTouchId(const base::NativeEvent& xev) {
618 ui::DeviceDataManager* manager = ui::DeviceDataManager::GetInstance();
620 if (!manager->GetEventData(
621 *xev, ui::DeviceDataManager::DT_TOUCH_TRACKING_ID, &tracking_id)) {
622 LOG(ERROR) << "Could not get the tracking ID for the event. Using 0.";
624 ui::TouchFactory* factory = ui::TouchFactory::GetInstance();
625 slot = factory->GetSlotForTrackingID(tracking_id);
630 float GetTouchRadiusX(const base::NativeEvent& native_event) {
631 return GetTouchParamFromXEvent(native_event,
632 ui::DeviceDataManager::DT_TOUCH_MAJOR, 0.0) / 2.0;
635 float GetTouchRadiusY(const base::NativeEvent& native_event) {
636 return GetTouchParamFromXEvent(native_event,
637 ui::DeviceDataManager::DT_TOUCH_MINOR, 0.0) / 2.0;
640 float GetTouchAngle(const base::NativeEvent& native_event) {
641 return GetTouchParamFromXEvent(native_event,
642 ui::DeviceDataManager::DT_TOUCH_ORIENTATION, 0.0) / 2.0;
645 float GetTouchForce(const base::NativeEvent& native_event) {
647 force = GetTouchParamFromXEvent(native_event,
648 ui::DeviceDataManager::DT_TOUCH_PRESSURE, 0.0);
649 unsigned int deviceid =
650 static_cast<XIDeviceEvent*>(native_event->xcookie.data)->sourceid;
651 // Force is normalized to fall into [0, 1]
652 if (!ui::DeviceDataManager::GetInstance()->NormalizeData(
653 deviceid, ui::DeviceDataManager::DT_TOUCH_PRESSURE, &force))
658 bool GetScrollOffsets(const base::NativeEvent& native_event,
661 float* x_offset_ordinal,
662 float* y_offset_ordinal,
664 if (!DeviceDataManager::GetInstance()->IsScrollEvent(native_event))
667 // Temp values to prevent passing NULLs to DeviceDataManager.
668 float x_offset_, y_offset_;
669 float x_offset_ordinal_, y_offset_ordinal_;
672 x_offset = &x_offset_;
674 y_offset = &y_offset_;
675 if (!x_offset_ordinal)
676 x_offset_ordinal = &x_offset_ordinal_;
677 if (!y_offset_ordinal)
678 y_offset_ordinal = &y_offset_ordinal_;
680 finger_count = &finger_count_;
682 DeviceDataManager::GetInstance()->GetScrollOffsets(
685 x_offset_ordinal, y_offset_ordinal,
690 bool GetFlingData(const base::NativeEvent& native_event,
696 if (!DeviceDataManager::GetInstance()->IsFlingEvent(native_event))
700 float vx_ordinal_, vy_ordinal_;
707 vx_ordinal = &vx_ordinal_;
709 vy_ordinal = &vy_ordinal_;
711 is_cancel = &is_cancel_;
713 DeviceDataManager::GetInstance()->GetFlingData(
714 native_event, vx, vy, vx_ordinal, vy_ordinal, is_cancel);
718 bool GetGestureTimes(const base::NativeEvent& native_event,
721 if (!DeviceDataManager::GetInstance()->HasGestureTimes(native_event))
724 double start_time_, end_time_;
726 start_time = &start_time_;
728 end_time = &end_time_;
730 DeviceDataManager::GetInstance()->GetGestureTimes(
731 native_event, start_time, end_time);
735 bool IsTouchpadEvent(const base::NativeEvent& event) {
736 return DeviceDataManager::GetInstance()->IsTouchpadXInputEvent(event);