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/keycodes/keyboard_code_conversion_x.h"
15 #include "ui/events/x/touch_factory_x11.h"
16
17 namespace {
18
19 // Converts ui::EventType to state for X*Events.
XEventState(int flags)20 unsigned int XEventState(int flags) {
21 return
22 ((flags & ui::EF_SHIFT_DOWN) ? ShiftMask : 0) |
23 ((flags & ui::EF_CONTROL_DOWN) ? ControlMask : 0) |
24 ((flags & ui::EF_ALT_DOWN) ? Mod1Mask : 0) |
25 ((flags & ui::EF_CAPS_LOCK_DOWN) ? LockMask : 0) |
26 ((flags & ui::EF_LEFT_MOUSE_BUTTON) ? Button1Mask: 0) |
27 ((flags & ui::EF_MIDDLE_MOUSE_BUTTON) ? Button2Mask: 0) |
28 ((flags & ui::EF_RIGHT_MOUSE_BUTTON) ? Button3Mask: 0);
29 }
30
31 // Converts EventType to XKeyEvent type.
XKeyEventType(ui::EventType type)32 int XKeyEventType(ui::EventType type) {
33 switch (type) {
34 case ui::ET_KEY_PRESSED:
35 return KeyPress;
36 case ui::ET_KEY_RELEASED:
37 return KeyRelease;
38 default:
39 return 0;
40 }
41 }
42
43 // Converts EventType to XButtonEvent type.
XButtonEventType(ui::EventType type)44 int XButtonEventType(ui::EventType type) {
45 switch (type) {
46 case ui::ET_MOUSEWHEEL:
47 case ui::ET_MOUSE_PRESSED:
48 // The button release X events for mouse wheels are dropped by Aura.
49 return ButtonPress;
50 case ui::ET_MOUSE_RELEASED:
51 return ButtonRelease;
52 default:
53 return 0;
54 }
55 }
56
57 // Converts KeyboardCode to XKeyEvent keycode.
XKeyEventKeyCode(ui::KeyboardCode key_code,int flags,XDisplay * display)58 unsigned int XKeyEventKeyCode(ui::KeyboardCode key_code,
59 int flags,
60 XDisplay* display) {
61 const int keysym = XKeysymForWindowsKeyCode(key_code,
62 flags & ui::EF_SHIFT_DOWN);
63 // Tests assume the keycode for XK_less is equal to the one of XK_comma,
64 // but XKeysymToKeycode returns 94 for XK_less while it returns 59 for
65 // XK_comma. Here we convert the value for XK_less to the value for XK_comma.
66 return (keysym == XK_less) ? 59 : XKeysymToKeycode(display, keysym);
67 }
68
69 // Converts Aura event type and flag to X button event.
XButtonEventButton(ui::EventType type,int flags)70 unsigned int XButtonEventButton(ui::EventType type,
71 int flags) {
72 // Aura events don't keep track of mouse wheel button, so just return
73 // the first mouse wheel button.
74 if (type == ui::ET_MOUSEWHEEL)
75 return Button4;
76
77 switch (flags) {
78 case ui::EF_LEFT_MOUSE_BUTTON:
79 return Button1;
80 case ui::EF_MIDDLE_MOUSE_BUTTON:
81 return Button2;
82 case ui::EF_RIGHT_MOUSE_BUTTON:
83 return Button3;
84 }
85
86 return 0;
87 }
88
InitValuatorsForXIDeviceEvent(XIDeviceEvent * xiev)89 void InitValuatorsForXIDeviceEvent(XIDeviceEvent* xiev) {
90 int valuator_count = ui::DeviceDataManager::DT_LAST_ENTRY;
91 xiev->valuators.mask_len = (valuator_count / 8) + 1;
92 xiev->valuators.mask = new unsigned char[xiev->valuators.mask_len];
93 memset(xiev->valuators.mask, 0, xiev->valuators.mask_len);
94 xiev->valuators.values = new double[valuator_count];
95 }
96
CreateXInput2Event(int deviceid,int evtype,int tracking_id,const gfx::Point & location)97 XEvent* CreateXInput2Event(int deviceid,
98 int evtype,
99 int tracking_id,
100 const gfx::Point& location) {
101 XEvent* event = new XEvent;
102 memset(event, 0, sizeof(*event));
103 event->type = GenericEvent;
104 event->xcookie.data = new XIDeviceEvent;
105 XIDeviceEvent* xiev =
106 static_cast<XIDeviceEvent*>(event->xcookie.data);
107 memset(xiev, 0, sizeof(XIDeviceEvent));
108 xiev->deviceid = deviceid;
109 xiev->sourceid = deviceid;
110 xiev->evtype = evtype;
111 xiev->detail = tracking_id;
112 xiev->event_x = location.x();
113 xiev->event_y = location.y();
114
115 return event;
116 }
117
118 } // namespace
119
120 namespace ui {
121
ScopedXI2Event()122 ScopedXI2Event::ScopedXI2Event() {}
~ScopedXI2Event()123 ScopedXI2Event::~ScopedXI2Event() {
124 Cleanup();
125 }
126
InitKeyEvent(EventType type,KeyboardCode key_code,int flags)127 void ScopedXI2Event::InitKeyEvent(EventType type,
128 KeyboardCode key_code,
129 int flags) {
130 Cleanup();
131 XDisplay* display = gfx::GetXDisplay();
132 event_.reset(new XEvent);
133 memset(event_.get(), 0, sizeof(XEvent));
134 event_->type = XKeyEventType(type);
135 CHECK_NE(0, event_->type);
136 event_->xkey.serial = 0;
137 event_->xkey.send_event = 0;
138 event_->xkey.display = display;
139 event_->xkey.time = 0;
140 event_->xkey.window = 0;
141 event_->xkey.root = 0;
142 event_->xkey.subwindow = 0;
143 event_->xkey.x = 0;
144 event_->xkey.y = 0;
145 event_->xkey.x_root = 0;
146 event_->xkey.y_root = 0;
147 event_->xkey.state = XEventState(flags);
148 event_->xkey.keycode = XKeyEventKeyCode(key_code, flags, display);
149 event_->xkey.same_screen = 1;
150 }
151
InitButtonEvent(EventType type,int flags)152 void ScopedXI2Event::InitButtonEvent(EventType type,
153 int flags) {
154 Cleanup();
155 event_.reset(new XEvent);
156 memset(event_.get(), 0, sizeof(XEvent));
157 event_->type = XButtonEventType(type);
158 CHECK_NE(0, event_->type);
159 event_->xbutton.serial = 0;
160 event_->xbutton.send_event = 0;
161 event_->xbutton.display = gfx::GetXDisplay();
162 event_->xbutton.time = 0;
163 event_->xbutton.window = 0;
164 event_->xbutton.root = 0;
165 event_->xbutton.subwindow = 0;
166 event_->xbutton.x = 0;
167 event_->xbutton.y = 0;
168 event_->xbutton.x_root = 0;
169 event_->xbutton.y_root = 0;
170 event_->xbutton.state = XEventState(flags);
171 event_->xbutton.button = XButtonEventButton(type, flags);
172 event_->xbutton.same_screen = 1;
173 }
174
InitMouseWheelEvent(int wheel_delta,int flags)175 void ScopedXI2Event::InitMouseWheelEvent(int wheel_delta,
176 int flags) {
177 InitButtonEvent(ui::ET_MOUSEWHEEL, flags);
178 // MouseWheelEvents are not taking horizontal scrolls into account
179 // at the moment.
180 event_->xbutton.button = wheel_delta > 0 ? Button4 : Button5;
181 }
182
InitScrollEvent(int deviceid,int x_offset,int y_offset,int x_offset_ordinal,int y_offset_ordinal,int finger_count)183 void ScopedXI2Event::InitScrollEvent(int deviceid,
184 int x_offset,
185 int y_offset,
186 int x_offset_ordinal,
187 int y_offset_ordinal,
188 int finger_count) {
189 Cleanup();
190 event_.reset(CreateXInput2Event(deviceid, XI_Motion, 0, gfx::Point()));
191
192 Valuator valuators[] = {
193 Valuator(DeviceDataManager::DT_CMT_SCROLL_X, x_offset),
194 Valuator(DeviceDataManager::DT_CMT_SCROLL_Y, y_offset),
195 Valuator(DeviceDataManager::DT_CMT_ORDINAL_X, x_offset_ordinal),
196 Valuator(DeviceDataManager::DT_CMT_ORDINAL_Y, y_offset_ordinal),
197 Valuator(DeviceDataManager::DT_CMT_FINGER_COUNT, finger_count)
198 };
199 SetUpValuators(
200 std::vector<Valuator>(valuators, valuators + arraysize(valuators)));
201 }
202
InitFlingScrollEvent(int deviceid,int x_velocity,int y_velocity,int x_velocity_ordinal,int y_velocity_ordinal,bool is_cancel)203 void ScopedXI2Event::InitFlingScrollEvent(int deviceid,
204 int x_velocity,
205 int y_velocity,
206 int x_velocity_ordinal,
207 int y_velocity_ordinal,
208 bool is_cancel) {
209 Cleanup();
210 event_.reset(CreateXInput2Event(deviceid, XI_Motion, deviceid, gfx::Point()));
211
212 Valuator valuators[] = {
213 Valuator(DeviceDataManager::DT_CMT_FLING_STATE, is_cancel ? 1 : 0),
214 Valuator(DeviceDataManager::DT_CMT_FLING_Y, y_velocity),
215 Valuator(DeviceDataManager::DT_CMT_ORDINAL_Y, y_velocity_ordinal),
216 Valuator(DeviceDataManager::DT_CMT_FLING_X, x_velocity),
217 Valuator(DeviceDataManager::DT_CMT_ORDINAL_X, x_velocity_ordinal)
218 };
219
220 SetUpValuators(
221 std::vector<Valuator>(valuators, valuators + arraysize(valuators)));
222 }
223
InitTouchEvent(int deviceid,int evtype,int tracking_id,const gfx::Point & location,const std::vector<Valuator> & valuators)224 void ScopedXI2Event::InitTouchEvent(int deviceid,
225 int evtype,
226 int tracking_id,
227 const gfx::Point& location,
228 const std::vector<Valuator>& valuators) {
229 Cleanup();
230 event_.reset(CreateXInput2Event(deviceid, evtype, tracking_id, location));
231 SetUpValuators(valuators);
232 }
233
Cleanup()234 void ScopedXI2Event::Cleanup() {
235 if (event_.get() && event_->type == GenericEvent) {
236 XIDeviceEvent* xiev =
237 static_cast<XIDeviceEvent*>(event_->xcookie.data);
238 if (xiev) {
239 delete[] xiev->valuators.mask;
240 delete[] xiev->valuators.values;
241 delete xiev;
242 }
243 }
244 event_.reset();
245 }
246
SetUpValuators(const std::vector<Valuator> & valuators)247 void ScopedXI2Event::SetUpValuators(const std::vector<Valuator>& valuators) {
248 CHECK(event_.get());
249 CHECK_EQ(GenericEvent, event_->type);
250 XIDeviceEvent* xiev = static_cast<XIDeviceEvent*>(event_->xcookie.data);
251 InitValuatorsForXIDeviceEvent(xiev);
252 ui::DeviceDataManager* manager = ui::DeviceDataManager::GetInstance();
253 for (size_t i = 0; i < valuators.size(); ++i) {
254 manager->SetValuatorDataForTest(xiev, valuators[i].data_type,
255 valuators[i].value);
256 }
257 }
258
SetUpScrollDeviceForTest(unsigned int deviceid)259 void SetUpScrollDeviceForTest(unsigned int deviceid) {
260 std::vector<unsigned int> device_list;
261 device_list.push_back(deviceid);
262
263 TouchFactory::GetInstance()->SetPointerDeviceForTest(device_list);
264 ui::DeviceDataManager* manager = ui::DeviceDataManager::GetInstance();
265 manager->SetDeviceListForTest(std::vector<unsigned int>(), device_list);
266 }
267
SetUpTouchDevicesForTest(const std::vector<unsigned int> & devices)268 void SetUpTouchDevicesForTest(const std::vector<unsigned int>& devices) {
269 TouchFactory::GetInstance()->SetTouchDeviceForTest(devices);
270 ui::DeviceDataManager* manager = ui::DeviceDataManager::GetInstance();
271 manager->SetDeviceListForTest(devices, std::vector<unsigned int>());
272 }
273
274 } // namespace ui
275