Home | History | Annotate | Download | only in x
      1 // Copyright (c) 2012 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 <cstring>
      6 
      7 #include <X11/extensions/XInput2.h>
      8 #include <X11/Xlib.h>
      9 
     10 // Generically-named #defines from Xlib that conflict with symbols in GTest.
     11 #undef Bool
     12 #undef None
     13 
     14 #include "testing/gtest/include/gtest/gtest.h"
     15 #include "ui/base/events/event_constants.h"
     16 #include "ui/base/events/event_utils.h"
     17 #include "ui/base/touch/touch_factory_x11.h"
     18 #include "ui/base/x/device_data_manager.h"
     19 #include "ui/gfx/point.h"
     20 
     21 namespace ui {
     22 
     23 namespace {
     24 
     25 // Initializes the passed-in Xlib event.
     26 void InitButtonEvent(XEvent* event,
     27                      bool is_press,
     28                      const gfx::Point& location,
     29                      int button,
     30                      int state) {
     31   memset(event, 0, sizeof(*event));
     32 
     33   // We don't bother setting fields that the event code doesn't use, such as
     34   // x_root/y_root and window/root/subwindow.
     35   XButtonEvent* button_event = &(event->xbutton);
     36   button_event->type = is_press ? ButtonPress : ButtonRelease;
     37   button_event->x = location.x();
     38   button_event->y = location.y();
     39   button_event->button = button;
     40   button_event->state = state;
     41 }
     42 
     43 #if defined(USE_XI2_MT)
     44 const int kValuatorNum = 3;
     45 const int kTouchValuatorMap[kValuatorNum][4] = {
     46   // { valuator_index, valuator_type, min_val, max_val }
     47   { 0, DeviceDataManager::DT_TOUCH_MAJOR, 0, 1000},
     48   { 1, DeviceDataManager::DT_TOUCH_ORIENTATION, 0, 1.0},
     49   { 2, DeviceDataManager::DT_TOUCH_PRESSURE, 0, 1000},
     50 };
     51 
     52 struct Valuator {
     53   Valuator(DeviceDataManager::DataType type, double v)
     54       : data_type(type), value(v) {}
     55 
     56   DeviceDataManager::DataType data_type;
     57   double value;
     58 };
     59 
     60 XEvent* CreateTouchEvent(int deviceid,
     61                          int evtype,
     62                          int tracking_id,
     63                          const gfx::Point& location,
     64                          const std::vector<Valuator>& valuators) {
     65   XEvent* event = new XEvent;
     66   memset(event, 0, sizeof(*event));
     67   event->type = GenericEvent;
     68   event->xcookie.data = new XIDeviceEvent;
     69   XIDeviceEvent* xiev =
     70       static_cast<XIDeviceEvent*>(event->xcookie.data);
     71   xiev->deviceid = deviceid;
     72   xiev->sourceid = deviceid;
     73   xiev->evtype = evtype;
     74   xiev->detail = tracking_id;
     75   xiev->event_x = location.x();
     76   xiev->event_y = location.y();
     77 
     78   xiev->valuators.mask_len = (valuators.size() / 8) + 1;
     79   xiev->valuators.mask = new unsigned char[xiev->valuators.mask_len];
     80   memset(xiev->valuators.mask, 0, xiev->valuators.mask_len);
     81   xiev->valuators.values = new double[valuators.size()];
     82 
     83   int val_count = 0;
     84   for (int i = 0; i < kValuatorNum; i++) {
     85     for(size_t j = 0; j < valuators.size(); j++) {
     86       if (valuators[j].data_type == kTouchValuatorMap[i][1]) {
     87         XISetMask(xiev->valuators.mask, kTouchValuatorMap[i][0]);
     88         xiev->valuators.values[val_count++] = valuators[j].value;
     89       }
     90     }
     91   }
     92 
     93   return event;
     94 }
     95 
     96 void DestroyTouchEvent(XEvent* event) {
     97   XIDeviceEvent* xiev =
     98       static_cast<XIDeviceEvent*>(event->xcookie.data);
     99   if (xiev) {
    100     delete[] xiev->valuators.mask;
    101     delete[] xiev->valuators.values;
    102     delete xiev;
    103   }
    104   delete event;
    105 }
    106 
    107 void SetupTouchFactory(const std::vector<unsigned int>& devices) {
    108   TouchFactory* factory = TouchFactory::GetInstance();
    109   factory->SetTouchDeviceForTest(devices);
    110 }
    111 
    112 void SetupDeviceDataManager(const std::vector<unsigned int>& devices) {
    113   ui::DeviceDataManager* manager = ui::DeviceDataManager::GetInstance();
    114   manager->SetDeviceListForTest(devices);
    115   for (size_t i = 0; i < devices.size(); i++) {
    116     for (int j = 0; j < kValuatorNum; j++) {
    117       manager->SetDeviceValuatorForTest(
    118           devices[i],
    119           kTouchValuatorMap[j][0],
    120           static_cast<DeviceDataManager::DataType>(kTouchValuatorMap[j][1]),
    121           kTouchValuatorMap[j][2],
    122           kTouchValuatorMap[j][3]);
    123     }
    124   }
    125 }
    126 #endif
    127 }  // namespace
    128 
    129 TEST(EventsXTest, ButtonEvents) {
    130   XEvent event;
    131   gfx::Point location(5, 10);
    132   gfx::Vector2d offset;
    133 
    134   InitButtonEvent(&event, true, location, 1, 0);
    135   EXPECT_EQ(ui::ET_MOUSE_PRESSED, ui::EventTypeFromNative(&event));
    136   EXPECT_EQ(ui::EF_LEFT_MOUSE_BUTTON, ui::EventFlagsFromNative(&event));
    137   EXPECT_EQ(location, ui::EventLocationFromNative(&event));
    138   EXPECT_TRUE(ui::IsMouseEvent(&event));
    139 
    140   InitButtonEvent(&event, true, location, 2, Button1Mask | ShiftMask);
    141   EXPECT_EQ(ui::ET_MOUSE_PRESSED, ui::EventTypeFromNative(&event));
    142   EXPECT_EQ(ui::EF_LEFT_MOUSE_BUTTON | ui::EF_MIDDLE_MOUSE_BUTTON |
    143                 ui::EF_SHIFT_DOWN,
    144             ui::EventFlagsFromNative(&event));
    145   EXPECT_EQ(location, ui::EventLocationFromNative(&event));
    146   EXPECT_TRUE(ui::IsMouseEvent(&event));
    147 
    148   InitButtonEvent(&event, false, location, 3, 0);
    149   EXPECT_EQ(ui::ET_MOUSE_RELEASED, ui::EventTypeFromNative(&event));
    150   EXPECT_EQ(ui::EF_RIGHT_MOUSE_BUTTON, ui::EventFlagsFromNative(&event));
    151   EXPECT_EQ(location, ui::EventLocationFromNative(&event));
    152   EXPECT_TRUE(ui::IsMouseEvent(&event));
    153 
    154   // Scroll up.
    155   InitButtonEvent(&event, true, location, 4, 0);
    156   EXPECT_EQ(ui::ET_MOUSEWHEEL, ui::EventTypeFromNative(&event));
    157   EXPECT_EQ(0, ui::EventFlagsFromNative(&event));
    158   EXPECT_EQ(location, ui::EventLocationFromNative(&event));
    159   EXPECT_TRUE(ui::IsMouseEvent(&event));
    160   offset = ui::GetMouseWheelOffset(&event);
    161   EXPECT_GT(offset.y(), 0);
    162   EXPECT_EQ(0, offset.x());
    163 
    164   // Scroll down.
    165   InitButtonEvent(&event, true, location, 5, 0);
    166   EXPECT_EQ(ui::ET_MOUSEWHEEL, ui::EventTypeFromNative(&event));
    167   EXPECT_EQ(0, ui::EventFlagsFromNative(&event));
    168   EXPECT_EQ(location, ui::EventLocationFromNative(&event));
    169   EXPECT_TRUE(ui::IsMouseEvent(&event));
    170   offset = ui::GetMouseWheelOffset(&event);
    171   EXPECT_LT(offset.y(), 0);
    172   EXPECT_EQ(0, offset.x());
    173 
    174   // Scroll left, typically.
    175   InitButtonEvent(&event, true, location, 6, 0);
    176   EXPECT_EQ(ui::ET_MOUSEWHEEL, ui::EventTypeFromNative(&event));
    177   EXPECT_EQ(0, ui::EventFlagsFromNative(&event));
    178   EXPECT_EQ(location, ui::EventLocationFromNative(&event));
    179   EXPECT_TRUE(ui::IsMouseEvent(&event));
    180   offset = ui::GetMouseWheelOffset(&event);
    181   EXPECT_EQ(0, offset.y());
    182   EXPECT_EQ(0, offset.x());
    183 
    184   // Scroll right, typically.
    185   InitButtonEvent(&event, true, location, 7, 0);
    186   EXPECT_EQ(ui::ET_MOUSEWHEEL, ui::EventTypeFromNative(&event));
    187   EXPECT_EQ(0, ui::EventFlagsFromNative(&event));
    188   EXPECT_EQ(location, ui::EventLocationFromNative(&event));
    189   EXPECT_TRUE(ui::IsMouseEvent(&event));
    190   offset = ui::GetMouseWheelOffset(&event);
    191   EXPECT_EQ(0, offset.y());
    192   EXPECT_EQ(0, offset.x());
    193 
    194   // TODO(derat): Test XInput code.
    195 }
    196 
    197 TEST(EventsXTest, AvoidExtraEventsOnWheelRelease) {
    198   XEvent event;
    199   gfx::Point location(5, 10);
    200 
    201   InitButtonEvent(&event, true, location, 4, 0);
    202   EXPECT_EQ(ui::ET_MOUSEWHEEL, ui::EventTypeFromNative(&event));
    203 
    204   // We should return ET_UNKNOWN for the release event instead of returning
    205   // ET_MOUSEWHEEL; otherwise we'll scroll twice for each scrollwheel step.
    206   InitButtonEvent(&event, false, location, 4, 0);
    207   EXPECT_EQ(ui::ET_UNKNOWN, ui::EventTypeFromNative(&event));
    208 
    209   // TODO(derat): Test XInput code.
    210 }
    211 
    212 TEST(EventsXTest, EnterLeaveEvent) {
    213   XEvent event;
    214   event.xcrossing.type = EnterNotify;
    215   event.xcrossing.x = 10;
    216   event.xcrossing.y = 20;
    217   event.xcrossing.x_root = 110;
    218   event.xcrossing.y_root = 120;
    219 
    220   // Mouse enter events are converted to mouse move events to be consistent with
    221   // the way views handle mouse enter. See comments for EnterNotify case in
    222   // ui::EventTypeFromNative for more details.
    223   EXPECT_EQ(ui::ET_MOUSE_MOVED, ui::EventTypeFromNative(&event));
    224   EXPECT_EQ("10,20", ui::EventLocationFromNative(&event).ToString());
    225   EXPECT_EQ("110,120", ui::EventSystemLocationFromNative(&event).ToString());
    226 
    227   event.xcrossing.type = LeaveNotify;
    228   event.xcrossing.x = 30;
    229   event.xcrossing.y = 40;
    230   event.xcrossing.x_root = 230;
    231   event.xcrossing.y_root = 240;
    232   EXPECT_EQ(ui::ET_MOUSE_EXITED, ui::EventTypeFromNative(&event));
    233   EXPECT_EQ("30,40", ui::EventLocationFromNative(&event).ToString());
    234   EXPECT_EQ("230,240", ui::EventSystemLocationFromNative(&event).ToString());
    235 }
    236 
    237 #if defined(USE_XI2_MT)
    238 TEST(EventsXTest, TouchEventBasic) {
    239   std::vector<unsigned int> devices;
    240   devices.push_back(0);
    241   SetupTouchFactory(devices);
    242   SetupDeviceDataManager(devices);
    243   XEvent* event = NULL;
    244   std::vector<Valuator> valuators;
    245 
    246   // Init touch begin with tracking id 5, touch id 0.
    247   valuators.push_back(Valuator(DeviceDataManager::DT_TOUCH_MAJOR, 20));
    248   valuators.push_back(Valuator(DeviceDataManager::DT_TOUCH_ORIENTATION, 0.3f));
    249   valuators.push_back(Valuator(DeviceDataManager::DT_TOUCH_PRESSURE, 100));
    250   event = CreateTouchEvent(0, XI_TouchBegin, 5, gfx::Point(10, 10), valuators);
    251   EXPECT_EQ("10,10", ui::EventLocationFromNative(event).ToString());
    252   EXPECT_EQ(GetTouchId(event), 0);
    253   EXPECT_EQ(GetTouchRadiusX(event), 10);
    254   EXPECT_FLOAT_EQ(GetTouchAngle(event), 0.15f);
    255   EXPECT_FLOAT_EQ(GetTouchForce(event), 0.1f);
    256   DestroyTouchEvent(event);
    257 
    258   // Touch update, with new orientation info.
    259   valuators.clear();
    260   valuators.push_back(Valuator(DeviceDataManager::DT_TOUCH_ORIENTATION, 0.5f));
    261   event = CreateTouchEvent(0, XI_TouchUpdate, 5, gfx::Point(20, 20), valuators);
    262   EXPECT_EQ("20,20", ui::EventLocationFromNative(event).ToString());
    263   EXPECT_EQ(GetTouchId(event), 0);
    264   EXPECT_EQ(GetTouchRadiusX(event), 10);
    265   EXPECT_FLOAT_EQ(GetTouchAngle(event), 0.25f);
    266   EXPECT_FLOAT_EQ(GetTouchForce(event), 0.1f);
    267   DestroyTouchEvent(event);
    268 
    269   // Another touch with tracking id 6, touch id 1.
    270   valuators.clear();
    271   valuators.push_back(Valuator(DeviceDataManager::DT_TOUCH_MAJOR, 100));
    272   valuators.push_back(Valuator(DeviceDataManager::DT_TOUCH_ORIENTATION, 0.9f));
    273   valuators.push_back(Valuator(DeviceDataManager::DT_TOUCH_PRESSURE, 500));
    274   event = CreateTouchEvent(
    275       0, XI_TouchBegin, 6, gfx::Point(200, 200), valuators);
    276   EXPECT_EQ("200,200", ui::EventLocationFromNative(event).ToString());
    277   EXPECT_EQ(GetTouchId(event), 1);
    278   EXPECT_EQ(GetTouchRadiusX(event), 50);
    279   EXPECT_FLOAT_EQ(GetTouchAngle(event), 0.45f);
    280   EXPECT_FLOAT_EQ(GetTouchForce(event), 0.5f);
    281   DestroyTouchEvent(event);
    282 
    283   // Touch with tracking id 5 should have old radius/angle value and new pressue
    284   // value.
    285   valuators.clear();
    286   valuators.push_back(Valuator(DeviceDataManager::DT_TOUCH_PRESSURE, 50));
    287   event = CreateTouchEvent(0, XI_TouchEnd, 5, gfx::Point(30, 30), valuators);
    288   EXPECT_EQ("30,30", ui::EventLocationFromNative(event).ToString());
    289   EXPECT_EQ(GetTouchId(event), 0);
    290   EXPECT_EQ(GetTouchRadiusX(event), 10);
    291   EXPECT_FLOAT_EQ(GetTouchAngle(event), 0.25f);
    292   EXPECT_FLOAT_EQ(GetTouchForce(event), 0.05f);
    293   DestroyTouchEvent(event);
    294 
    295   // Touch with tracking id 6 should have old angle/pressure value and new
    296   // radius value.
    297   valuators.clear();
    298   valuators.push_back(Valuator(DeviceDataManager::DT_TOUCH_MAJOR, 50));
    299   event = CreateTouchEvent(0, XI_TouchEnd, 6, gfx::Point(200, 200), valuators);
    300   EXPECT_EQ("200,200", ui::EventLocationFromNative(event).ToString());
    301   EXPECT_EQ(GetTouchId(event), 1);
    302   EXPECT_EQ(GetTouchRadiusX(event), 25);
    303   EXPECT_FLOAT_EQ(GetTouchAngle(event), 0.45f);
    304   EXPECT_FLOAT_EQ(GetTouchForce(event), 0.5f);
    305   DestroyTouchEvent(event);
    306 }
    307 #endif
    308 }  // namespace ui
    309