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. 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. 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. 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. 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. 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 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 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 122 ScopedXI2Event::ScopedXI2Event() {} 123 ScopedXI2Event::~ScopedXI2Event() { 124 Cleanup(); 125 } 126 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 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 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 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 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 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 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 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 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 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