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/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