Home | History | Annotate | Download | only in test
      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