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(×tamp);
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