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. 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. 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. 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 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. 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 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 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()|. 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 146 ScopedXI2Event::ScopedXI2Event() {} 147 ScopedXI2Event::~ScopedXI2Event() {} 148 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 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 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 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 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 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 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 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 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 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