1 // Copyright 2013 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/test/events_test_utils_x11.h"
6
7 #include <X11/extensions/XI2.h>
8 #include <X11/keysym.h>
9 #include <X11/X.h>
10 #include <X11/Xlib.h>
11
12 #include "base/logging.h"
13 #include "ui/events/event_constants.h"
14 #include "ui/events/event_utils.h"
15 #include "ui/events/keycodes/keyboard_code_conversion_x.h"
16 #include "ui/events/x/touch_factory_x11.h"
17
18 namespace {
19
20 // Converts ui::EventType to state for X*Events.
XEventState(int flags)21 unsigned int XEventState(int flags) {
22 return
23 ((flags & ui::EF_SHIFT_DOWN) ? ShiftMask : 0) |
24 ((flags & ui::EF_CONTROL_DOWN) ? ControlMask : 0) |
25 ((flags & ui::EF_ALT_DOWN) ? Mod1Mask : 0) |
26 ((flags & ui::EF_CAPS_LOCK_DOWN) ? LockMask : 0) |
27 ((flags & ui::EF_ALTGR_DOWN) ? Mod5Mask : 0) |
28 ((flags & ui::EF_COMMAND_DOWN) ? Mod4Mask : 0) |
29 ((flags & ui::EF_MOD3_DOWN) ? Mod3Mask : 0) |
30 ((flags & ui::EF_NUMPAD_KEY) ? Mod2Mask : 0) |
31 ((flags & ui::EF_LEFT_MOUSE_BUTTON) ? Button1Mask: 0) |
32 ((flags & ui::EF_MIDDLE_MOUSE_BUTTON) ? Button2Mask: 0) |
33 ((flags & ui::EF_RIGHT_MOUSE_BUTTON) ? Button3Mask: 0);
34 }
35
36 // Converts EventType to XKeyEvent type.
XKeyEventType(ui::EventType type)37 int XKeyEventType(ui::EventType type) {
38 switch (type) {
39 case ui::ET_KEY_PRESSED:
40 return KeyPress;
41 case ui::ET_KEY_RELEASED:
42 return KeyRelease;
43 default:
44 return 0;
45 }
46 }
47
48 // Converts EventType to XI2 event type.
XIKeyEventType(ui::EventType type)49 int XIKeyEventType(ui::EventType type) {
50 switch (type) {
51 case ui::ET_KEY_PRESSED:
52 return XI_KeyPress;
53 case ui::ET_KEY_RELEASED:
54 return XI_KeyRelease;
55 default:
56 return 0;
57 }
58 }
59
XIButtonEventType(ui::EventType type)60 int XIButtonEventType(ui::EventType type) {
61 switch (type) {
62 case ui::ET_MOUSEWHEEL:
63 case ui::ET_MOUSE_PRESSED:
64 // The button release X events for mouse wheels are dropped by Aura.
65 return XI_ButtonPress;
66 case ui::ET_MOUSE_RELEASED:
67 return XI_ButtonRelease;
68 default:
69 NOTREACHED();
70 return 0;
71 }
72 }
73
74 // Converts Aura event type and flag to X button event.
XButtonEventButton(ui::EventType type,int flags)75 unsigned int XButtonEventButton(ui::EventType type,
76 int flags) {
77 // Aura events don't keep track of mouse wheel button, so just return
78 // the first mouse wheel button.
79 if (type == ui::ET_MOUSEWHEEL)
80 return Button4;
81
82 if (flags & ui::EF_LEFT_MOUSE_BUTTON)
83 return Button1;
84 if (flags & ui::EF_MIDDLE_MOUSE_BUTTON)
85 return Button2;
86 if (flags & ui::EF_RIGHT_MOUSE_BUTTON)
87 return Button3;
88
89 return 0;
90 }
91
InitValuatorsForXIDeviceEvent(XIDeviceEvent * xiev)92 void InitValuatorsForXIDeviceEvent(XIDeviceEvent* xiev) {
93 int valuator_count = ui::DeviceDataManagerX11::DT_LAST_ENTRY;
94 xiev->valuators.mask_len = (valuator_count / 8) + 1;
95 xiev->valuators.mask = new unsigned char[xiev->valuators.mask_len];
96 memset(xiev->valuators.mask, 0, xiev->valuators.mask_len);
97 xiev->valuators.values = new double[valuator_count];
98 }
99
CreateXInput2Event(int deviceid,int evtype,int tracking_id,const gfx::Point & location)100 XEvent* CreateXInput2Event(int deviceid,
101 int evtype,
102 int tracking_id,
103 const gfx::Point& location) {
104 XEvent* event = new XEvent;
105 memset(event, 0, sizeof(*event));
106 event->type = GenericEvent;
107 event->xcookie.data = new XIDeviceEvent;
108 XIDeviceEvent* xiev =
109 static_cast<XIDeviceEvent*>(event->xcookie.data);
110 memset(xiev, 0, sizeof(XIDeviceEvent));
111 xiev->deviceid = deviceid;
112 xiev->sourceid = deviceid;
113 xiev->evtype = evtype;
114 xiev->detail = tracking_id;
115 xiev->event_x = location.x();
116 xiev->event_y = location.y();
117 xiev->event = DefaultRootWindow(gfx::GetXDisplay());
118 if (evtype == XI_ButtonPress || evtype == XI_ButtonRelease) {
119 xiev->buttons.mask_len = 8;
120 xiev->buttons.mask = new unsigned char[xiev->buttons.mask_len];
121 memset(xiev->buttons.mask, 0, xiev->buttons.mask_len);
122 }
123 return event;
124 }
125
126 } // namespace
127
128 namespace ui {
129
130 // XInput2 events contain additional data that need to be explicitly freed (see
131 // |CreateXInput2Event()|.
operator ()(XEvent * event)132 void XEventDeleter::operator()(XEvent* event) {
133 if (event->type == GenericEvent) {
134 XIDeviceEvent* xiev =
135 static_cast<XIDeviceEvent*>(event->xcookie.data);
136 if (xiev) {
137 delete[] xiev->valuators.mask;
138 delete[] xiev->valuators.values;
139 delete[] xiev->buttons.mask;
140 delete xiev;
141 }
142 }
143 delete event;
144 }
145
ScopedXI2Event()146 ScopedXI2Event::ScopedXI2Event() {}
~ScopedXI2Event()147 ScopedXI2Event::~ScopedXI2Event() {}
148
InitKeyEvent(EventType type,KeyboardCode key_code,int flags)149 void ScopedXI2Event::InitKeyEvent(EventType type,
150 KeyboardCode key_code,
151 int flags) {
152 XDisplay* display = gfx::GetXDisplay();
153 event_.reset(new XEvent);
154 memset(event_.get(), 0, sizeof(XEvent));
155 event_->type = XKeyEventType(type);
156 CHECK_NE(0, event_->type);
157 event_->xkey.serial = 0;
158 event_->xkey.send_event = 0;
159 event_->xkey.display = display;
160 event_->xkey.time = 0;
161 event_->xkey.window = 0;
162 event_->xkey.root = 0;
163 event_->xkey.subwindow = 0;
164 event_->xkey.x = 0;
165 event_->xkey.y = 0;
166 event_->xkey.x_root = 0;
167 event_->xkey.y_root = 0;
168 event_->xkey.state = XEventState(flags);
169 event_->xkey.keycode = XKeyCodeForWindowsKeyCode(key_code, flags, display);
170 event_->xkey.same_screen = 1;
171 }
172
InitGenericKeyEvent(int deviceid,int sourceid,EventType type,KeyboardCode key_code,int flags)173 void ScopedXI2Event::InitGenericKeyEvent(int deviceid,
174 int sourceid,
175 EventType type,
176 KeyboardCode key_code,
177 int flags) {
178 event_.reset(
179 CreateXInput2Event(deviceid, XIKeyEventType(type), 0, gfx::Point()));
180 XIDeviceEvent* xievent = static_cast<XIDeviceEvent*>(event_->xcookie.data);
181 CHECK_NE(0, xievent->evtype);
182 XDisplay* display = gfx::GetXDisplay();
183 event_->xgeneric.display = display;
184 xievent->display = display;
185 xievent->mods.effective = XEventState(flags);
186 xievent->detail = XKeyCodeForWindowsKeyCode(key_code, flags, display);
187 xievent->sourceid = sourceid;
188 }
189
InitGenericButtonEvent(int deviceid,EventType type,const gfx::Point & location,int flags)190 void ScopedXI2Event::InitGenericButtonEvent(int deviceid,
191 EventType type,
192 const gfx::Point& location,
193 int flags) {
194 event_.reset(CreateXInput2Event(deviceid,
195 XIButtonEventType(type), 0, gfx::Point()));
196 XIDeviceEvent* xievent = static_cast<XIDeviceEvent*>(event_->xcookie.data);
197 xievent->mods.effective = XEventState(flags);
198 xievent->detail = XButtonEventButton(type, flags);
199 xievent->event_x = location.x();
200 xievent->event_y = location.y();
201 XISetMask(xievent->buttons.mask, xievent->detail);
202 // Setup an empty valuator list for generic button events.
203 SetUpValuators(std::vector<Valuator>());
204 }
205
InitGenericMouseWheelEvent(int deviceid,int wheel_delta,int flags)206 void ScopedXI2Event::InitGenericMouseWheelEvent(int deviceid,
207 int wheel_delta,
208 int flags) {
209 InitGenericButtonEvent(deviceid, ui::ET_MOUSEWHEEL, gfx::Point(), flags);
210 XIDeviceEvent* xievent = static_cast<XIDeviceEvent*>(event_->xcookie.data);
211 xievent->detail = wheel_delta > 0 ? Button4 : Button5;
212 }
213
InitScrollEvent(int deviceid,int x_offset,int y_offset,int x_offset_ordinal,int y_offset_ordinal,int finger_count)214 void ScopedXI2Event::InitScrollEvent(int deviceid,
215 int x_offset,
216 int y_offset,
217 int x_offset_ordinal,
218 int y_offset_ordinal,
219 int finger_count) {
220 event_.reset(CreateXInput2Event(deviceid, XI_Motion, 0, gfx::Point()));
221
222 Valuator valuators[] = {
223 Valuator(DeviceDataManagerX11::DT_CMT_SCROLL_X, x_offset),
224 Valuator(DeviceDataManagerX11::DT_CMT_SCROLL_Y, y_offset),
225 Valuator(DeviceDataManagerX11::DT_CMT_ORDINAL_X, x_offset_ordinal),
226 Valuator(DeviceDataManagerX11::DT_CMT_ORDINAL_Y, y_offset_ordinal),
227 Valuator(DeviceDataManagerX11::DT_CMT_FINGER_COUNT, finger_count)
228 };
229 SetUpValuators(
230 std::vector<Valuator>(valuators, valuators + arraysize(valuators)));
231 }
232
InitFlingScrollEvent(int deviceid,int x_velocity,int y_velocity,int x_velocity_ordinal,int y_velocity_ordinal,bool is_cancel)233 void ScopedXI2Event::InitFlingScrollEvent(int deviceid,
234 int x_velocity,
235 int y_velocity,
236 int x_velocity_ordinal,
237 int y_velocity_ordinal,
238 bool is_cancel) {
239 event_.reset(CreateXInput2Event(deviceid, XI_Motion, deviceid, gfx::Point()));
240
241 Valuator valuators[] = {
242 Valuator(DeviceDataManagerX11::DT_CMT_FLING_STATE, is_cancel ? 1 : 0),
243 Valuator(DeviceDataManagerX11::DT_CMT_FLING_Y, y_velocity),
244 Valuator(DeviceDataManagerX11::DT_CMT_ORDINAL_Y, y_velocity_ordinal),
245 Valuator(DeviceDataManagerX11::DT_CMT_FLING_X, x_velocity),
246 Valuator(DeviceDataManagerX11::DT_CMT_ORDINAL_X, x_velocity_ordinal)
247 };
248
249 SetUpValuators(
250 std::vector<Valuator>(valuators, valuators + arraysize(valuators)));
251 }
252
InitTouchEvent(int deviceid,int evtype,int tracking_id,const gfx::Point & location,const std::vector<Valuator> & valuators)253 void ScopedXI2Event::InitTouchEvent(int deviceid,
254 int evtype,
255 int tracking_id,
256 const gfx::Point& location,
257 const std::vector<Valuator>& valuators) {
258 event_.reset(CreateXInput2Event(deviceid, evtype, tracking_id, location));
259
260 // If a timestamp was specified, setup the event.
261 for (size_t i = 0; i < valuators.size(); ++i) {
262 if (valuators[i].data_type ==
263 DeviceDataManagerX11::DT_TOUCH_RAW_TIMESTAMP) {
264 SetUpValuators(valuators);
265 return;
266 }
267 }
268
269 // No timestamp was specified. Use |ui::EventTimeForNow()|.
270 std::vector<Valuator> valuators_with_time = valuators;
271 valuators_with_time.push_back(
272 Valuator(DeviceDataManagerX11::DT_TOUCH_RAW_TIMESTAMP,
273 (ui::EventTimeForNow()).InMicroseconds()));
274 SetUpValuators(valuators_with_time);
275 }
276
SetUpValuators(const std::vector<Valuator> & valuators)277 void ScopedXI2Event::SetUpValuators(const std::vector<Valuator>& valuators) {
278 CHECK(event_.get());
279 CHECK_EQ(GenericEvent, event_->type);
280 XIDeviceEvent* xiev = static_cast<XIDeviceEvent*>(event_->xcookie.data);
281 InitValuatorsForXIDeviceEvent(xiev);
282 ui::DeviceDataManagerX11* manager = ui::DeviceDataManagerX11::GetInstance();
283 for (size_t i = 0; i < valuators.size(); ++i) {
284 manager->SetValuatorDataForTest(xiev, valuators[i].data_type,
285 valuators[i].value);
286 }
287 }
288
SetUpTouchPadForTest(unsigned int deviceid)289 void SetUpTouchPadForTest(unsigned int deviceid) {
290 std::vector<unsigned int> device_list;
291 device_list.push_back(deviceid);
292
293 TouchFactory::GetInstance()->SetPointerDeviceForTest(device_list);
294 ui::DeviceDataManagerX11* manager = ui::DeviceDataManagerX11::GetInstance();
295 manager->SetDeviceListForTest(std::vector<unsigned int>(), device_list);
296 }
297
SetUpTouchDevicesForTest(const std::vector<unsigned int> & devices)298 void SetUpTouchDevicesForTest(const std::vector<unsigned int>& devices) {
299 TouchFactory::GetInstance()->SetTouchDeviceForTest(devices);
300 ui::DeviceDataManagerX11* manager = ui::DeviceDataManagerX11::GetInstance();
301 manager->SetDeviceListForTest(devices, std::vector<unsigned int>());
302 }
303
304 } // namespace ui
305