Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(579)

Side by Side Diff: ui/base/x/events_x.cc

Issue 10441028: aura/cros: Rename MessagePump{X => AuraX11} and move the atom cache into it. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 8 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "ui/base/events.h"
6
7 #include <X11/Xlib.h>
8 #include <X11/extensions/XInput.h>
9 #include <X11/extensions/XInput2.h>
10 #include <string.h>
11
12 #include "base/command_line.h"
13 #include "base/logging.h"
14 #include "base/message_pump_x.h"
15 #include "ui/base/keycodes/keyboard_code_conversion_x.h"
16 #include "ui/base/ui_base_switches.h"
17 #include "ui/base/touch/touch_factory.h"
18 #include "ui/base/x/x11_util.h"
19 #include "ui/gfx/point.h"
20 #include "ui/gfx/monitor.h"
21 #include "ui/gfx/rect.h"
22 #include "ui/gfx/screen.h"
23
24 // Copied from xserver-properties.h
25 #define AXIS_LABEL_PROP_REL_HWHEEL "Rel Horiz Wheel"
26 #define AXIS_LABEL_PROP_REL_WHEEL "Rel Vert Wheel"
27
28 // CMT specific timings
29 #define AXIS_LABEL_PROP_ABS_START_TIME "Abs Start Timestamp"
30 #define AXIS_LABEL_PROP_ABS_END_TIME "Abs End Timestamp"
31
32 // Fling properties
33 #define AXIS_LABEL_PROP_ABS_FLING_X "Abs Fling X Velocity"
34 #define AXIS_LABEL_PROP_ABS_FLING_Y "Abs Fling Y Velocity"
35 #define AXIS_LABEL_PROP_ABS_FLING_STATE "Abs Fling State"
36
37 // New versions of the valuators, with double values instead of fixed point.
38 #define AXIS_LABEL_PROP_ABS_DBL_START_TIME "Abs Dbl Start Timestamp"
39 #define AXIS_LABEL_PROP_ABS_DBL_END_TIME "Abs Dbl End Timestamp"
40 #define AXIS_LABEL_PROP_ABS_DBL_FLING_VX "Abs Dbl Fling X Velocity"
41 #define AXIS_LABEL_PROP_ABS_DBL_FLING_VY "Abs Dbl Fling Y Velocity"
42
43 namespace {
44
45 // Scroll amount for each wheelscroll event. 53 is also the value used for GTK+.
46 const int kWheelScrollAmount = 53;
47
48 const int kMinWheelButton = 4;
49 const int kMaxWheelButton = 7;
50
51 // A class to support the detection of scroll events, using X11 valuators.
52 class UI_EXPORT CMTEventData {
53 public:
54 // Returns the ScrollEventData singleton.
55 static CMTEventData* GetInstance() {
56 return Singleton<CMTEventData>::get();
57 }
58
59 // Updates the list of devices.
60 void UpdateDeviceList(Display* display) {
61 cmt_devices_.reset();
62 touchpads_.reset();
63 device_to_valuators_.clear();
64
65 int count = 0;
66
67 // Find all the touchpad devices.
68 XDeviceInfo* dev_list = XListInputDevices(display, &count);
69 Atom xi_touchpad = XInternAtom(display, XI_TOUCHPAD, false);
70 for (int i = 0; i < count; ++i) {
71 XDeviceInfo* dev = dev_list + i;
72 if (dev->type == xi_touchpad)
73 touchpads_[dev_list[i].id] = true;
74 }
75 if (dev_list)
76 XFreeDeviceList(dev_list);
77
78 XIDeviceInfo* info_list = XIQueryDevice(display, XIAllDevices, &count);
79 Atom x_axis = XInternAtom(display, AXIS_LABEL_PROP_REL_HWHEEL, false);
80 Atom y_axis = XInternAtom(display, AXIS_LABEL_PROP_REL_WHEEL, false);
81 Atom start_time =
82 XInternAtom(display, AXIS_LABEL_PROP_ABS_START_TIME, false);
83 Atom start_time_dbl =
84 XInternAtom(display, AXIS_LABEL_PROP_ABS_DBL_START_TIME, false);
85 Atom end_time = XInternAtom(display, AXIS_LABEL_PROP_ABS_END_TIME, false);
86 Atom end_time_dbl =
87 XInternAtom(display, AXIS_LABEL_PROP_ABS_DBL_END_TIME, false);
88 Atom fling_vx = XInternAtom(display, AXIS_LABEL_PROP_ABS_FLING_X, false);
89 Atom fling_vx_dbl =
90 XInternAtom(display, AXIS_LABEL_PROP_ABS_DBL_FLING_VX, false);
91 Atom fling_vy = XInternAtom(display, AXIS_LABEL_PROP_ABS_FLING_Y, false);
92 Atom fling_vy_dbl =
93 XInternAtom(display, AXIS_LABEL_PROP_ABS_DBL_FLING_VY, false);
94 Atom fling_state =
95 XInternAtom(display, AXIS_LABEL_PROP_ABS_FLING_STATE, false);
96
97 for (int i = 0; i < count; ++i) {
98 XIDeviceInfo* info = info_list + i;
99
100 if (info->use != XISlavePointer && info->use != XIFloatingSlave)
101 continue;
102
103 Valuators valuators;
104 bool is_cmt = false;
105 for (int j = 0; j < info->num_classes; ++j) {
106 if (info->classes[j]->type != XIValuatorClass)
107 continue;
108
109 XIValuatorClassInfo* v =
110 reinterpret_cast<XIValuatorClassInfo*>(info->classes[j]);
111 int number = v->number;
112 if (number > valuators.max)
113 valuators.max = number;
114 if (v->label == x_axis) {
115 valuators.scroll_x = number;
116 is_cmt = true;
117 } else if (v->label == y_axis) {
118 valuators.scroll_y = number;
119 is_cmt = true;
120 } else if (v->label == start_time) {
121 valuators.start_time = number;
122 is_cmt = true;
123 } else if (v->label == start_time_dbl) {
124 valuators.start_time_dbl = number;
125 is_cmt = true;
126 } else if (v->label == end_time) {
127 valuators.end_time = number;
128 is_cmt = true;
129 } else if (v->label == end_time_dbl) {
130 valuators.end_time_dbl = number;
131 is_cmt = true;
132 } else if (v->label == fling_vx) {
133 valuators.fling_vx = number;
134 is_cmt = true;
135 } else if (v->label == fling_vx_dbl) {
136 valuators.fling_vx_dbl = number;
137 is_cmt = true;
138 } else if (v->label == fling_vy) {
139 valuators.fling_vy = number;
140 is_cmt = true;
141 } else if (v->label == fling_vy_dbl) {
142 valuators.fling_vy_dbl = number;
143 is_cmt = true;
144 } else if (v->label == fling_state) {
145 valuators.fling_state = number;
146 is_cmt = true;
147 }
148 }
149 if (is_cmt) {
150 // Double valuators override fixed point ones.
151 if (valuators.start_time_dbl >= 0)
152 valuators.start_time = -1;
153 if (valuators.end_time_dbl >= 0)
154 valuators.end_time = -1;
155 if (valuators.fling_vx_dbl >= 0)
156 valuators.fling_vx = -1;
157 if (valuators.fling_vy_dbl >= 0)
158 valuators.fling_vy = -1;
159 device_to_valuators_[info->deviceid] = valuators;
160 cmt_devices_[info->deviceid] = true;
161 }
162 }
163 if (info_list)
164 XIFreeDeviceInfo(info_list);
165 }
166
167 bool natural_scroll_enabled() const { return natural_scroll_enabled_; }
168 void set_natural_scroll_enabled(bool enabled) {
169 natural_scroll_enabled_ = enabled;
170 }
171
172 bool IsTouchpadXInputEvent(const base::NativeEvent& native_event) {
173 if (native_event->type != GenericEvent)
174 return false;
175
176 XIDeviceEvent* xievent =
177 static_cast<XIDeviceEvent*>(native_event->xcookie.data);
178 return touchpads_[xievent->sourceid];
179 }
180
181 float GetNaturalScrollFactor(int deviceid) {
182 // Natural scroll is touchpad-only.
183 if (!touchpads_[deviceid])
184 return -1.0f;
185
186 return natural_scroll_enabled_ ? 1.0f : -1.0f;
187 }
188
189 // Returns true if this is a scroll event (a motion event with the necessary
190 // valuators. Also returns the offsets. |x_offset| and |y_offset| can be
191 // NULL.
192 bool GetScrollOffsets(const XEvent& xev, float* x_offset, float* y_offset) {
193 XIDeviceEvent* xiev = static_cast<XIDeviceEvent*>(xev.xcookie.data);
194
195 if (x_offset)
196 *x_offset = 0;
197 if (y_offset)
198 *y_offset = 0;
199
200 const int deviceid = xiev->deviceid;
201 if (!cmt_devices_[deviceid])
202 return false;
203
204 const float natural_scroll_factor = GetNaturalScrollFactor(deviceid);
205 const Valuators v = device_to_valuators_[deviceid];
206 const bool has_x_offset = XIMaskIsSet(xiev->valuators.mask, v.scroll_x);
207 const bool has_y_offset = XIMaskIsSet(xiev->valuators.mask, v.scroll_y);
208 const bool is_scroll = has_x_offset || has_y_offset;
209
210 if (!is_scroll || (!x_offset && !y_offset))
211 return is_scroll;
212
213 double* valuators = xiev->valuators.values;
214 for (int i = 0; i <= v.max; ++i) {
215 if (XIMaskIsSet(xiev->valuators.mask, i)) {
216 if (x_offset && v.scroll_x == i)
217 *x_offset = *valuators * natural_scroll_factor;
218 else if (y_offset && v.scroll_y == i)
219 *y_offset = *valuators * natural_scroll_factor;
220 valuators++;
221 }
222 }
223
224 return true;
225 }
226
227 bool GetFlingData(const XEvent& xev,
228 float* vx, float* vy,
229 bool* is_cancel) {
230 XIDeviceEvent* xiev = static_cast<XIDeviceEvent*>(xev.xcookie.data);
231
232 *vx = 0;
233 *vy = 0;
234 *is_cancel = false;
235
236 const int deviceid = xiev->deviceid;
237 if (!cmt_devices_[deviceid])
238 return false;
239
240 const float natural_scroll_factor = GetNaturalScrollFactor(deviceid);
241 const Valuators v = device_to_valuators_[deviceid];
242 if ((!XIMaskIsSet(xiev->valuators.mask, v.fling_vx) &&
243 !XIMaskIsSet(xiev->valuators.mask, v.fling_vx_dbl)) ||
244 (!XIMaskIsSet(xiev->valuators.mask, v.fling_vy) &&
245 !XIMaskIsSet(xiev->valuators.mask, v.fling_vy_dbl)) ||
246 !XIMaskIsSet(xiev->valuators.mask, v.fling_state))
247 return false;
248
249 double* valuators = xiev->valuators.values;
250 for (int i = 0; i <= v.max; ++i) {
251 if (XIMaskIsSet(xiev->valuators.mask, i)) {
252 // Convert values to unsigned ints representing ms before storing them,
253 // as that is how they were encoded before conversion to doubles.
254 if (v.fling_vx_dbl == i) {
255 *vx = natural_scroll_factor * *valuators;
256 } else if (v.fling_vx == i) {
257 *vx = natural_scroll_factor *
258 static_cast<double>(static_cast<int>(*valuators)) / 1000.0f;
259 } else if (v.fling_vy_dbl == i) {
260 *vy = natural_scroll_factor * *valuators;
261 } else if (v.fling_vy == i) {
262 *vy = natural_scroll_factor *
263 static_cast<double>(static_cast<int>(*valuators)) / 1000.0f;
264 } else if (v.fling_state == i) {
265 *is_cancel = !!static_cast<unsigned int>(*valuators);
266 }
267 valuators++;
268 }
269 }
270
271 return true;
272 }
273
274 bool GetGestureTimes(const XEvent& xev,
275 double* start_time,
276 double* end_time) {
277 *start_time = 0;
278 *end_time = 0;
279
280 XIDeviceEvent* xiev = static_cast<XIDeviceEvent*>(xev.xcookie.data);
281 if (!cmt_devices_[xiev->deviceid])
282 return false;
283
284 Valuators v = device_to_valuators_[xiev->deviceid];
285 if ((!XIMaskIsSet(xiev->valuators.mask, v.start_time) &&
286 !XIMaskIsSet(xiev->valuators.mask, v.start_time_dbl)) ||
287 (!XIMaskIsSet(xiev->valuators.mask, v.end_time) &&
288 !XIMaskIsSet(xiev->valuators.mask, v.end_time_dbl)))
289 return false;
290
291 double* valuators = xiev->valuators.values;
292 for (int i = 0; i <= v.max; ++i) {
293 if (XIMaskIsSet(xiev->valuators.mask, i)) {
294 if (v.start_time_dbl == i) {
295 *start_time = *valuators;
296 } else if (v.start_time == i) {
297 // Convert values to unsigned ints representing ms before storing
298 // them, as that is how they were encoded before conversion
299 // to doubles.
300 *start_time =
301 static_cast<double>(
302 static_cast<unsigned int>(*valuators)) / 1000;
303 } else if (v.end_time_dbl == i) {
304 *end_time = *valuators;
305 } else if (v.end_time == i) {
306 // Convert values to unsigned ints representing ms before storing
307 // them, as that is how they were encoded before conversion
308 // to doubles.
309 *end_time =
310 static_cast<double>(
311 static_cast<unsigned int>(*valuators)) / 1000;
312 }
313 valuators++;
314 }
315 }
316
317 return true;
318 }
319
320 private:
321 // Requirement for Singleton
322 friend struct DefaultSingletonTraits<CMTEventData>;
323
324 struct Valuators {
325 int max;
326 int scroll_x;
327 int scroll_y;
328 int start_time;
329 int end_time;
330 int fling_vx;
331 int fling_vy;
332 int fling_state;
333 // *_dbl valuators take precedence over the fixed precision versions.
334 int start_time_dbl;
335 int end_time_dbl;
336 int fling_vx_dbl;
337 int fling_vy_dbl;
338
339 Valuators()
340 : max(-1),
341 scroll_x(-1),
342 scroll_y(-1),
343 start_time(-1),
344 end_time(-1),
345 fling_vx(-1),
346 fling_vy(-1),
347 fling_state(-1),
348 start_time_dbl(-1),
349 end_time_dbl(-1),
350 fling_vx_dbl(-1),
351 fling_vy_dbl(-1) {
352 }
353
354 };
355
356 CMTEventData() : natural_scroll_enabled_(false) {
357 UpdateDeviceList(ui::GetXDisplay());
358 }
359
360 ~CMTEventData() {}
361
362 // A quick lookup table for determining if events from the pointer device
363 // should be processed.
364 static const int kMaxDeviceNum = 128;
365 bool natural_scroll_enabled_;
366 std::bitset<kMaxDeviceNum> cmt_devices_;
367 std::bitset<kMaxDeviceNum> touchpads_;
368 std::map<int, Valuators> device_to_valuators_;
369
370 DISALLOW_COPY_AND_ASSIGN(CMTEventData);
371 };
372
373 // A class to track current modifier state on master device. Only track ctrl,
374 // alt, shift and caps lock keys currently. The tracked state can then be used
375 // by floating device.
376 class UI_EXPORT XModifierStateWatcher{
377 public:
378 static XModifierStateWatcher* GetInstance() {
379 return Singleton<XModifierStateWatcher>::get();
380 }
381
382 void UpdateStateFromEvent(const base::NativeEvent& native_event) {
383 // Floating device can't access the modifer state from master device.
384 // We need to track the states of modifier keys in a singleton for
385 // floating devices such as touch screen. Issue 106426 is one example
386 // of why we need the modifier states for floating device.
387 state_ = native_event->xkey.state;
388 // master_state is the state before key press. We need to track the
389 // state after key press for floating device. Currently only ctrl,
390 // shift, alt and caps lock keys are tracked.
391 ui::KeyboardCode keyboard_code = ui::KeyboardCodeFromNative(native_event);
392 unsigned int mask = 0;
393
394 switch (keyboard_code) {
395 case ui::VKEY_CONTROL: {
396 mask = ControlMask;
397 break;
398 }
399 case ui::VKEY_SHIFT: {
400 mask = ShiftMask;
401 break;
402 }
403 case ui::VKEY_MENU: {
404 mask = Mod1Mask;
405 break;
406 }
407 case ui::VKEY_CAPITAL: {
408 mask = LockMask;
409 break;
410 }
411 default:
412 break;
413 }
414
415 if (native_event->type == KeyPress)
416 state_ |= mask;
417 else
418 state_ &= ~mask;
419 }
420
421 // Returns the current modifer state in master device. It only contains the
422 // state of ctrl, shift, alt and caps lock keys.
423 unsigned int state() { return state_; }
424
425 private:
426 friend struct DefaultSingletonTraits<XModifierStateWatcher>;
427
428 XModifierStateWatcher() : state_(0) { }
429
430 unsigned int state_;
431
432 DISALLOW_COPY_AND_ASSIGN(XModifierStateWatcher);
433 };
434
435 int GetEventFlagsFromXState(unsigned int state) {
436 int flags = 0;
437 if (state & ControlMask)
438 flags |= ui::EF_CONTROL_DOWN;
439 if (state & ShiftMask)
440 flags |= ui::EF_SHIFT_DOWN;
441 if (state & Mod1Mask)
442 flags |= ui::EF_ALT_DOWN;
443 if (state & LockMask)
444 flags |= ui::EF_CAPS_LOCK_DOWN;
445 if (state & Button1Mask)
446 flags |= ui::EF_LEFT_MOUSE_BUTTON;
447 if (state & Button2Mask)
448 flags |= ui::EF_MIDDLE_MOUSE_BUTTON;
449 if (state & Button3Mask)
450 flags |= ui::EF_RIGHT_MOUSE_BUTTON;
451 return flags;
452 }
453
454 // Get the event flag for the button in XButtonEvent. During a ButtonPress
455 // event, |state| in XButtonEvent does not include the button that has just been
456 // pressed. Instead |state| contains flags for the buttons (if any) that had
457 // already been pressed before the current button, and |button| stores the most
458 // current pressed button. So, if you press down left mouse button, and while
459 // pressing it down, press down the right mouse button, then for the latter
460 // event, |state| would have Button1Mask set but not Button3Mask, and |button|
461 // would be 3.
462 int GetEventFlagsForButton(int button) {
463 switch (button) {
464 case 1:
465 return ui::EF_LEFT_MOUSE_BUTTON;
466 case 2:
467 return ui::EF_MIDDLE_MOUSE_BUTTON;
468 case 3:
469 return ui::EF_RIGHT_MOUSE_BUTTON;
470 default:
471 return 0;
472 }
473 }
474
475 int GetButtonMaskForX2Event(XIDeviceEvent* xievent) {
476 int buttonflags = 0;
477 for (int i = 0; i < 8 * xievent->buttons.mask_len; i++) {
478 if (XIMaskIsSet(xievent->buttons.mask, i)) {
479 int button = (xievent->sourceid == xievent->deviceid) ?
480 ui::GetMappedButton(i) : i;
481 buttonflags |= GetEventFlagsForButton(button);
482 }
483 }
484 return buttonflags;
485 }
486
487 ui::EventType GetTouchEventType(const base::NativeEvent& native_event) {
488 XIDeviceEvent* event =
489 static_cast<XIDeviceEvent*>(native_event->xcookie.data);
490 #if defined(USE_XI2_MT)
491 switch(event->evtype) {
492 case XI_TouchBegin:
493 return ui::ET_TOUCH_PRESSED;
494 case XI_TouchUpdate:
495 return ui::ET_TOUCH_MOVED;
496 case XI_TouchEnd:
497 return ui::ET_TOUCH_RELEASED;
498 }
499
500 return ui::ET_UNKNOWN;
501 #else
502 ui::TouchFactory* factory = ui::TouchFactory::GetInstance();
503
504 // If this device doesn't support multi-touch, then just use the normal
505 // pressed/release events to indicate touch start/end. With multi-touch,
506 // these events are sent only for the first (pressed) or last (released)
507 // touch point, and so we must infer start/end from motion events.
508 if (!factory->IsMultiTouchDevice(event->sourceid)) {
509 switch (event->evtype) {
510 case XI_ButtonPress:
511 return ui::ET_TOUCH_PRESSED;
512 case XI_ButtonRelease:
513 return ui::ET_TOUCH_RELEASED;
514 case XI_Motion:
515 if (GetButtonMaskForX2Event(event))
516 return ui::ET_TOUCH_MOVED;
517 return ui::ET_UNKNOWN;
518 default:
519 NOTREACHED();
520 }
521 }
522
523 DCHECK_EQ(event->evtype, XI_Motion);
524
525 // Note: We will not generate a _STATIONARY event here. It will be created,
526 // when necessary, by a RWHVV.
527 // TODO(sad): When should _CANCELLED be generated?
528
529 float slot;
530 if (!factory->ExtractTouchParam(*native_event, ui::TouchFactory::TP_SLOT_ID,
531 &slot))
532 return ui::ET_UNKNOWN;
533
534 if (!factory->IsSlotUsed(slot)) {
535 // This is a new touch point.
536 return ui::ET_TOUCH_PRESSED;
537 }
538
539 float tracking;
540 if (!factory->ExtractTouchParam(*native_event,
541 ui::TouchFactory::TP_TRACKING_ID, &tracking))
542 return ui::ET_UNKNOWN;
543
544 if (tracking == 0l) {
545 // The touch point has been released.
546 return ui::ET_TOUCH_RELEASED;
547 }
548
549 return ui::ET_TOUCH_MOVED;
550 #endif // defined(USE_XI2_MT)
551 }
552
553 float GetTouchParamFromXEvent(XEvent* xev,
554 ui::TouchFactory::TouchParam tp,
555 float default_value) {
556 ui::TouchFactory::GetInstance()->ExtractTouchParam(*xev, tp, &default_value);
557 return default_value;
558 }
559
560 Atom GetNoopEventAtom() {
561 return XInternAtom(
562 base::MessagePumpX::GetDefaultXDisplay(),
563 "noop", False);
564 }
565
566 #if defined(USE_XI2_MT)
567 gfx::Point CalibrateTouchCoordinates(
568 const XIDeviceEvent* xievent) {
569 int x = static_cast<int>(xievent->event_x);
570 int y = static_cast<int>(xievent->event_y);
571 if (!CommandLine::ForCurrentProcess()->HasSwitch(
572 switches::kEnableTouchCalibration))
573 return gfx::Point(x, y);
574 // TODO(skuhne): Find a new home for these hardware dependent touch
575 // constants.
576 // Note: These values have been found to be correct for the device I was
577 // testing with. I have the feeling that the DPI resolution of the bezel is
578 // less then the dpi resolution over the visible part - which would explain
579 // why the small value (50) is so wide compared to the entire area.
580 gfx::Rect bounds = gfx::Screen::GetPrimaryMonitor().bounds_in_pixel();
581 const int kLeftBorder = 50;
582 const int kRightBorder = 50;
583 const int kBottomBorder = 50;
584 const int kTopBorder = 0;
585 const int resolution_x = bounds.width();
586 const int resolution_y = bounds.height();
587 // The "grace area" (10% in this case) is to make it easier for the user to
588 // navigate to the corner.
589 const double kGraceAreaFraction = 0.1;
590 // Offset the x position to the real
591 x -= kLeftBorder;
592 // Check if we are in the grace area of the left side.
593 // Note: We might not want to do this when the gesture is locked?
594 if (x < 0 && x > -kLeftBorder * kGraceAreaFraction)
595 x = 0;
596 // Check if we are in the grace area of the right side.
597 // Note: We might not want to do this when the gesture is locked?
598 if (x > resolution_x - kLeftBorder &&
599 x < resolution_x - kLeftBorder + kRightBorder * kGraceAreaFraction)
600 x = resolution_x - kLeftBorder;
601 // Scale the screen area back to the full resolution of the screen.
602 x = (x * resolution_x) / (resolution_x - (kRightBorder + kLeftBorder));
603 // Offset the y position to the real
604 y -= kTopBorder;
605 // Check if we are in the grace area of the left side.
606 // Note: We might not want to do this when the gesture is locked?
607 if (y < 0 && y > -kTopBorder * kGraceAreaFraction)
608 y = 0;
609 // Check if we are in the grace area of the right side.
610 // Note: We might not want to do this when the gesture is locked?
611 if (y > resolution_y - kTopBorder &&
612 y < resolution_y - kTopBorder + kBottomBorder * kGraceAreaFraction)
613 y = resolution_y - kTopBorder;
614 // Scale the screen area back to the full resolution of the screen.
615 y = (y * resolution_y) / (resolution_y - (kBottomBorder + kTopBorder));
616 // Set the modified coordinate back to the event.
617 return gfx::Point(x, y);
618 }
619 #endif // defined(USE_XI2_MT)
620
621 } // namespace
622
623 namespace ui {
624
625 void UpdateDeviceList() {
626 Display* display = GetXDisplay();
627 CMTEventData::GetInstance()->UpdateDeviceList(display);
628 TouchFactory::GetInstance()->UpdateDeviceList(display);
629 }
630
631 EventType EventTypeFromNative(const base::NativeEvent& native_event) {
632 switch (native_event->type) {
633 case KeyPress:
634 return ET_KEY_PRESSED;
635 case KeyRelease:
636 return ET_KEY_RELEASED;
637 case ButtonPress:
638 if (static_cast<int>(native_event->xbutton.button) >= kMinWheelButton &&
639 static_cast<int>(native_event->xbutton.button) <= kMaxWheelButton)
640 return ET_MOUSEWHEEL;
641 return ET_MOUSE_PRESSED;
642 case ButtonRelease:
643 // Drop wheel events; we should've already scrolled on the press.
644 if (static_cast<int>(native_event->xbutton.button) >= kMinWheelButton &&
645 static_cast<int>(native_event->xbutton.button) <= kMaxWheelButton)
646 return ET_UNKNOWN;
647 return ET_MOUSE_RELEASED;
648 case MotionNotify:
649 if (native_event->xmotion.state &
650 (Button1Mask | Button2Mask | Button3Mask))
651 return ET_MOUSE_DRAGGED;
652 return ET_MOUSE_MOVED;
653 case EnterNotify:
654 return ET_MOUSE_ENTERED;
655 case LeaveNotify:
656 return ET_MOUSE_EXITED;
657 case GenericEvent: {
658 TouchFactory* factory = TouchFactory::GetInstance();
659 if (!factory->ShouldProcessXI2Event(native_event))
660 return ET_UNKNOWN;
661
662 XIDeviceEvent* xievent =
663 static_cast<XIDeviceEvent*>(native_event->xcookie.data);
664
665 if (factory->IsTouchDevice(xievent->sourceid))
666 return GetTouchEventType(native_event);
667
668 switch (xievent->evtype) {
669 case XI_ButtonPress: {
670 int button = EventButtonFromNative(native_event);
671 if (button >= kMinWheelButton && button <= kMaxWheelButton)
672 return ET_MOUSEWHEEL;
673 return ET_MOUSE_PRESSED;
674 }
675 case XI_ButtonRelease: {
676 int button = EventButtonFromNative(native_event);
677 // Drop wheel events; we should've already scrolled on the press.
678 if (button >= kMinWheelButton && button <= kMaxWheelButton)
679 return ET_UNKNOWN;
680 return ET_MOUSE_RELEASED;
681 }
682 case XI_Motion: {
683 float vx, vy;
684 bool is_cancel;
685 if (GetFlingData(native_event, &vx, &vy, &is_cancel)) {
686 return is_cancel ? ET_SCROLL_FLING_CANCEL : ET_SCROLL_FLING_START;
687 } else if (GetScrollOffsets(native_event, NULL, NULL))
688 return ET_SCROLL;
689 else if (GetButtonMaskForX2Event(xievent)) {
690 return ET_MOUSE_DRAGGED;
691 } else
692 return ET_MOUSE_MOVED;
693 }
694 }
695 }
696 default:
697 break;
698 }
699 return ET_UNKNOWN;
700 }
701
702 int EventFlagsFromNative(const base::NativeEvent& native_event) {
703 switch (native_event->type) {
704 case KeyPress:
705 case KeyRelease: {
706 XModifierStateWatcher::GetInstance()->UpdateStateFromEvent(native_event);
707 return GetEventFlagsFromXState(native_event->xkey.state);
708 }
709 case ButtonPress:
710 case ButtonRelease: {
711 int flags = GetEventFlagsFromXState(native_event->xbutton.state);
712 const EventType type = EventTypeFromNative(native_event);
713 if (type == ET_MOUSE_PRESSED || type == ET_MOUSE_RELEASED)
714 flags |= GetEventFlagsForButton(native_event->xbutton.button);
715 return flags;
716 }
717 case MotionNotify:
718 return GetEventFlagsFromXState(native_event->xmotion.state);
719 case GenericEvent: {
720 XIDeviceEvent* xievent =
721 static_cast<XIDeviceEvent*>(native_event->xcookie.data);
722
723 const bool touch =
724 TouchFactory::GetInstance()->IsTouchDevice(xievent->sourceid);
725 switch (xievent->evtype) {
726 case XI_ButtonPress:
727 case XI_ButtonRelease: {
728 int flags = GetButtonMaskForX2Event(xievent) |
729 GetEventFlagsFromXState(xievent->mods.effective);
730 if (touch) {
731 flags |= GetEventFlagsFromXState(
732 XModifierStateWatcher::GetInstance()->state());
733 }
734
735 const EventType type = EventTypeFromNative(native_event);
736 int button = EventButtonFromNative(native_event);
737 if ((type == ET_MOUSE_PRESSED || type == ET_MOUSE_RELEASED) && !touch)
738 flags |= GetEventFlagsForButton(button);
739 return flags;
740 }
741 case XI_Motion:
742 return GetButtonMaskForX2Event(xievent) |
743 GetEventFlagsFromXState(xievent->mods.effective);
744 }
745 }
746 }
747 return 0;
748 }
749
750 base::TimeDelta EventTimeFromNative(const base::NativeEvent& native_event) {
751 switch(native_event->type) {
752 case KeyPress:
753 case KeyRelease:
754 return base::TimeDelta::FromMilliseconds(native_event->xkey.time);
755 case ButtonPress:
756 case ButtonRelease:
757 return base::TimeDelta::FromMilliseconds(native_event->xbutton.time);
758 break;
759 case MotionNotify:
760 return base::TimeDelta::FromMilliseconds(native_event->xmotion.time);
761 break;
762 case GenericEvent: {
763 double start, end;
764 if (GetGestureTimes(native_event, &start, &end)) {
765 // If the driver supports gesture times, use them.
766 return base::TimeDelta::FromMicroseconds(end * 1000000);
767 } else {
768 XIDeviceEvent* xide =
769 static_cast<XIDeviceEvent*>(native_event->xcookie.data);
770 return base::TimeDelta::FromMilliseconds(xide->time);
771 }
772 break;
773 }
774 }
775 NOTREACHED();
776 return base::TimeDelta();
777 }
778
779 gfx::Point EventLocationFromNative(const base::NativeEvent& native_event) {
780 switch (native_event->type) {
781 case ButtonPress:
782 case ButtonRelease:
783 return gfx::Point(native_event->xbutton.x, native_event->xbutton.y);
784 case MotionNotify:
785 return gfx::Point(native_event->xmotion.x, native_event->xmotion.y);
786 case GenericEvent: {
787 XIDeviceEvent* xievent =
788 static_cast<XIDeviceEvent*>(native_event->xcookie.data);
789
790 #if defined(USE_XI2_MT)
791 // Touch event valuators aren't coordinates.
792 // Return the |event_x|/|event_y| directly as event's position.
793 if (xievent->evtype == XI_TouchBegin ||
794 xievent->evtype == XI_TouchUpdate ||
795 xievent->evtype == XI_TouchEnd)
796 // Note: Touch events are always touch screen events.
797 return CalibrateTouchCoordinates(xievent);
798 #endif
799 // Read the position from the valuators, because the location reported in
800 // event_x/event_y seems to be different (and doesn't match for events
801 // coming from slave device and master device) from the values in the
802 // valuators. See more on crbug.com/103981. The position in the valuators
803 // is in the global screen coordinates. But it is necessary to convert it
804 // into the window's coordinates. If the valuator is not set, that means
805 // the value hasn't changed, and so we can use the value from
806 // event_x/event_y (which are in the window's coordinates).
807 double* valuators = xievent->valuators.values;
808
809 double x = xievent->event_x;
810 if (XIMaskIsSet(xievent->valuators.mask, 0))
811 x = *valuators++ - (xievent->root_x - xievent->event_x);
812
813 double y = xievent->event_y;
814 if (XIMaskIsSet(xievent->valuators.mask, 1))
815 y = *valuators++ - (xievent->root_y - xievent->event_y);
816
817 return gfx::Point(static_cast<int>(x), static_cast<int>(y));
818 }
819 }
820 return gfx::Point();
821 }
822
823 int EventButtonFromNative(const base::NativeEvent& native_event) {
824 CHECK_EQ(GenericEvent, native_event->type);
825 XIDeviceEvent* xievent =
826 static_cast<XIDeviceEvent*>(native_event->xcookie.data);
827 int button = xievent->detail;
828
829 return (xievent->sourceid == xievent->deviceid) ?
830 ui::GetMappedButton(button) : button;
831 }
832
833 KeyboardCode KeyboardCodeFromNative(const base::NativeEvent& native_event) {
834 return KeyboardCodeFromXKeyEvent(native_event);
835 }
836
837 bool IsMouseEvent(const base::NativeEvent& native_event) {
838 if (native_event->type == ButtonPress ||
839 native_event->type == ButtonRelease ||
840 native_event->type == MotionNotify)
841 return true;
842 if (native_event->type == GenericEvent) {
843 XIDeviceEvent* xievent =
844 static_cast<XIDeviceEvent*>(native_event->xcookie.data);
845 return xievent->evtype == XI_ButtonPress ||
846 xievent->evtype == XI_ButtonRelease ||
847 xievent->evtype == XI_Motion;
848 }
849 return false;
850 }
851
852 int GetMouseWheelOffset(const base::NativeEvent& native_event) {
853 int button = native_event->type == GenericEvent
854 ? EventButtonFromNative(native_event) : native_event->xbutton.button;
855
856 switch (button) {
857 case 4:
858 return kWheelScrollAmount;
859 case 5:
860 return -kWheelScrollAmount;
861 default:
862 // TODO(derat): Do something for horizontal scrolls (buttons 6 and 7)?
863 return 0;
864 }
865 }
866
867 int GetTouchId(const base::NativeEvent& xev) {
868 float slot = 0;
869 ui::TouchFactory* factory = ui::TouchFactory::GetInstance();
870 XIDeviceEvent* xievent = static_cast<XIDeviceEvent*>(xev->xcookie.data);
871 if (!factory->IsMultiTouchDevice(xievent->sourceid)) {
872 // TODO(sad): Come up with a way to generate touch-ids for multi-touch
873 // events when touch-events are generated from a single-touch device.
874 return slot;
875 }
876
877 #if defined(USE_XI2_MT)
878 float tracking_id;
879 if (!factory->ExtractTouchParam(
880 *xev, ui::TouchFactory::TP_TRACKING_ID, &tracking_id)) {
881 LOG(ERROR) << "Could not get the slot ID for the event. Using 0.";
882 } else {
883 slot = factory->GetSlotForTrackingID(tracking_id);
884 ui::EventType type = ui::EventTypeFromNative(xev);
885 if (type == ui::ET_TOUCH_CANCELLED ||
886 type == ui::ET_TOUCH_RELEASED) {
887 factory->ReleaseSlotForTrackingID(tracking_id);
888 }
889 }
890 #else
891 if (!factory->ExtractTouchParam(
892 *xev, ui::TouchFactory::TP_SLOT_ID, &slot))
893 LOG(ERROR) << "Could not get the slot ID for the event. Using 0.";
894 #endif
895 return slot;
896 }
897
898 float GetTouchRadiusX(const base::NativeEvent& native_event) {
899 return GetTouchParamFromXEvent(native_event,
900 ui::TouchFactory::TP_TOUCH_MAJOR, 0.0) / 2.0;
901 }
902
903 float GetTouchRadiusY(const base::NativeEvent& native_event) {
904 return GetTouchParamFromXEvent(native_event,
905 ui::TouchFactory::TP_TOUCH_MINOR, 0.0) / 2.0;
906 }
907
908 float GetTouchAngle(const base::NativeEvent& native_event) {
909 return GetTouchParamFromXEvent(native_event,
910 ui::TouchFactory::TP_ORIENTATION, 0.0) / 2.0;
911 }
912
913 float GetTouchForce(const base::NativeEvent& native_event) {
914 float force = 0.0;
915 force = GetTouchParamFromXEvent(native_event, ui::TouchFactory::TP_PRESSURE,
916 0.0);
917 unsigned int deviceid =
918 static_cast<XIDeviceEvent*>(native_event->xcookie.data)->sourceid;
919 // Force is normalized to fall into [0, 1]
920 if (!ui::TouchFactory::GetInstance()->NormalizeTouchParam(
921 deviceid, ui::TouchFactory::TP_PRESSURE, &force))
922 force = 0.0;
923 return force;
924 }
925
926 bool GetScrollOffsets(const base::NativeEvent& native_event,
927 float* x_offset,
928 float* y_offset) {
929 return CMTEventData::GetInstance()->GetScrollOffsets(
930 *native_event, x_offset, y_offset);
931 }
932
933 bool GetFlingData(const base::NativeEvent& native_event,
934 float* vx,
935 float* vy,
936 bool* is_cancel) {
937 return CMTEventData::GetInstance()->GetFlingData(
938 *native_event, vx, vy, is_cancel);
939 }
940
941 bool GetGestureTimes(const base::NativeEvent& native_event,
942 double* start_time,
943 double* end_time) {
944 return CMTEventData::GetInstance()->GetGestureTimes(
945 *native_event, start_time, end_time);
946 }
947
948 void SetNaturalScroll(bool enabled) {
949 CMTEventData::GetInstance()->set_natural_scroll_enabled(enabled);
950 }
951
952 bool IsNaturalScrollEnabled() {
953 return CMTEventData::GetInstance()->natural_scroll_enabled();
954 }
955
956 bool IsTouchpadEvent(const base::NativeEvent& event) {
957 return CMTEventData::GetInstance()->IsTouchpadXInputEvent(event);
958 }
959
960 bool IsNoopEvent(const base::NativeEvent& event) {
961 return (event->type == ClientMessage &&
962 event->xclient.message_type == GetNoopEventAtom());
963 }
964
965 base::NativeEvent CreateNoopEvent() {
966 static XEvent* noop = NULL;
967 if (!noop) {
968 noop = new XEvent();
969 memset(noop, 0, sizeof(XEvent));
970 noop->xclient.type = ClientMessage;
971 noop->xclient.window = None;
972 noop->xclient.format = 8;
973 DCHECK(!noop->xclient.display);
974 }
975 // Make sure we use atom from current xdisplay, which may
976 // change during the test.
977 noop->xclient.message_type = GetNoopEventAtom();
978 return noop;
979 }
980
981 } // namespace ui
OLDNEW
« base/base.gypi ('K') | « ui/base/x/events_aurax11.cc ('k') | ui/ui.gyp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698