// Copyright 2013 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. #include "ui/events/test/events_test_utils_x11.h" #include #include #include #include #include #include "base/logging.h" #include "base/macros.h" #include "ui/events/devices/x11/touch_factory_x11.h" #include "ui/events/event_constants.h" #include "ui/events/event_utils.h" #include "ui/events/keycodes/keyboard_code_conversion_x.h" namespace { // Converts ui::EventType to state for X*Events. unsigned int XEventState(int flags) { return ((flags & ui::EF_SHIFT_DOWN) ? ShiftMask : 0) | ((flags & ui::EF_CAPS_LOCK_ON) ? LockMask : 0) | ((flags & ui::EF_CONTROL_DOWN) ? ControlMask : 0) | ((flags & ui::EF_ALT_DOWN) ? Mod1Mask : 0) | ((flags & ui::EF_NUM_LOCK_ON) ? Mod2Mask : 0) | ((flags & ui::EF_MOD3_DOWN) ? Mod3Mask : 0) | ((flags & ui::EF_COMMAND_DOWN) ? Mod4Mask : 0) | ((flags & ui::EF_ALTGR_DOWN) ? Mod5Mask : 0) | ((flags & ui::EF_LEFT_MOUSE_BUTTON) ? Button1Mask: 0) | ((flags & ui::EF_MIDDLE_MOUSE_BUTTON) ? Button2Mask: 0) | ((flags & ui::EF_RIGHT_MOUSE_BUTTON) ? Button3Mask: 0); } // Converts EventType to XKeyEvent type. int XKeyEventType(ui::EventType type) { switch (type) { case ui::ET_KEY_PRESSED: return KeyPress; case ui::ET_KEY_RELEASED: return KeyRelease; default: return 0; } } // Converts EventType to XI2 event type. int XIKeyEventType(ui::EventType type) { switch (type) { case ui::ET_KEY_PRESSED: return XI_KeyPress; case ui::ET_KEY_RELEASED: return XI_KeyRelease; default: return 0; } } int XIButtonEventType(ui::EventType type) { switch (type) { case ui::ET_MOUSEWHEEL: case ui::ET_MOUSE_PRESSED: // The button release X events for mouse wheels are dropped by Aura. return XI_ButtonPress; case ui::ET_MOUSE_RELEASED: return XI_ButtonRelease; default: NOTREACHED(); return 0; } } // Converts Aura event type and flag to X button event. unsigned int XButtonEventButton(ui::EventType type, int flags) { // Aura events don't keep track of mouse wheel button, so just return // the first mouse wheel button. if (type == ui::ET_MOUSEWHEEL) return Button4; if (flags & ui::EF_LEFT_MOUSE_BUTTON) return Button1; if (flags & ui::EF_MIDDLE_MOUSE_BUTTON) return Button2; if (flags & ui::EF_RIGHT_MOUSE_BUTTON) return Button3; return 0; } void InitValuatorsForXIDeviceEvent(XIDeviceEvent* xiev) { int valuator_count = ui::DeviceDataManagerX11::DT_LAST_ENTRY; xiev->valuators.mask_len = (valuator_count / 8) + 1; xiev->valuators.mask = new unsigned char[xiev->valuators.mask_len]; memset(xiev->valuators.mask, 0, xiev->valuators.mask_len); xiev->valuators.values = new double[valuator_count]; } XEvent* CreateXInput2Event(int deviceid, int evtype, int tracking_id, const gfx::Point& location) { XEvent* event = new XEvent; memset(event, 0, sizeof(*event)); event->type = GenericEvent; event->xcookie.data = new XIDeviceEvent; XIDeviceEvent* xiev = static_cast(event->xcookie.data); memset(xiev, 0, sizeof(XIDeviceEvent)); xiev->deviceid = deviceid; xiev->sourceid = deviceid; xiev->evtype = evtype; xiev->detail = tracking_id; xiev->event_x = location.x(); xiev->event_y = location.y(); xiev->event = DefaultRootWindow(gfx::GetXDisplay()); if (evtype == XI_ButtonPress || evtype == XI_ButtonRelease) { xiev->buttons.mask_len = 8; xiev->buttons.mask = new unsigned char[xiev->buttons.mask_len]; memset(xiev->buttons.mask, 0, xiev->buttons.mask_len); } return event; } } // namespace namespace ui { // XInput2 events contain additional data that need to be explicitly freed (see // |CreateXInput2Event()|. void XEventDeleter::operator()(XEvent* event) { if (event->type == GenericEvent) { XIDeviceEvent* xiev = static_cast(event->xcookie.data); if (xiev) { delete[] xiev->valuators.mask; delete[] xiev->valuators.values; delete[] xiev->buttons.mask; delete xiev; } } delete event; } ScopedXI2Event::ScopedXI2Event() {} ScopedXI2Event::~ScopedXI2Event() {} void ScopedXI2Event::InitKeyEvent(EventType type, KeyboardCode key_code, int flags) { XDisplay* display = gfx::GetXDisplay(); event_.reset(new XEvent); memset(event_.get(), 0, sizeof(XEvent)); event_->type = XKeyEventType(type); CHECK_NE(0, event_->type); event_->xkey.serial = 0; event_->xkey.send_event = 0; event_->xkey.display = display; event_->xkey.time = 0; event_->xkey.window = 0; event_->xkey.root = 0; event_->xkey.subwindow = 0; event_->xkey.x = 0; event_->xkey.y = 0; event_->xkey.x_root = 0; event_->xkey.y_root = 0; event_->xkey.state = XEventState(flags); event_->xkey.keycode = XKeyCodeForWindowsKeyCode(key_code, flags, display); event_->xkey.same_screen = 1; } void ScopedXI2Event::InitMotionEvent(const gfx::Point& location, const gfx::Point& root_location, int flags) { XDisplay* display = gfx::GetXDisplay(); event_.reset(new XEvent); memset(event_.get(), 0, sizeof(XEvent)); event_->type = MotionNotify; event_->xmotion.serial = 0; event_->xmotion.send_event = 0; event_->xmotion.display = display; event_->xmotion.time = 0; event_->xmotion.window = 0; event_->xmotion.root = 0; event_->xkey.subwindow = 0; event_->xmotion.x = location.x(); event_->xmotion.y = location.y(); event_->xmotion.x_root = root_location.x(); event_->xmotion.y_root = root_location.y(); event_->xmotion.state = XEventState(flags); event_->xmotion.same_screen = 1; } void ScopedXI2Event::InitGenericKeyEvent(int deviceid, int sourceid, EventType type, KeyboardCode key_code, int flags) { event_.reset( CreateXInput2Event(deviceid, XIKeyEventType(type), 0, gfx::Point())); XIDeviceEvent* xievent = static_cast(event_->xcookie.data); CHECK_NE(0, xievent->evtype); XDisplay* display = gfx::GetXDisplay(); event_->xgeneric.display = display; xievent->display = display; xievent->mods.effective = XEventState(flags); xievent->detail = XKeyCodeForWindowsKeyCode(key_code, flags, display); xievent->sourceid = sourceid; } void ScopedXI2Event::InitGenericButtonEvent(int deviceid, EventType type, const gfx::Point& location, int flags) { event_.reset(CreateXInput2Event(deviceid, XIButtonEventType(type), 0, gfx::Point())); XIDeviceEvent* xievent = static_cast(event_->xcookie.data); xievent->mods.effective = XEventState(flags); xievent->detail = XButtonEventButton(type, flags); xievent->event_x = location.x(); xievent->event_y = location.y(); XISetMask(xievent->buttons.mask, xievent->detail); // Setup an empty valuator list for generic button events. SetUpValuators(std::vector()); } void ScopedXI2Event::InitGenericMouseWheelEvent(int deviceid, int wheel_delta, int flags) { InitGenericButtonEvent(deviceid, ui::ET_MOUSEWHEEL, gfx::Point(), flags); XIDeviceEvent* xievent = static_cast(event_->xcookie.data); xievent->detail = wheel_delta > 0 ? Button4 : Button5; } void ScopedXI2Event::InitScrollEvent(int deviceid, int x_offset, int y_offset, int x_offset_ordinal, int y_offset_ordinal, int finger_count) { event_.reset(CreateXInput2Event(deviceid, XI_Motion, 0, gfx::Point())); Valuator valuators[] = { Valuator(DeviceDataManagerX11::DT_CMT_SCROLL_X, x_offset), Valuator(DeviceDataManagerX11::DT_CMT_SCROLL_Y, y_offset), Valuator(DeviceDataManagerX11::DT_CMT_ORDINAL_X, x_offset_ordinal), Valuator(DeviceDataManagerX11::DT_CMT_ORDINAL_Y, y_offset_ordinal), Valuator(DeviceDataManagerX11::DT_CMT_FINGER_COUNT, finger_count) }; SetUpValuators( std::vector(valuators, valuators + arraysize(valuators))); } void ScopedXI2Event::InitFlingScrollEvent(int deviceid, int x_velocity, int y_velocity, int x_velocity_ordinal, int y_velocity_ordinal, bool is_cancel) { event_.reset(CreateXInput2Event(deviceid, XI_Motion, deviceid, gfx::Point())); Valuator valuators[] = { Valuator(DeviceDataManagerX11::DT_CMT_FLING_STATE, is_cancel ? 1 : 0), Valuator(DeviceDataManagerX11::DT_CMT_FLING_Y, y_velocity), Valuator(DeviceDataManagerX11::DT_CMT_ORDINAL_Y, y_velocity_ordinal), Valuator(DeviceDataManagerX11::DT_CMT_FLING_X, x_velocity), Valuator(DeviceDataManagerX11::DT_CMT_ORDINAL_X, x_velocity_ordinal) }; SetUpValuators( std::vector(valuators, valuators + arraysize(valuators))); } void ScopedXI2Event::InitTouchEvent(int deviceid, int evtype, int tracking_id, const gfx::Point& location, const std::vector& valuators) { event_.reset(CreateXInput2Event(deviceid, evtype, tracking_id, location)); // If a timestamp was specified, setup the event. for (size_t i = 0; i < valuators.size(); ++i) { if (valuators[i].data_type == DeviceDataManagerX11::DT_TOUCH_RAW_TIMESTAMP) { SetUpValuators(valuators); return; } } // No timestamp was specified. Use |ui::EventTimeForNow()|. std::vector valuators_with_time = valuators; valuators_with_time.push_back( Valuator(DeviceDataManagerX11::DT_TOUCH_RAW_TIMESTAMP, (ui::EventTimeForNow()).InMicroseconds())); SetUpValuators(valuators_with_time); } void ScopedXI2Event::SetUpValuators(const std::vector& valuators) { CHECK(event_.get()); CHECK_EQ(GenericEvent, event_->type); XIDeviceEvent* xiev = static_cast(event_->xcookie.data); InitValuatorsForXIDeviceEvent(xiev); ui::DeviceDataManagerX11* manager = ui::DeviceDataManagerX11::GetInstance(); for (size_t i = 0; i < valuators.size(); ++i) { manager->SetValuatorDataForTest(xiev, valuators[i].data_type, valuators[i].value); } } void SetUpTouchPadForTest(int deviceid) { std::vector device_list; device_list.push_back(deviceid); TouchFactory::GetInstance()->SetPointerDeviceForTest(device_list); ui::DeviceDataManagerX11* manager = ui::DeviceDataManagerX11::GetInstance(); manager->SetDeviceListForTest(std::vector(), device_list, std::vector()); } void SetUpTouchDevicesForTest(const std::vector& devices) { TouchFactory::GetInstance()->SetTouchDeviceForTest(devices); ui::DeviceDataManagerX11* manager = ui::DeviceDataManagerX11::GetInstance(); manager->SetDeviceListForTest(devices, std::vector(), std::vector()); } void SetUpPointerDevicesForTest(const std::vector& devices) { TouchFactory::GetInstance()->SetPointerDeviceForTest(devices); ui::DeviceDataManagerX11* manager = ui::DeviceDataManagerX11::GetInstance(); manager->SetDeviceListForTest(std::vector(), std::vector(), devices); } } // namespace ui