1 // Copyright (c) 2016 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/x/events_x_utils.h"
6 
7 #include <stddef.h>
8 #include <string.h>
9 
10 #include <cmath>
11 
12 #include "base/logging.h"
13 #include "base/macros.h"
14 #include "base/memory/singleton.h"
15 #include "base/metrics/histogram_macros.h"
16 #include "build/build_config.h"
17 #include "ui/display/display.h"
18 #include "ui/display/screen.h"
19 #include "ui/events/base_event_utils.h"
20 #include "ui/events/devices/x11/device_data_manager_x11.h"
21 #include "ui/events/devices/x11/device_list_cache_x11.h"
22 #include "ui/events/devices/x11/touch_factory_x11.h"
23 #include "ui/events/devices/x11/xinput_util.h"
24 #include "ui/events/keycodes/keyboard_code_conversion_x.h"
25 #include "ui/gfx/geometry/point.h"
26 #include "ui/gfx/geometry/rect.h"
27 #include "ui/gfx/x/extension_manager.h"
28 #include "ui/gfx/x/x11_atom_cache.h"
29 #include "ui/gfx/x/xproto.h"
30 
31 namespace {
32 
33 // Scroll amount for each wheelscroll event. 53 is also the value used for GTK+.
34 const int kWheelScrollAmount = 53;
35 
36 const int kMinWheelButton = 4;
37 const int kMaxWheelButton = 7;
38 
39 // A class to track current modifier state on master device. Only track ctrl,
40 // alt, shift and caps lock keys currently. The tracked state can then be used
41 // by floating device.
42 class XModifierStateWatcher {
43  public:
GetInstance()44   static XModifierStateWatcher* GetInstance() {
45     return base::Singleton<XModifierStateWatcher>::get();
46   }
47 
StateFromKeyboardCode(ui::KeyboardCode keyboard_code)48   x11::KeyButMask StateFromKeyboardCode(ui::KeyboardCode keyboard_code) {
49     switch (keyboard_code) {
50       case ui::VKEY_CONTROL:
51         return x11::KeyButMask::Control;
52       case ui::VKEY_SHIFT:
53         return x11::KeyButMask::Shift;
54       case ui::VKEY_MENU:
55         return x11::KeyButMask::Mod1;
56       case ui::VKEY_CAPITAL:
57         return x11::KeyButMask::Lock;
58       default:
59         return {};
60     }
61   }
62 
UpdateStateFromXEvent(const x11::Event & xev)63   void UpdateStateFromXEvent(const x11::Event& xev) {
64     ui::KeyboardCode keyboard_code = ui::KeyboardCodeFromXKeyEvent(xev);
65     auto mask = static_cast<int>(StateFromKeyboardCode(keyboard_code));
66     // Floating device can't access the modifier state from master device.
67     // We need to track the states of modifier keys in a singleton for
68     // floating devices such as touch screen. Issue 106426 is one example
69     // of why we need the modifier states for floating device.
70     if (auto* key = xev.As<x11::KeyEvent>()) {
71       if (key->opcode == x11::KeyEvent::Press)
72         state_ = static_cast<int>(key->state) | mask;
73       else
74         state_ = static_cast<int>(key->state) & ~mask;
75     } else if (auto* device = xev.As<x11::Input::DeviceEvent>()) {
76       if (device->opcode == x11::Input::DeviceEvent::KeyPress)
77         state_ = device->mods.effective | mask;
78       else if (device->opcode == x11::Input::DeviceEvent::KeyPress)
79         state_ = device->mods.effective & ~mask;
80     }
81   }
82 
83   // Returns the current modifier state in master device. It only contains the
84   // state of ctrl, shift, alt and caps lock keys.
state()85   unsigned int state() { return state_; }
86 
87  private:
88   friend struct base::DefaultSingletonTraits<XModifierStateWatcher>;
89 
90   XModifierStateWatcher() = default;
91 
92   unsigned int state_{};
93 
94   DISALLOW_COPY_AND_ASSIGN(XModifierStateWatcher);
95 };
96 
97 // Detects if a touch event is a driver-generated 'special event'.
98 // A 'special event' is a touch event with maximum radius and pressure at
99 // location (0, 0).
100 // This needs to be done in a cleaner way: http://crbug.com/169256
TouchEventIsGeneratedHack(const x11::Event & x11_event)101 bool TouchEventIsGeneratedHack(const x11::Event& x11_event) {
102   auto* event = x11_event.As<x11::Input::DeviceEvent>();
103   CHECK(event);
104   CHECK(event->opcode == x11::Input::DeviceEvent::TouchBegin ||
105         event->opcode == x11::Input::DeviceEvent::TouchUpdate ||
106         event->opcode == x11::Input::DeviceEvent::TouchEnd);
107 
108   // Force is normalized to [0, 1].
109   if (ui::GetTouchForceFromXEvent(x11_event) < 1.0f)
110     return false;
111 
112   if (ui::EventLocationFromXEvent(x11_event) != gfx::Point())
113     return false;
114 
115   // Radius is in pixels, and the valuator is the diameter in pixels.
116   double radius = ui::GetTouchRadiusXFromXEvent(x11_event), min, max;
117   auto deviceid = event->sourceid;
118   if (!ui::DeviceDataManagerX11::GetInstance()->GetDataRange(
119           deviceid, ui::DeviceDataManagerX11::DT_TOUCH_MAJOR, &min, &max)) {
120     return false;
121   }
122 
123   return radius * 2 == max;
124 }
125 
GetEventFlagsFromXState(x11::KeyButMask state)126 int GetEventFlagsFromXState(x11::KeyButMask state) {
127   int flags = 0;
128   if (static_cast<bool>(state & x11::KeyButMask::Shift))
129     flags |= ui::EF_SHIFT_DOWN;
130   if (static_cast<bool>(state & x11::KeyButMask::Lock))
131     flags |= ui::EF_CAPS_LOCK_ON;
132   if (static_cast<bool>(state & x11::KeyButMask::Control))
133     flags |= ui::EF_CONTROL_DOWN;
134   if (static_cast<bool>(state & x11::KeyButMask::Mod1))
135     flags |= ui::EF_ALT_DOWN;
136   if (static_cast<bool>(state & x11::KeyButMask::Mod2))
137     flags |= ui::EF_NUM_LOCK_ON;
138   if (static_cast<bool>(state & x11::KeyButMask::Mod3))
139     flags |= ui::EF_MOD3_DOWN;
140   if (static_cast<bool>(state & x11::KeyButMask::Mod4))
141     flags |= ui::EF_COMMAND_DOWN;
142   if (static_cast<bool>(state & x11::KeyButMask::Mod5))
143     flags |= ui::EF_ALTGR_DOWN;
144   if (static_cast<bool>(state & x11::KeyButMask::Button1))
145     flags |= ui::EF_LEFT_MOUSE_BUTTON;
146   if (static_cast<bool>(state & x11::KeyButMask::Button2))
147     flags |= ui::EF_MIDDLE_MOUSE_BUTTON;
148   if (static_cast<bool>(state & x11::KeyButMask::Button3))
149     flags |= ui::EF_RIGHT_MOUSE_BUTTON;
150   // There are no masks for EF_BACK_MOUSE_BUTTON and
151   // EF_FORWARD_MOUSE_BUTTON.
152   return flags;
153 }
154 
GetEventFlagsFromXState(uint32_t state)155 int GetEventFlagsFromXState(uint32_t state) {
156   return GetEventFlagsFromXState(static_cast<x11::KeyButMask>(state));
157 }
158 
GetEventFlagsFromXKeyEvent(const x11::Event & xev)159 int GetEventFlagsFromXKeyEvent(const x11::Event& xev) {
160   auto* key = xev.As<x11::KeyEvent>();
161   DCHECK(key);
162   const auto state = static_cast<int>(key->state);
163 
164 #if defined(OS_CHROMEOS)
165   const int ime_fabricated_flag = 0;
166 #else
167   // XIM fabricates key events for the character compositions by XK_Multi_key.
168   // For example, when a user hits XK_Multi_key, XK_apostrophe, and XK_e in
169   // order to input "é", then XIM generates a key event with keycode=0 and
170   // state=0 for the composition, and the sequence of X11 key events will be
171   // XK_Multi_key, XK_apostrophe, **NoSymbol**, and XK_e.  If the user used
172   // shift key and/or caps lock key, state can be ShiftMask, LockMask or both.
173   //
174   // We have to send these fabricated key events to XIM so it can correctly
175   // handle the character compositions.
176   const auto detail = static_cast<uint8_t>(key->detail);
177   const auto shift_lock_mask =
178       static_cast<int>(x11::KeyButMask::Shift | x11::KeyButMask::Lock);
179   const bool fabricated_by_xim = detail == 0 && (state & ~shift_lock_mask) == 0;
180   const int ime_fabricated_flag =
181       fabricated_by_xim ? ui::EF_IME_FABRICATED_KEY : 0;
182 #endif
183 
184   return GetEventFlagsFromXState(state) | (key->send_event ? ui::EF_FINAL : 0) |
185          ime_fabricated_flag;
186 }
187 
GetEventFlagsFromXGenericEvent(const x11::Event & x11_event)188 int GetEventFlagsFromXGenericEvent(const x11::Event& x11_event) {
189   auto* xievent = x11_event.As<x11::Input::DeviceEvent>();
190   DCHECK(xievent);
191   DCHECK(xievent->opcode == x11::Input::DeviceEvent::KeyPress ||
192          xievent->opcode == x11::Input::DeviceEvent::KeyRelease);
193   return GetEventFlagsFromXState(xievent->mods.effective) |
194          (xievent->send_event ? ui::EF_FINAL : 0);
195 }
196 
197 // Get the event flag for the button in XButtonEvent. During a ButtonPress
198 // event, |state| in XButtonEvent does not include the button that has just been
199 // pressed. Instead |state| contains flags for the buttons (if any) that had
200 // already been pressed before the current button, and |button| stores the most
201 // current pressed button. So, if you press down left mouse button, and while
202 // pressing it down, press down the right mouse button, then for the latter
203 // event, |state| would have Button1Mask set but not Button3Mask, and |button|
204 // would be 3.
GetEventFlagsForButton(int button)205 int GetEventFlagsForButton(int button) {
206   switch (button) {
207     case 1:
208       return ui::EF_LEFT_MOUSE_BUTTON;
209     case 2:
210       return ui::EF_MIDDLE_MOUSE_BUTTON;
211     case 3:
212       return ui::EF_RIGHT_MOUSE_BUTTON;
213     case 8:
214       return ui::EF_BACK_MOUSE_BUTTON;
215     case 9:
216       return ui::EF_FORWARD_MOUSE_BUTTON;
217     default:
218       return 0;
219   }
220 }
221 
GetEventFlagsForButton(x11::Button button)222 int GetEventFlagsForButton(x11::Button button) {
223   return GetEventFlagsForButton(static_cast<int>(button));
224 }
225 
GetButtonMaskForX2Event(const x11::Input::DeviceEvent & xievent)226 int GetButtonMaskForX2Event(const x11::Input::DeviceEvent& xievent) {
227   int buttonflags = 0;
228   for (size_t i = 0; i < 32 * xievent.button_mask.size(); i++) {
229     if (ui::IsXinputMaskSet(xievent.button_mask.data(), i)) {
230       int button =
231           (xievent.sourceid == xievent.deviceid)
232               ? ui::DeviceDataManagerX11::GetInstance()->GetMappedButton(i)
233               : i;
234       buttonflags |= GetEventFlagsForButton(button);
235     }
236   }
237   return buttonflags;
238 }
239 
GetTouchEventType(const x11::Event & x11_event)240 ui::EventType GetTouchEventType(const x11::Event& x11_event) {
241   auto* event = x11_event.As<x11::Input::DeviceEvent>();
242   if (!event) {
243     // This is either a crossing event (which are handled by
244     // PlatformEventDispatcher directly) or a device changed event (which can
245     // happen when --touch-devices flag is used).
246     return ui::ET_UNKNOWN;
247   }
248   switch (event->opcode) {
249     case x11::Input::DeviceEvent::TouchBegin:
250       return TouchEventIsGeneratedHack(x11_event) ? ui::ET_UNKNOWN
251                                                   : ui::ET_TOUCH_PRESSED;
252     case x11::Input::DeviceEvent::TouchUpdate:
253       return TouchEventIsGeneratedHack(x11_event) ? ui::ET_UNKNOWN
254                                                   : ui::ET_TOUCH_MOVED;
255     case x11::Input::DeviceEvent::TouchEnd:
256       return TouchEventIsGeneratedHack(x11_event) ? ui::ET_TOUCH_CANCELLED
257                                                   : ui::ET_TOUCH_RELEASED;
258     default:;
259   }
260 
261   DCHECK(ui::TouchFactory::GetInstance()->IsTouchDevice(event->sourceid));
262   switch (event->opcode) {
263     case x11::Input::DeviceEvent::ButtonPress:
264       return ui::ET_TOUCH_PRESSED;
265     case x11::Input::DeviceEvent::ButtonRelease:
266       return ui::ET_TOUCH_RELEASED;
267     case x11::Input::DeviceEvent::Motion:
268       // Should not convert any emulated Motion event from touch device to
269       // touch event.
270       if (!static_cast<bool>(event->flags &
271                              x11::Input::KeyEventFlags::KeyRepeat) &&
272           GetButtonMaskForX2Event(*event))
273         return ui::ET_TOUCH_MOVED;
274       return ui::ET_UNKNOWN;
275     default:
276       NOTREACHED();
277   }
278   return ui::ET_UNKNOWN;
279 }
280 
GetTouchParamFromXEvent(const x11::Event & xev,ui::DeviceDataManagerX11::DataType val,double default_value)281 double GetTouchParamFromXEvent(const x11::Event& xev,
282                                ui::DeviceDataManagerX11::DataType val,
283                                double default_value) {
284   ui::DeviceDataManagerX11::GetInstance()->GetEventData(xev, val,
285                                                         &default_value);
286   return default_value;
287 }
288 
ScaleTouchRadius(const x11::Event & x11_event,double * radius)289 void ScaleTouchRadius(const x11::Event& x11_event, double* radius) {
290   auto* xiev = x11_event.As<x11::Input::DeviceEvent>();
291   DCHECK(xiev);
292   ui::DeviceDataManagerX11::GetInstance()->ApplyTouchRadiusScale(
293       static_cast<uint16_t>(xiev->sourceid), radius);
294 }
295 
GetGestureTimes(const x11::Event & xev,double * start_time,double * end_time)296 bool GetGestureTimes(const x11::Event& xev,
297                      double* start_time,
298                      double* end_time) {
299   if (!ui::DeviceDataManagerX11::GetInstance()->HasGestureTimes(xev))
300     return false;
301 
302   double start_time_, end_time_;
303   if (!start_time)
304     start_time = &start_time_;
305   if (!end_time)
306     end_time = &end_time_;
307 
308   ui::DeviceDataManagerX11::GetInstance()->GetGestureTimes(xev, start_time,
309                                                            end_time);
310   return true;
311 }
312 
313 int64_t g_last_seen_timestamp_ms = 0;
314 int64_t g_rollover_ms = 0;
315 
316 // Takes Xlib Time and returns a time delta that is immune to timer rollover.
317 // This function is not thread safe as we do not use a lock.
TimeTicksFromXEventTime(x11::Time timestamp)318 base::TimeTicks TimeTicksFromXEventTime(x11::Time timestamp) {
319   uint32_t timestamp32 = static_cast<uint32_t>(timestamp);
320   int64_t timestamp64 = static_cast<int64_t>(timestamp);
321 
322   if (!timestamp64)
323     return ui::EventTimeForNow();
324 
325   // If this is the first event that we get, assume the time stamp roll-over
326   // might have happened before the process was started.
327   // Register a rollover if the distance between last timestamp and current one
328   // is larger than half the width. This avoids false rollovers even in a case
329   // where X server delivers reasonably close events out-of-order.
330   bool had_recent_rollover =
331       !g_last_seen_timestamp_ms ||
332       g_last_seen_timestamp_ms - timestamp64 > (UINT32_MAX >> 1);
333 
334   g_last_seen_timestamp_ms = timestamp64;
335   if (!had_recent_rollover)
336     return base::TimeTicks() +
337            base::TimeDelta::FromMilliseconds(g_rollover_ms + timestamp32);
338 
339   DCHECK(timestamp64 <= UINT32_MAX)
340       << "X11 Time does not roll over 32 bit, the below logic is likely wrong";
341 
342   base::TimeTicks now_ticks = ui::EventTimeForNow();
343   int64_t now_ms = (now_ticks - base::TimeTicks()).InMilliseconds();
344 
345   g_rollover_ms = now_ms & ~static_cast<int64_t>(UINT32_MAX);
346   uint32_t delta = static_cast<uint32_t>(now_ms - timestamp32);
347   return base::TimeTicks() + base::TimeDelta::FromMilliseconds(now_ms - delta);
348 }
349 
TimeTicksFromXEvent(const x11::Event & xev)350 base::TimeTicks TimeTicksFromXEvent(const x11::Event& xev) {
351   if (auto* key = xev.As<x11::KeyEvent>())
352     return TimeTicksFromXEventTime(key->time);
353   if (auto* button = xev.As<x11::ButtonEvent>())
354     return TimeTicksFromXEventTime(button->time);
355   if (auto* motion = xev.As<x11::MotionNotifyEvent>())
356     return TimeTicksFromXEventTime(motion->time);
357   if (auto* crossing = xev.As<x11::CrossingEvent>())
358     return TimeTicksFromXEventTime(crossing->time);
359   if (auto* device = xev.As<x11::Input::DeviceEvent>()) {
360     double start, end;
361     double touch_timestamp;
362     if (GetGestureTimes(xev, &start, &end)) {
363       // If the driver supports gesture times, use them.
364       return ui::EventTimeStampFromSeconds(end);
365     } else if (ui::DeviceDataManagerX11::GetInstance()->GetEventData(
366                    xev, ui::DeviceDataManagerX11::DT_TOUCH_RAW_TIMESTAMP,
367                    &touch_timestamp)) {
368       return ui::EventTimeStampFromSeconds(touch_timestamp);
369     }
370     return TimeTicksFromXEventTime(device->time);
371   }
372   NOTREACHED();
373   return base::TimeTicks();
374 }
375 
376 // This is ported from libxi's FP1616toDBL in XExtInt.c
Fp1616ToDouble(x11::Input::Fp1616 x)377 double Fp1616ToDouble(x11::Input::Fp1616 x) {
378   auto x32 = static_cast<int32_t>(x);
379   return x32 * 1.0 / (1 << 16);
380 }
381 
382 }  // namespace
383 
384 namespace ui {
385 
EventTypeFromXEvent(const x11::Event & xev)386 EventType EventTypeFromXEvent(const x11::Event& xev) {
387   // Allow the DeviceDataManager to block the event. If blocked return
388   // ET_UNKNOWN as the type so this event will not be further processed.
389   // NOTE: During some events unittests there is no device data manager.
390   if (DeviceDataManager::HasInstance() &&
391       DeviceDataManagerX11::GetInstance()->IsEventBlocked(xev)) {
392     return ET_UNKNOWN;
393   }
394 
395   if (auto* key = xev.As<x11::KeyEvent>()) {
396     return key->opcode == x11::KeyEvent::Press ? ET_KEY_PRESSED
397                                                : ET_KEY_RELEASED;
398   }
399   if (auto* xbutton = xev.As<x11::ButtonEvent>()) {
400     int button = static_cast<int>(xbutton->detail);
401     bool wheel = button >= kMinWheelButton && button <= kMaxWheelButton;
402     if (xbutton->opcode == x11::ButtonEvent::Press) {
403       return wheel ? ET_MOUSEWHEEL : ET_MOUSE_PRESSED;
404     }
405     // Drop wheel events; we should've already scrolled on the press.
406     return wheel ? ET_UNKNOWN : ET_MOUSE_RELEASED;
407   }
408   if (auto* motion = xev.As<x11::MotionNotifyEvent>()) {
409     bool primary_button = static_cast<bool>(
410         motion->state & (x11::KeyButMask::Button1 | x11::KeyButMask::Button2 |
411                          x11::KeyButMask::Button3));
412     return primary_button ? ET_MOUSE_DRAGGED : ET_MOUSE_MOVED;
413   }
414   if (auto* crossing = xev.As<x11::CrossingEvent>()) {
415     bool enter = crossing->opcode == x11::CrossingEvent::EnterNotify;
416     // The standard on Windows is to send a MouseMove event when the mouse
417     // first enters a window instead of sending a special mouse enter event.
418     // To be consistent we follow the same style.
419     return enter ? ET_MOUSE_MOVED : ET_MOUSE_EXITED;
420   }
421   if (auto* xievent = xev.As<x11::Input::DeviceEvent>()) {
422     TouchFactory* factory = TouchFactory::GetInstance();
423     if (!factory->ShouldProcessDeviceEvent(*xievent))
424       return ET_UNKNOWN;
425 
426     // This check works only for master and floating slave devices. That is
427     // why it is necessary to check for the Touch events in the following
428     // switch statement to account for attached-slave touchscreens.
429     if (factory->IsTouchDevice(xievent->sourceid))
430       return GetTouchEventType(xev);
431 
432     switch (xievent->opcode) {
433       case x11::Input::DeviceEvent::TouchBegin:
434         return ui::ET_TOUCH_PRESSED;
435       case x11::Input::DeviceEvent::TouchUpdate:
436         return ui::ET_TOUCH_MOVED;
437       case x11::Input::DeviceEvent::TouchEnd:
438         return ui::ET_TOUCH_RELEASED;
439       case x11::Input::DeviceEvent::ButtonPress: {
440         int button = EventButtonFromXEvent(xev);
441         if (button >= kMinWheelButton && button <= kMaxWheelButton)
442           return ET_MOUSEWHEEL;
443         return ET_MOUSE_PRESSED;
444       }
445       case x11::Input::DeviceEvent::ButtonRelease: {
446         int button = EventButtonFromXEvent(xev);
447         // Drop wheel events; we should've already scrolled on the press.
448         if (button >= kMinWheelButton && button <= kMaxWheelButton)
449           return ET_UNKNOWN;
450         return ET_MOUSE_RELEASED;
451       }
452       case x11::Input::DeviceEvent::Motion: {
453         bool is_cancel;
454         DeviceDataManagerX11* devices = DeviceDataManagerX11::GetInstance();
455         if (GetFlingDataFromXEvent(xev, nullptr, nullptr, nullptr, nullptr,
456                                    &is_cancel))
457           return is_cancel ? ET_SCROLL_FLING_CANCEL : ET_SCROLL_FLING_START;
458         if (devices->IsScrollEvent(xev)) {
459           return devices->IsTouchpadXInputEvent(xev) ? ET_SCROLL
460                                                      : ET_MOUSEWHEEL;
461         }
462         if (devices->GetScrollClassEventDetail(xev) != SCROLL_TYPE_NO_SCROLL) {
463           return devices->IsTouchpadXInputEvent(xev) ? ET_SCROLL
464                                                      : ET_MOUSEWHEEL;
465         }
466         if (devices->IsCMTMetricsEvent(xev))
467           return ET_UMA_DATA;
468         if (GetButtonMaskForX2Event(*xievent))
469           return ET_MOUSE_DRAGGED;
470         if (DeviceDataManagerX11::GetInstance()->HasEventData(
471                 xev, DeviceDataManagerX11::DT_CMT_SCROLL_X) ||
472             DeviceDataManagerX11::GetInstance()->HasEventData(
473                 xev, DeviceDataManagerX11::DT_CMT_SCROLL_Y)) {
474           // Don't produce mouse move events for mousewheel scrolls.
475           return ET_UNKNOWN;
476         }
477 
478         return ET_MOUSE_MOVED;
479       }
480       case x11::Input::DeviceEvent::KeyPress:
481         return ET_KEY_PRESSED;
482       case x11::Input::DeviceEvent::KeyRelease:
483         return ET_KEY_RELEASED;
484     }
485   }
486   return ET_UNKNOWN;
487 }
488 
EventFlagsFromXEvent(const x11::Event & xev)489 int EventFlagsFromXEvent(const x11::Event& xev) {
490   if (xev.As<x11::KeyEvent>()) {
491     XModifierStateWatcher::GetInstance()->UpdateStateFromXEvent(xev);
492     return GetEventFlagsFromXKeyEvent(xev);
493   }
494   if (auto* button = xev.As<x11::ButtonEvent>()) {
495     int flags = GetEventFlagsFromXState(button->state);
496     const EventType type = EventTypeFromXEvent(xev);
497     if (type == ET_MOUSE_PRESSED || type == ET_MOUSE_RELEASED)
498       flags |= GetEventFlagsForButton(button->detail);
499     return flags;
500   }
501   if (auto* crossing = xev.As<x11::CrossingEvent>()) {
502     int state = GetEventFlagsFromXState(crossing->state);
503     // EnterNotify creates ET_MOUSE_MOVED. Mark as synthesized as this is not
504     // a real mouse move event.
505     if (crossing->opcode == x11::CrossingEvent::EnterNotify)
506       state |= EF_IS_SYNTHESIZED;
507     return state;
508   }
509   if (auto* motion = xev.As<x11::MotionNotifyEvent>())
510     return GetEventFlagsFromXState(motion->state);
511   if (auto* xievent = xev.As<x11::Input::DeviceEvent>()) {
512     switch (xievent->opcode) {
513       case x11::Input::DeviceEvent::TouchBegin:
514       case x11::Input::DeviceEvent::TouchUpdate:
515       case x11::Input::DeviceEvent::TouchEnd:
516         return GetButtonMaskForX2Event(*xievent) |
517                GetEventFlagsFromXState(xievent->mods.effective) |
518                GetEventFlagsFromXState(
519                    XModifierStateWatcher::GetInstance()->state());
520       case x11::Input::DeviceEvent::ButtonPress:
521       case x11::Input::DeviceEvent::ButtonRelease: {
522         const bool touch =
523             TouchFactory::GetInstance()->IsTouchDevice(xievent->sourceid);
524         int flags = GetButtonMaskForX2Event(*xievent) |
525                     GetEventFlagsFromXState(xievent->mods.effective);
526         if (touch) {
527           flags |= GetEventFlagsFromXState(
528               XModifierStateWatcher::GetInstance()->state());
529         }
530 
531         const EventType type = EventTypeFromXEvent(xev);
532         int button = EventButtonFromXEvent(xev);
533         if ((type == ET_MOUSE_PRESSED || type == ET_MOUSE_RELEASED) && !touch)
534           flags |= GetEventFlagsForButton(button);
535         return flags;
536       }
537       case x11::Input::DeviceEvent::Motion:
538         return GetButtonMaskForX2Event(*xievent) |
539                GetEventFlagsFromXState(xievent->mods.effective);
540       case x11::Input::DeviceEvent::KeyPress:
541       case x11::Input::DeviceEvent::KeyRelease: {
542         XModifierStateWatcher::GetInstance()->UpdateStateFromXEvent(xev);
543         return GetEventFlagsFromXGenericEvent(xev);
544       }
545     }
546   }
547   return 0;
548 }
549 
EventTimeFromXEvent(const x11::Event & xev)550 base::TimeTicks EventTimeFromXEvent(const x11::Event& xev) {
551   auto timestamp = TimeTicksFromXEvent(xev);
552   ValidateEventTimeClock(&timestamp);
553   return timestamp;
554 }
555 
EventLocationFromXEvent(const x11::Event & xev)556 gfx::Point EventLocationFromXEvent(const x11::Event& xev) {
557   if (auto* crossing = xev.As<x11::CrossingEvent>())
558     return gfx::Point(crossing->event_x, crossing->event_y);
559   if (auto* button = xev.As<x11::ButtonEvent>())
560     return gfx::Point(button->event_x, button->event_y);
561   if (auto* motion = xev.As<x11::MotionNotifyEvent>())
562     return gfx::Point(motion->event_x, motion->event_y);
563   if (auto* xievent = xev.As<x11::Input::DeviceEvent>()) {
564     float x = Fp1616ToDouble(xievent->event_x);
565     float y = Fp1616ToDouble(xievent->event_y);
566 #if defined(OS_CHROMEOS)
567     switch (xievent->opcode) {
568       case x11::Input::DeviceEvent::TouchBegin:
569       case x11::Input::DeviceEvent::TouchUpdate:
570       case x11::Input::DeviceEvent::TouchEnd:
571         ui::DeviceDataManagerX11::GetInstance()->ApplyTouchTransformer(
572             static_cast<uint16_t>(xievent->deviceid), &x, &y);
573         break;
574       default:
575         break;
576     }
577 #endif  // defined(OS_CHROMEOS)
578     return gfx::Point(static_cast<int>(x), static_cast<int>(y));
579   }
580   return gfx::Point();
581 }
582 
EventSystemLocationFromXEvent(const x11::Event & xev)583 gfx::Point EventSystemLocationFromXEvent(const x11::Event& xev) {
584   if (auto* crossing = xev.As<x11::CrossingEvent>())
585     return gfx::Point(crossing->root_x, crossing->root_y);
586   if (auto* button = xev.As<x11::ButtonEvent>())
587     return gfx::Point(button->root_x, button->root_y);
588   if (auto* motion = xev.As<x11::MotionNotifyEvent>())
589     return gfx::Point(motion->root_x, motion->root_y);
590   if (auto* xievent = xev.As<x11::Input::DeviceEvent>()) {
591     return gfx::Point(Fp1616ToDouble(xievent->root_x),
592                       Fp1616ToDouble(xievent->root_y));
593   }
594   return gfx::Point();
595 }
596 
EventButtonFromXEvent(const x11::Event & xev)597 int EventButtonFromXEvent(const x11::Event& xev) {
598   auto* xievent = xev.As<x11::Input::DeviceEvent>();
599   DCHECK(xievent);
600   int button = xievent->detail;
601 
602   return (xievent->sourceid == xievent->deviceid)
603              ? DeviceDataManagerX11::GetInstance()->GetMappedButton(button)
604              : button;
605 }
606 
GetChangedMouseButtonFlagsFromXEvent(const x11::Event & xev)607 int GetChangedMouseButtonFlagsFromXEvent(const x11::Event& xev) {
608   if (auto* button = xev.As<x11::ButtonEvent>())
609     return GetEventFlagsForButton(button->detail);
610   auto* device = xev.As<x11::Input::DeviceEvent>();
611   if (device && (device->opcode == x11::Input::DeviceEvent::ButtonPress ||
612                  device->opcode == x11::Input::DeviceEvent::ButtonRelease)) {
613     return GetEventFlagsForButton(EventButtonFromXEvent(xev));
614   }
615   return 0;
616 }
617 
GetMouseWheelOffsetFromXEvent(const x11::Event & xev)618 gfx::Vector2d GetMouseWheelOffsetFromXEvent(const x11::Event& xev) {
619   float x_offset, y_offset;
620   if (GetScrollOffsetsFromXEvent(xev, &x_offset, &y_offset, nullptr, nullptr,
621                                  nullptr)) {
622     return gfx::Vector2d(static_cast<int>(x_offset),
623                          static_cast<int>(y_offset));
624   }
625 
626   auto* device = xev.As<x11::Input::DeviceEvent>();
627   int button = device ? EventButtonFromXEvent(xev)
628                       : static_cast<int>(xev.As<x11::ButtonEvent>()->detail);
629 
630   // If this is an xinput1 scroll event from an xinput2 mouse then we need to
631   // block the legacy scroll events for the necessary axes.
632   int scroll_class_type =
633       DeviceDataManagerX11::GetInstance()->GetScrollClassDeviceDetail(xev);
634   bool xi2_vertical = scroll_class_type & SCROLL_TYPE_VERTICAL;
635   bool xi2_horizontal = scroll_class_type & SCROLL_TYPE_HORIZONTAL;
636 
637   switch (button) {
638     case 4:
639       return gfx::Vector2d(0, xi2_vertical ? 0 : kWheelScrollAmount);
640     case 5:
641       return gfx::Vector2d(0, xi2_vertical ? 0 : -kWheelScrollAmount);
642     case 6:
643       return gfx::Vector2d(xi2_horizontal ? 0 : kWheelScrollAmount, 0);
644     case 7:
645       return gfx::Vector2d(xi2_horizontal ? 0 : -kWheelScrollAmount, 0);
646     default:
647       return gfx::Vector2d();
648   }
649 }
650 
GetTouchIdFromXEvent(const x11::Event & xev)651 int GetTouchIdFromXEvent(const x11::Event& xev) {
652   double slot = 0;
653   ui::DeviceDataManagerX11* manager = ui::DeviceDataManagerX11::GetInstance();
654   double tracking_id;
655   if (!manager->GetEventData(
656           xev, ui::DeviceDataManagerX11::DT_TOUCH_TRACKING_ID, &tracking_id)) {
657     LOG(ERROR) << "Could not get the tracking ID for the event. Using 0.";
658   } else {
659     ui::TouchFactory* factory = ui::TouchFactory::GetInstance();
660     slot = factory->GetSlotForTrackingID(tracking_id);
661   }
662   return slot;
663 }
664 
GetTouchRadiusXFromXEvent(const x11::Event & xev)665 float GetTouchRadiusXFromXEvent(const x11::Event& xev) {
666   double radius = GetTouchParamFromXEvent(
667                       xev, ui::DeviceDataManagerX11::DT_TOUCH_MAJOR, 0.0) /
668                   2.0;
669   ScaleTouchRadius(xev, &radius);
670   return radius;
671 }
672 
GetTouchRadiusYFromXEvent(const x11::Event & xev)673 float GetTouchRadiusYFromXEvent(const x11::Event& xev) {
674   double radius = GetTouchParamFromXEvent(
675                       xev, ui::DeviceDataManagerX11::DT_TOUCH_MINOR, 0.0) /
676                   2.0;
677   ScaleTouchRadius(xev, &radius);
678   return radius;
679 }
680 
GetTouchAngleFromXEvent(const x11::Event & xev)681 float GetTouchAngleFromXEvent(const x11::Event& xev) {
682   return GetTouchParamFromXEvent(
683              xev, ui::DeviceDataManagerX11::DT_TOUCH_ORIENTATION, 0.0) /
684          2.0;
685 }
686 
GetTouchForceFromXEvent(const x11::Event & x11_event)687 float GetTouchForceFromXEvent(const x11::Event& x11_event) {
688   auto* event = x11_event.As<x11::Input::DeviceEvent>();
689   if (event->opcode == x11::Input::DeviceEvent::TouchEnd)
690     return 0.0;
691   double force = 0.0;
692   force = GetTouchParamFromXEvent(
693       x11_event, ui::DeviceDataManagerX11::DT_TOUCH_PRESSURE, 0.0);
694   auto deviceid = event->sourceid;
695   // Force is normalized to fall into [0, 1]
696   if (!ui::DeviceDataManagerX11::GetInstance()->NormalizeData(
697           deviceid, ui::DeviceDataManagerX11::DT_TOUCH_PRESSURE, &force))
698     force = 0.0;
699   return force;
700 }
701 
GetTouchPointerDetailsFromXEvent(const x11::Event & xev)702 PointerDetails GetTouchPointerDetailsFromXEvent(const x11::Event& xev) {
703   return PointerDetails(
704       EventPointerType::kTouch, GetTouchIdFromXEvent(xev),
705       GetTouchRadiusXFromXEvent(xev), GetTouchRadiusYFromXEvent(xev),
706       GetTouchForceFromXEvent(xev), GetTouchAngleFromXEvent(xev));
707 }
708 
GetScrollOffsetsFromXEvent(const x11::Event & xev,float * x_offset,float * y_offset,float * x_offset_ordinal,float * y_offset_ordinal,int * finger_count)709 bool GetScrollOffsetsFromXEvent(const x11::Event& xev,
710                                 float* x_offset,
711                                 float* y_offset,
712                                 float* x_offset_ordinal,
713                                 float* y_offset_ordinal,
714                                 int* finger_count) {
715   // Temp values to prevent passing nullptrs to DeviceDataManager.
716   float x_scroll_offset, y_scroll_offset;
717   float x_scroll_offset_ordinal, y_scroll_offset_ordinal;
718   int finger;
719   if (!x_offset)
720     x_offset = &x_scroll_offset;
721   if (!y_offset)
722     y_offset = &y_scroll_offset;
723   if (!x_offset_ordinal)
724     x_offset_ordinal = &x_scroll_offset_ordinal;
725   if (!y_offset_ordinal)
726     y_offset_ordinal = &y_scroll_offset_ordinal;
727   if (!finger_count)
728     finger_count = &finger;
729 
730   if (DeviceDataManagerX11::GetInstance()->IsScrollEvent(xev)) {
731     DeviceDataManagerX11::GetInstance()->GetScrollOffsets(
732         xev, x_offset, y_offset, x_offset_ordinal, y_offset_ordinal,
733         finger_count);
734     return true;
735   }
736 
737   if (DeviceDataManagerX11::GetInstance()->GetScrollClassEventDetail(xev) !=
738       SCROLL_TYPE_NO_SCROLL) {
739     double x_scroll_offset, y_scroll_offset;
740     DeviceDataManagerX11::GetInstance()->GetScrollClassOffsets(
741         xev, &x_scroll_offset, &y_scroll_offset);
742     *x_offset = x_scroll_offset * kWheelScrollAmount;
743     *y_offset = y_scroll_offset * kWheelScrollAmount;
744 
745     if (DeviceDataManagerX11::GetInstance()->IsTouchpadXInputEvent(xev)) {
746       *x_offset_ordinal = *x_offset;
747       *y_offset_ordinal = *y_offset;
748       // In libinput, we can check to validate whether the device supports
749       // 'two_finger', 'edge' scrolling or not. See
750       // https://www.mankier.com/4/libinput.
751       *finger_count = 2;
752     }
753     return true;
754   }
755   return false;
756 }
757 
GetFlingDataFromXEvent(const x11::Event & xev,float * vx,float * vy,float * vx_ordinal,float * vy_ordinal,bool * is_cancel)758 bool GetFlingDataFromXEvent(const x11::Event& xev,
759                             float* vx,
760                             float* vy,
761                             float* vx_ordinal,
762                             float* vy_ordinal,
763                             bool* is_cancel) {
764   if (!DeviceDataManagerX11::GetInstance()->IsFlingEvent(xev))
765     return false;
766 
767   float vx_, vy_;
768   float vx_ordinal_, vy_ordinal_;
769   bool is_cancel_;
770   if (!vx)
771     vx = &vx_;
772   if (!vy)
773     vy = &vy_;
774   if (!vx_ordinal)
775     vx_ordinal = &vx_ordinal_;
776   if (!vy_ordinal)
777     vy_ordinal = &vy_ordinal_;
778   if (!is_cancel)
779     is_cancel = &is_cancel_;
780 
781   DeviceDataManagerX11::GetInstance()->GetFlingData(xev, vx, vy, vx_ordinal,
782                                                     vy_ordinal, is_cancel);
783   return true;
784 }
785 
IsAltPressed()786 bool IsAltPressed() {
787   return XModifierStateWatcher::GetInstance()->state() &
788          static_cast<int>(x11::KeyButMask::Mod1);
789 }
790 
GetModifierKeyState()791 int GetModifierKeyState() {
792   return XModifierStateWatcher::GetInstance()->state();
793 }
794 
ResetTimestampRolloverCountersForTesting()795 void ResetTimestampRolloverCountersForTesting() {
796   g_last_seen_timestamp_ms = 0;
797   g_rollover_ms = 0;
798 }
799 
800 }  // namespace ui
801