blob: cb961398aea4c0e3bf468fd207a16492a1683acb [file] [log] [blame]
// 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 <stddef.h>
#include <X11/extensions/XI2.h>
#include <X11/keysym.h>
#include <X11/X.h>
#include <X11/Xlib.h>
#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<XIDeviceEvent*>(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<XIDeviceEvent*>(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<XIDeviceEvent*>(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<XIDeviceEvent*>(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<Valuator>());
}
void ScopedXI2Event::InitGenericMouseWheelEvent(int deviceid,
int wheel_delta,
int flags) {
InitGenericButtonEvent(deviceid, ui::ET_MOUSEWHEEL, gfx::Point(), flags);
XIDeviceEvent* xievent = static_cast<XIDeviceEvent*>(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<Valuator>(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<Valuator>(valuators, valuators + arraysize(valuators)));
}
void ScopedXI2Event::InitTouchEvent(int deviceid,
int evtype,
int tracking_id,
const gfx::Point& location,
const std::vector<Valuator>& 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<Valuator> valuators_with_time = valuators;
valuators_with_time.push_back(
Valuator(DeviceDataManagerX11::DT_TOUCH_RAW_TIMESTAMP,
(ui::EventTimeForNow() - base::TimeTicks()).InMicroseconds()));
SetUpValuators(valuators_with_time);
}
void ScopedXI2Event::SetUpValuators(const std::vector<Valuator>& valuators) {
CHECK(event_.get());
CHECK_EQ(GenericEvent, event_->type);
XIDeviceEvent* xiev = static_cast<XIDeviceEvent*>(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<int> device_list;
device_list.push_back(deviceid);
TouchFactory::GetInstance()->SetPointerDeviceForTest(device_list);
ui::DeviceDataManagerX11* manager = ui::DeviceDataManagerX11::GetInstance();
manager->SetDeviceListForTest(std::vector<int>(), device_list,
std::vector<int>());
}
void SetUpTouchDevicesForTest(const std::vector<int>& devices) {
TouchFactory::GetInstance()->SetTouchDeviceForTest(devices);
ui::DeviceDataManagerX11* manager = ui::DeviceDataManagerX11::GetInstance();
manager->SetDeviceListForTest(devices, std::vector<int>(),
std::vector<int>());
}
void SetUpPointerDevicesForTest(const std::vector<int>& devices) {
TouchFactory::GetInstance()->SetPointerDeviceForTest(devices);
ui::DeviceDataManagerX11* manager = ui::DeviceDataManagerX11::GetInstance();
manager->SetDeviceListForTest(std::vector<int>(), std::vector<int>(),
devices);
}
} // namespace ui