• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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