OLD | NEW |
---|---|
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "ui/base/events.h" | 5 #include "ui/base/events.h" |
6 | 6 |
7 #include <X11/Xlib.h> | 7 #include <X11/Xlib.h> |
8 #include <X11/extensions/XInput.h> | |
8 #include <X11/extensions/XInput2.h> | 9 #include <X11/extensions/XInput2.h> |
9 #include <string.h> | 10 #include <string.h> |
10 | 11 |
11 #include "base/logging.h" | 12 #include "base/logging.h" |
12 #include "ui/base/keycodes/keyboard_code_conversion_x.h" | 13 #include "ui/base/keycodes/keyboard_code_conversion_x.h" |
13 #include "ui/base/touch/touch_factory.h" | 14 #include "ui/base/touch/touch_factory.h" |
14 #include "ui/base/x/x11_util.h" | 15 #include "ui/base/x/x11_util.h" |
15 #include "ui/gfx/point.h" | 16 #include "ui/gfx/point.h" |
16 | 17 |
17 #if !defined(TOOLKIT_USES_GTK) | 18 #if !defined(TOOLKIT_USES_GTK) |
18 #include "base/message_pump_x.h" | 19 #include "base/message_pump_x.h" |
19 #endif | 20 #endif |
20 | 21 |
22 // Copied from xserver-properties.h | |
23 #define AXIS_LABEL_PROP_REL_HWHEEL "Rel Horiz Wheel" | |
Daniel Erat
2011/12/14 21:49:07
nit: just one space between symbol name and string
DaveMoore
2011/12/15 17:07:21
Done.
| |
24 #define AXIS_LABEL_PROP_REL_WHEEL "Rel Vert Wheel" | |
25 | |
21 namespace { | 26 namespace { |
22 | 27 |
23 // Scroll amount for each wheelscroll event. 53 is also the value used for GTK+. | 28 // Scroll amount for each wheelscroll event. 53 is also the value used for GTK+. |
24 static const int kWheelScrollAmount = 53; | 29 static const int kWheelScrollAmount = 53; |
25 | 30 |
26 static const int kMinWheelButton = 4; | 31 static const int kMinWheelButton = 4; |
27 #if defined(OS_CHROMEOS) | 32 #if defined(OS_CHROMEOS) |
28 // TODO(davemoore) For now use the button to decide how much to scroll by. | 33 // TODO(davemoore) For now use the button to decide how much to scroll by. |
29 // When we go to XI2 scroll events this won't be necessary. If this doesn't | 34 // When we go to XI2 scroll events this won't be necessary. If this doesn't |
30 // happen for some reason we can better detect which devices are touchpads. | 35 // happen for some reason we can better detect which devices are touchpads. |
31 static const int kTouchpadScrollAmount = 3; | 36 static const int kTouchpadScrollAmount = 3; |
32 // Chrome OS also uses buttons 8 and 9 for scrolling. | 37 // Chrome OS also uses buttons 8 and 9 for scrolling. |
33 static const int kMaxWheelButton = 9; | 38 static const int kMaxWheelButton = 9; |
34 #else | 39 #else |
35 static const int kMaxWheelButton = 7; | 40 static const int kMaxWheelButton = 7; |
36 #endif | 41 #endif |
37 | 42 |
43 // A class to support the detection of scroll events, using X11 valuators. | |
44 class UI_EXPORT ScrollEventData { | |
45 public: | |
46 // Returns the ScrollEventData singleton. | |
47 static ScrollEventData* GetInstance() { | |
48 return Singleton<ScrollEventData>::get(); | |
49 } | |
50 | |
51 // Updates the list of devices. | |
52 void UpdateDeviceList(Display* display) { | |
53 int count; | |
Daniel Erat
2011/12/14 21:49:07
nit: initialize to 0
DaveMoore
2011/12/15 17:07:21
Done.
| |
54 scroll_devices_.reset(); | |
55 device_to_valuators_.clear(); | |
56 XDeviceInfo* dev_list = XListInputDevices(display, &count); | |
57 Atom xi_touchpad = XInternAtom(display, XI_TOUCHPAD, false); | |
58 for (int i = 0; i < count; ++i) { | |
59 XDeviceInfo* dev = dev_list + i; | |
60 if (dev->type == xi_touchpad) | |
61 scroll_devices_[dev_list[i].id] = true; | |
62 } | |
63 if (dev_list) | |
64 XFreeDeviceList(dev_list); | |
65 | |
66 XIDeviceInfo* info_list = XIQueryDevice(display, XIAllDevices, &count); | |
67 Atom x_axis = XInternAtom(display, AXIS_LABEL_PROP_REL_HWHEEL, false); | |
68 Atom y_axis = XInternAtom(display, AXIS_LABEL_PROP_REL_WHEEL, false); | |
69 for (int i = 0; i < count; ++i) { | |
70 XIDeviceInfo* info = info_list + i; | |
71 | |
72 if (!scroll_devices_[info->deviceid]) | |
73 continue; | |
74 | |
75 if (info->use != XISlavePointer && info->use != XIFloatingSlave) { | |
76 scroll_devices_[info->deviceid] = false; | |
77 continue; | |
78 } | |
79 | |
80 Valuators valuators = {-1, -1}; | |
81 for (int j = 0; j < info->num_classes; ++j) { | |
82 if (info->classes[j]->type != XIValuatorClass) | |
83 continue; | |
84 | |
85 XIValuatorClassInfo* v = | |
86 reinterpret_cast<XIValuatorClassInfo*>(info->classes[j]); | |
87 if (v->label == x_axis) | |
88 valuators.x_scroll = v->number; | |
89 else if (v->label == y_axis) | |
90 valuators.y_scroll = v->number; | |
91 } | |
92 if (valuators.x_scroll >= 0 && valuators.y_scroll >= 0) | |
93 device_to_valuators_[info->deviceid] = valuators; | |
94 else | |
95 scroll_devices_[info->deviceid] = false; | |
96 } | |
97 } | |
98 | |
99 // Returns true if this is a scroll event (a motion event with the necessary | |
100 // valuators. Also returns the offsets. |x_offset| and |y_offset| can be | |
Daniel Erat
2011/12/14 21:49:07
nit: add ')' after 'valuators'
either initialize
DaveMoore
2011/12/15 17:07:21
Done.
| |
101 // NULL. | |
102 bool GetScrollOffsets(const XEvent& xev, float* x_offset, float* y_offset) { | |
103 XIDeviceEvent* xiev = static_cast<XIDeviceEvent*>(xev.xcookie.data); | |
104 if (!scroll_devices_[xiev->deviceid]) | |
105 return false; | |
106 | |
107 int x_scroll = device_to_valuators_[xiev->deviceid].x_scroll; | |
108 int y_scroll = device_to_valuators_[xiev->deviceid].y_scroll; | |
109 | |
110 bool has_x_offset = XIMaskIsSet(xiev->valuators.mask, x_scroll); | |
111 bool has_y_offset = XIMaskIsSet(xiev->valuators.mask, y_scroll); | |
112 bool is_scroll = has_x_offset || has_y_offset; | |
113 | |
114 if (!x_offset && !y_offset) | |
115 return is_scroll; | |
116 | |
117 double* valuators = xiev->valuators.values; | |
118 for (int i = 0; i < xiev->valuators.mask_len * 8; ++i) { | |
119 if (XIMaskIsSet(xiev->valuators.mask, i)) { | |
120 if (x_offset && x_scroll == i) | |
121 *x_offset = -(*valuators); | |
122 else if (y_offset && y_scroll == i) | |
123 *y_offset = -(*valuators); | |
124 valuators++; | |
125 } | |
126 } | |
127 | |
128 return is_scroll; | |
129 } | |
130 | |
131 private: | |
132 // Requirement for Singleton | |
133 friend struct DefaultSingletonTraits<ScrollEventData>; | |
134 | |
135 struct Valuators { | |
136 int x_scroll; | |
137 int y_scroll; | |
138 }; | |
139 | |
140 ScrollEventData() { | |
141 UpdateDeviceList(ui::GetXDisplay()); | |
142 } | |
143 | |
144 ~ScrollEventData() {} | |
145 | |
146 // A quick lookup table for determining if events from the pointer device | |
147 // should be processed. | |
148 static const int kMaxDeviceNum = 128; | |
149 std::bitset<kMaxDeviceNum> scroll_devices_; | |
150 std::map<int, Valuators> device_to_valuators_; | |
151 | |
152 DISALLOW_COPY_AND_ASSIGN(ScrollEventData); | |
153 }; | |
154 | |
38 int GetEventFlagsFromXState(unsigned int state) { | 155 int GetEventFlagsFromXState(unsigned int state) { |
39 int flags = 0; | 156 int flags = 0; |
40 if (state & ControlMask) | 157 if (state & ControlMask) |
41 flags |= ui::EF_CONTROL_DOWN; | 158 flags |= ui::EF_CONTROL_DOWN; |
42 if (state & ShiftMask) | 159 if (state & ShiftMask) |
43 flags |= ui::EF_SHIFT_DOWN; | 160 flags |= ui::EF_SHIFT_DOWN; |
44 if (state & Mod1Mask) | 161 if (state & Mod1Mask) |
45 flags |= ui::EF_ALT_DOWN; | 162 flags |= ui::EF_ALT_DOWN; |
46 if (state & LockMask) | 163 if (state & LockMask) |
47 flags |= ui::EF_CAPS_LOCK_DOWN; | 164 flags |= ui::EF_CAPS_LOCK_DOWN; |
(...skipping 137 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
185 return ET_MOUSE_MOVED; | 302 return ET_MOUSE_MOVED; |
186 case EnterNotify: | 303 case EnterNotify: |
187 return ET_MOUSE_ENTERED; | 304 return ET_MOUSE_ENTERED; |
188 case LeaveNotify: | 305 case LeaveNotify: |
189 return ET_MOUSE_EXITED; | 306 return ET_MOUSE_EXITED; |
190 case GenericEvent: { | 307 case GenericEvent: { |
191 XIDeviceEvent* xievent = | 308 XIDeviceEvent* xievent = |
192 static_cast<XIDeviceEvent*>(native_event->xcookie.data); | 309 static_cast<XIDeviceEvent*>(native_event->xcookie.data); |
193 if (TouchFactory::GetInstance()->IsTouchDevice(xievent->sourceid)) | 310 if (TouchFactory::GetInstance()->IsTouchDevice(xievent->sourceid)) |
194 return GetTouchEventType(native_event); | 311 return GetTouchEventType(native_event); |
195 int button = EventButtonFromNative(native_event); | |
196 switch (xievent->evtype) { | 312 switch (xievent->evtype) { |
197 case XI_ButtonPress: | 313 case XI_ButtonPress: |
198 if (button >= kMinWheelButton && | 314 case XI_ButtonRelease: { |
199 button <= kMaxWheelButton) | 315 int button = EventButtonFromNative(native_event); |
316 if (button >= kMinWheelButton && button <= kMaxWheelButton) | |
200 return ET_MOUSEWHEEL; | 317 return ET_MOUSEWHEEL; |
201 return ET_MOUSE_PRESSED; | 318 return xievent->evtype == XI_ButtonPress ? |
202 case XI_ButtonRelease: | 319 ET_MOUSE_PRESSED : ET_MOUSE_RELEASED; |
203 if (button >= kMinWheelButton && | 320 } |
204 button <= kMaxWheelButton) | |
205 return ET_MOUSEWHEEL; | |
206 return ET_MOUSE_RELEASED; | |
207 case XI_Motion: | 321 case XI_Motion: |
208 return GetButtonMaskForX2Event(xievent) ? | 322 if (GetScrollOffsets(native_event, NULL, NULL)) |
209 ET_MOUSE_DRAGGED : ET_MOUSE_MOVED; | 323 return ET_SCROLL; |
324 else if (GetButtonMaskForX2Event(xievent)) | |
325 return ET_MOUSE_DRAGGED; | |
326 else | |
327 return ET_MOUSE_MOVED; | |
210 } | 328 } |
211 } | 329 } |
212 default: | 330 default: |
213 break; | 331 break; |
214 } | 332 } |
215 return ET_UNKNOWN; | 333 return ET_UNKNOWN; |
216 } | 334 } |
217 | 335 |
218 int EventFlagsFromNative(const base::NativeEvent& native_event) { | 336 int EventFlagsFromNative(const base::NativeEvent& native_event) { |
219 switch (native_event->type) { | 337 switch (native_event->type) { |
(...skipping 178 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
398 0.0); | 516 0.0); |
399 unsigned int deviceid = | 517 unsigned int deviceid = |
400 static_cast<XIDeviceEvent*>(native_event->xcookie.data)->sourceid; | 518 static_cast<XIDeviceEvent*>(native_event->xcookie.data)->sourceid; |
401 // Force is normalized to fall into [0, 1] | 519 // Force is normalized to fall into [0, 1] |
402 if (!ui::TouchFactory::GetInstance()->NormalizeTouchParam( | 520 if (!ui::TouchFactory::GetInstance()->NormalizeTouchParam( |
403 deviceid, ui::TouchFactory::TP_PRESSURE, &force)) | 521 deviceid, ui::TouchFactory::TP_PRESSURE, &force)) |
404 force = 0.0; | 522 force = 0.0; |
405 return force; | 523 return force; |
406 } | 524 } |
407 | 525 |
526 bool GetScrollOffsets(const base::NativeEvent& native_event, | |
527 float* x_offset, | |
528 float* y_offset) { | |
529 return ScrollEventData::GetInstance()->GetScrollOffsets( | |
530 *native_event, x_offset, y_offset); | |
531 } | |
532 | |
533 void UpdateDeviceList() { | |
534 Display* display = GetXDisplay(); | |
535 ScrollEventData::GetInstance()->UpdateDeviceList(display); | |
536 TouchFactory::GetInstance()->UpdateDeviceList(display); | |
537 } | |
538 | |
408 base::NativeEvent CreateNoopEvent() { | 539 base::NativeEvent CreateNoopEvent() { |
409 static XEvent* noop = NULL; | 540 static XEvent* noop = NULL; |
410 if (!noop) { | 541 if (!noop) { |
411 noop = new XEvent(); | 542 noop = new XEvent(); |
412 memset(noop, 0, sizeof(XEvent)); | 543 memset(noop, 0, sizeof(XEvent)); |
413 noop->xclient.type = ClientMessage; | 544 noop->xclient.type = ClientMessage; |
414 noop->xclient.window = None; | 545 noop->xclient.window = None; |
415 noop->xclient.format = 8; | 546 noop->xclient.format = 8; |
416 DCHECK(!noop->xclient.display); | 547 DCHECK(!noop->xclient.display); |
417 } | 548 } |
418 // TODO(oshima): Remove ifdef once gtk is removed from views. | 549 // TODO(oshima): Remove ifdef once gtk is removed from views. |
419 #if defined(TOOLKIT_USES_GTK) | 550 #if defined(TOOLKIT_USES_GTK) |
420 NOTREACHED(); | 551 NOTREACHED(); |
421 #else | 552 #else |
422 // Make sure we use atom from current xdisplay, which may | 553 // Make sure we use atom from current xdisplay, which may |
423 // change during the test. | 554 // change during the test. |
424 noop->xclient.message_type = XInternAtom( | 555 noop->xclient.message_type = XInternAtom( |
425 base::MessagePumpX::GetDefaultXDisplay(), | 556 base::MessagePumpX::GetDefaultXDisplay(), |
426 "noop", False); | 557 "noop", False); |
427 #endif | 558 #endif |
428 return noop; | 559 return noop; |
429 } | 560 } |
430 | 561 |
431 } // namespace ui | 562 } // namespace ui |
OLD | NEW |