diff options
Diffstat (limited to 'ui/base/x')
-rw-r--r-- | ui/base/x/device_data_manager.cc | 423 | ||||
-rw-r--r-- | ui/base/x/device_data_manager.h | 238 | ||||
-rw-r--r-- | ui/base/x/events_x.cc | 535 | ||||
-rw-r--r-- | ui/base/x/valuators.cc | 184 | ||||
-rw-r--r-- | ui/base/x/valuators.h | 117 | ||||
-rw-r--r-- | ui/base/x/x11_util.cc | 6 |
6 files changed, 749 insertions, 754 deletions
diff --git a/ui/base/x/device_data_manager.cc b/ui/base/x/device_data_manager.cc new file mode 100644 index 0000000..e5b6187 --- /dev/null +++ b/ui/base/x/device_data_manager.cc @@ -0,0 +1,423 @@ +// 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/base/x/device_data_manager.h" + +#include <X11/extensions/XInput.h> +#include <X11/extensions/XInput2.h> +#include <X11/Xlib.h> + +#include "base/logging.h" +#include "base/memory/singleton.h" +#include "base/message_pump_aurax11.h" +#include "ui/base/events/event_constants.h" +#include "ui/base/events/event_utils.h" +#include "ui/base/x/device_list_cache_x.h" +#include "ui/base/x/x11_util.h" + +// Copied from xserver-properties.h +#define AXIS_LABEL_PROP_REL_HWHEEL "Rel Horiz Wheel" +#define AXIS_LABEL_PROP_REL_WHEEL "Rel Vert Wheel" + +// CMT specific timings +#define AXIS_LABEL_PROP_ABS_DBL_START_TIME "Abs Dbl Start Timestamp" +#define AXIS_LABEL_PROP_ABS_DBL_END_TIME "Abs Dbl End Timestamp" + +// Ordinal values +#define AXIS_LABEL_PROP_ABS_DBL_ORDINAL_X "Abs Dbl Ordinal X" +#define AXIS_LABEL_PROP_ABS_DBL_ORDINAL_Y "Abs Dbl Ordinal Y" + +// Fling properties +#define AXIS_LABEL_PROP_ABS_DBL_FLING_VX "Abs Dbl Fling X Velocity" +#define AXIS_LABEL_PROP_ABS_DBL_FLING_VY "Abs Dbl Fling Y Velocity" +#define AXIS_LABEL_PROP_ABS_FLING_STATE "Abs Fling State" + +#define AXIS_LABEL_PROP_ABS_FINGER_COUNT "Abs Finger Count" + +// Touchscreen multi-touch +#define AXIS_LABEL_ABS_MT_TOUCH_MAJOR "Abs MT Touch Major" +#define AXIS_LABEL_ABS_MT_TOUCH_MINOR "Abs MT Touch Minor" +#define AXIS_LABEL_ABS_MT_ORIENTATION "Abs MT Orientation" +#define AXIS_LABEL_ABS_MT_PRESSURE "Abs MT Pressure" +#define AXIS_LABEL_ABS_MT_SLOT_ID "Abs MT Slot ID" +#define AXIS_LABEL_ABS_MT_TRACKING_ID "Abs MT Tracking ID" +#define AXIS_LABEL_TOUCH_TIMESTAMP "Touch Timestamp" + +// When you add new data types, please make sure the order here is aligned +// with the order in the DataType enum in the header file because we assume +// they are in sync when updating the device list (see UpdateDeviceList). +const char* kCachedAtoms[] = { + AXIS_LABEL_PROP_REL_HWHEEL, + AXIS_LABEL_PROP_REL_WHEEL, + AXIS_LABEL_PROP_ABS_DBL_ORDINAL_X, + AXIS_LABEL_PROP_ABS_DBL_ORDINAL_Y, + AXIS_LABEL_PROP_ABS_DBL_START_TIME, + AXIS_LABEL_PROP_ABS_DBL_END_TIME, + AXIS_LABEL_PROP_ABS_DBL_FLING_VX, + AXIS_LABEL_PROP_ABS_DBL_FLING_VY, + AXIS_LABEL_PROP_ABS_FLING_STATE, + AXIS_LABEL_PROP_ABS_FINGER_COUNT, + AXIS_LABEL_ABS_MT_TOUCH_MAJOR, + AXIS_LABEL_ABS_MT_TOUCH_MINOR, + AXIS_LABEL_ABS_MT_ORIENTATION, + AXIS_LABEL_ABS_MT_PRESSURE, +#if !defined(USE_XI2_MT) + AXIS_LABEL_ABS_MT_SLOT_ID, +#endif + AXIS_LABEL_ABS_MT_TRACKING_ID, + AXIS_LABEL_TOUCH_TIMESTAMP, + + NULL +}; + +// Constants for checking if a data type lies in the range of CMT/Touch data +// types. +const int kCMTDataTypeStart = ui::DeviceDataManager::DT_CMT_SCROLL_X; +const int kCMTDataTypeEnd = ui::DeviceDataManager::DT_CMT_FINGER_COUNT; +const int kTouchDataTypeStart = ui::DeviceDataManager::DT_TOUCH_MAJOR; +const int kTouchDataTypeEnd = ui::DeviceDataManager::DT_TOUCH_RAW_TIMESTAMP; + +namespace ui { + +bool DeviceDataManager::IsCMTDataType(const int type) { + return (type >= kCMTDataTypeStart) && (type <= kCMTDataTypeEnd); +} + +bool DeviceDataManager::IsTouchDataType(const int type) { + return (type >= kTouchDataTypeStart) && (type <= kTouchDataTypeEnd); +} + +DeviceDataManager* DeviceDataManager::GetInstance() { + return Singleton<DeviceDataManager>::get(); +} + +DeviceDataManager::DeviceDataManager() + : natural_scroll_enabled_(false), + atom_cache_(ui::GetXDisplay(), kCachedAtoms) { + // Make sure the sizes of enum and kCachedAtoms are aligned. + CHECK(arraysize(kCachedAtoms) == static_cast<size_t>(DT_LAST_ENTRY) + 1); + UpdateDeviceList(ui::GetXDisplay()); +} + +DeviceDataManager::~DeviceDataManager() { +} + +float DeviceDataManager::GetNaturalScrollFactor(int sourceid) const { + // Natural scroll is touchpad-only. + if (sourceid >= kMaxDeviceNum || !touchpads_[sourceid]) + return -1.0f; + + return natural_scroll_enabled_ ? 1.0f : -1.0f; +} + +void DeviceDataManager::UpdateDeviceList(Display* display) { + cmt_devices_.reset(); + touchpads_.reset(); + for (int i = 0; i < kMaxDeviceNum; ++i) { + valuator_count_[i] = 0; + valuator_lookup_[i].clear(); + data_type_lookup_[i].clear(); + valuator_min_[i].clear(); + valuator_max_[i].clear(); + last_seen_valuator_[i].clear(); + } + + // Find all the touchpad devices. + XDeviceList dev_list = + ui::DeviceListCacheX::GetInstance()->GetXDeviceList(display); + Atom xi_touchpad = XInternAtom(display, XI_TOUCHPAD, false); + for (int i = 0; i < dev_list.count; ++i) + if (dev_list[i].type == xi_touchpad) + touchpads_[dev_list[i].id] = true; + + // Update the structs with new valuator information + XIDeviceList info_list = + ui::DeviceListCacheX::GetInstance()->GetXI2DeviceList(display); + Atom atoms[DT_LAST_ENTRY]; + for (int data_type = 0; data_type < DT_LAST_ENTRY; ++data_type) + atoms[data_type] = atom_cache_.GetAtom(kCachedAtoms[data_type]); + + for (int i = 0; i < info_list.count; ++i) { + XIDeviceInfo* info = info_list.devices + i; + + // We currently handle only slave, non-keyboard devices + if (info->use != XISlavePointer && info->use != XIFloatingSlave) + continue; + + bool possible_cmt = false; + bool not_cmt = false; + const int deviceid = info->deviceid; + + for (int j = 0; j < info->num_classes; ++j) { + if (info->classes[j]->type == XIValuatorClass) + ++valuator_count_[deviceid]; + else if (info->classes[j]->type == XIScrollClass) + not_cmt = true; + } + + // Skip devices that don't use any valuator + if (!valuator_count_[deviceid]) + continue; + + valuator_lookup_[deviceid].resize(DT_LAST_ENTRY, -1); + data_type_lookup_[deviceid].resize( + valuator_count_[deviceid], DT_LAST_ENTRY); + valuator_min_[deviceid].resize(DT_LAST_ENTRY, 0); + valuator_max_[deviceid].resize(DT_LAST_ENTRY, 0); + last_seen_valuator_[deviceid].resize(DT_LAST_ENTRY, 0); + for (int j = 0; j < info->num_classes; ++j) { + if (info->classes[j]->type != XIValuatorClass) + continue; + + XIValuatorClassInfo* v = + reinterpret_cast<XIValuatorClassInfo*>(info->classes[j]); + for (int data_type = 0; data_type < DT_LAST_ENTRY; ++data_type) { + if (v->label == atoms[data_type]) { + valuator_lookup_[deviceid][data_type] = v->number; + data_type_lookup_[deviceid][v->number] = data_type; + valuator_min_[deviceid][data_type] = v->min; + valuator_max_[deviceid][data_type] = v->max; + if (IsCMTDataType(data_type)) + possible_cmt = true; + break; + } + } + } + + if (possible_cmt && !not_cmt) + cmt_devices_[deviceid] = true; + } +} + +void DeviceDataManager::GetEventRawData(const XEvent& xev, EventData* data) { + if (xev.type != GenericEvent) + return; + + XIDeviceEvent* xiev = static_cast<XIDeviceEvent*>(xev.xcookie.data); + if (xiev->sourceid >= kMaxDeviceNum || xiev->deviceid >= kMaxDeviceNum) + return; + data->clear(); + const int sourceid = xiev->sourceid; + double* valuators = xiev->valuators.values; + for (int i = 0; i <= valuator_count_[sourceid]; ++i) { + if (XIMaskIsSet(xiev->valuators.mask, i)) { + int type = data_type_lookup_[sourceid][i]; + if (type != DT_LAST_ENTRY) { + (*data)[type] = *valuators; + if (IsTouchDataType(type)) + last_seen_valuator_[sourceid][type] = *valuators; + } + valuators++; + } + } +} + +bool DeviceDataManager::GetEventData(const XEvent& xev, + const DataType type, double* value) { + if (xev.type != GenericEvent) + return false; + + XIDeviceEvent* xiev = static_cast<XIDeviceEvent*>(xev.xcookie.data); + if (xiev->sourceid >= kMaxDeviceNum || xiev->deviceid >= kMaxDeviceNum) + return false; + const int sourceid = xiev->sourceid; + if (valuator_lookup_[sourceid].empty()) + return false; + + int val_index = valuator_lookup_[sourceid][type]; + if (val_index >= 0) { + if (XIMaskIsSet(xiev->valuators.mask, val_index)) { + double* valuators = xiev->valuators.values; + while (val_index--) { + if (XIMaskIsSet(xiev->valuators.mask, val_index)) + ++valuators; + } + *value = *valuators; + last_seen_valuator_[sourceid][type] = *value; + return true; + } else if (IsTouchDataType(type)) { + *value = last_seen_valuator_[sourceid][type]; + } + } + +#if defined(USE_XI2_MT) + // With XInput2 MT, Tracking ID is provided in the detail field. + if (type == DT_TOUCH_TRACKING_ID) { + *value = xiev->detail; + return true; + } +#endif + + return false; +} + +bool DeviceDataManager::IsTouchpadXInputEvent( + const base::NativeEvent& native_event) const { + if (native_event->type != GenericEvent) + return false; + + XIDeviceEvent* xievent = + static_cast<XIDeviceEvent*>(native_event->xcookie.data); + if (xievent->sourceid >= kMaxDeviceNum) + return false; + return touchpads_[xievent->sourceid]; +} + +bool DeviceDataManager::IsCMTDeviceEvent( + const base::NativeEvent& native_event) const { + if (native_event->type != GenericEvent) + return false; + + XIDeviceEvent* xievent = + static_cast<XIDeviceEvent*>(native_event->xcookie.data); + if (xievent->sourceid >= kMaxDeviceNum) + return false; + return cmt_devices_[xievent->sourceid]; +} + +bool DeviceDataManager::IsCMTGestureEvent( + const base::NativeEvent& native_event) const { + return (IsScrollEvent(native_event) || + IsFlingEvent(native_event)); +} + +bool DeviceDataManager::HasEventData( + const XIDeviceEvent* xiev, const DataType type) const { + const int idx = valuator_lookup_[xiev->sourceid][type]; + return (idx >= 0) && XIMaskIsSet(xiev->valuators.mask, idx); +} + +bool DeviceDataManager::IsScrollEvent( + const base::NativeEvent& native_event) const { + if (!IsCMTDeviceEvent(native_event)) + return false; + + XIDeviceEvent* xiev = + static_cast<XIDeviceEvent*>(native_event->xcookie.data); + return (HasEventData(xiev, DT_CMT_SCROLL_X) || + HasEventData(xiev, DT_CMT_SCROLL_Y)); +} + +bool DeviceDataManager::IsFlingEvent( + const base::NativeEvent& native_event) const { + if (!IsCMTDeviceEvent(native_event)) + return false; + + XIDeviceEvent* xiev = + static_cast<XIDeviceEvent*>(native_event->xcookie.data); + return (HasEventData(xiev, DT_CMT_FLING_X) && + HasEventData(xiev, DT_CMT_FLING_Y) && + HasEventData(xiev, DT_CMT_FLING_STATE)); +} + +bool DeviceDataManager::HasGestureTimes( + const base::NativeEvent& native_event) const { + if (!IsCMTDeviceEvent(native_event)) + return false; + + XIDeviceEvent* xiev = + static_cast<XIDeviceEvent*>(native_event->xcookie.data); + return (HasEventData(xiev, DT_CMT_START_TIME) && + HasEventData(xiev, DT_CMT_END_TIME)); +} + +void DeviceDataManager::GetScrollOffsets(const base::NativeEvent& native_event, + float* x_offset, float* y_offset, + float* x_offset_ordinal, + float* y_offset_ordinal, + int* finger_count) { + *x_offset = 0; + *y_offset = 0; + *x_offset_ordinal = 0; + *y_offset_ordinal = 0; + *finger_count = 2; + + XIDeviceEvent* xiev = + static_cast<XIDeviceEvent*>(native_event->xcookie.data); + const float natural_scroll_factor = GetNaturalScrollFactor(xiev->sourceid); + EventData data; + GetEventRawData(*native_event, &data); + + if (data.find(DT_CMT_SCROLL_X) != data.end()) + *x_offset = data[DT_CMT_SCROLL_X] * natural_scroll_factor; + if (data.find(DT_CMT_SCROLL_Y) != data.end()) + *y_offset = data[DT_CMT_SCROLL_Y] * natural_scroll_factor; + if (data.find(DT_CMT_ORDINAL_X) != data.end()) + *x_offset_ordinal = data[DT_CMT_ORDINAL_X] * natural_scroll_factor; + if (data.find(DT_CMT_ORDINAL_Y) != data.end()) + *y_offset_ordinal = data[DT_CMT_ORDINAL_Y] * natural_scroll_factor; + if (data.find(DT_CMT_FINGER_COUNT) != data.end()) + *finger_count = static_cast<int>(data[DT_CMT_FINGER_COUNT]); +} + +void DeviceDataManager::GetFlingData(const base::NativeEvent& native_event, + float* vx, float* vy, + float* vx_ordinal, float* vy_ordinal, + bool* is_cancel) { + *vx = 0; + *vy = 0; + *vx_ordinal = 0; + *vy_ordinal = 0; + *is_cancel = false; + + XIDeviceEvent* xiev = + static_cast<XIDeviceEvent*>(native_event->xcookie.data); + const float natural_scroll_factor = GetNaturalScrollFactor(xiev->sourceid); + EventData data; + GetEventRawData(*native_event, &data); + + if (data.find(DT_CMT_FLING_X) != data.end()) + *vx = data[DT_CMT_FLING_X] * natural_scroll_factor; + if (data.find(DT_CMT_FLING_Y) != data.end()) + *vy = data[DT_CMT_FLING_Y] * natural_scroll_factor; + if (data.find(DT_CMT_FLING_STATE) != data.end()) + *is_cancel = !!static_cast<unsigned int>(data[DT_CMT_FLING_STATE]); + if (data.find(DT_CMT_ORDINAL_X) != data.end()) + *vx_ordinal = data[DT_CMT_ORDINAL_X] * natural_scroll_factor; + if (data.find(DT_CMT_ORDINAL_Y) != data.end()) + *vy_ordinal = data[DT_CMT_ORDINAL_Y] * natural_scroll_factor; +} + +void DeviceDataManager::GetGestureTimes(const base::NativeEvent& native_event, + double* start_time, + double* end_time) { + *start_time = 0; + *end_time = 0; + + EventData data; + GetEventRawData(*native_event, &data); + + if (data.find(DT_CMT_START_TIME) != data.end()) + *start_time = data[DT_CMT_START_TIME]; + if (data.find(DT_CMT_END_TIME) != data.end()) + *end_time = data[DT_CMT_END_TIME]; +} + +bool DeviceDataManager::NormalizeData(unsigned int deviceid, + const DataType type, + double* value) { + double max_value; + double min_value; + if (GetDataRange(deviceid, type, &min_value, &max_value)) { + *value = (*value - min_value) / (max_value - min_value); + DCHECK(*value >= 0.0 && *value <= 1.0); + return true; + } + return false; +} + +bool DeviceDataManager::GetDataRange(unsigned int deviceid, + const DataType type, + double* min, double* max) { + if (deviceid >= static_cast<unsigned int>(kMaxDeviceNum)) + return false; + if (valuator_lookup_[deviceid][type] >= 0) { + *min = valuator_min_[deviceid][type]; + *max = valuator_max_[deviceid][type]; + return true; + } + return false; +} + +} // namespace ui diff --git a/ui/base/x/device_data_manager.h b/ui/base/x/device_data_manager.h new file mode 100644 index 0000000..27f468a --- /dev/null +++ b/ui/base/x/device_data_manager.h @@ -0,0 +1,238 @@ +// 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. + +#ifndef UI_BASE_X_DEVICE_DATA_MANAGER_H_ +#define UI_BASE_X_DEVICE_DATA_MANAGER_H_ + +#include <X11/extensions/XInput2.h> + +#include <bitset> +#include <map> +#include <vector> + +#include "base/basictypes.h" +#include "base/event_types.h" +#include "ui/base/events/event_constants.h" +#include "ui/base/ui_export.h" +#include "ui/base/x/x11_atom_cache.h" + +template <typename T> struct DefaultSingletonTraits; + +typedef union _XEvent XEvent; + +namespace ui { + +// A class that extracts and tracks the input events data. It currently handles +// mouse, touchpad and touchscreen devices. +class UI_EXPORT DeviceDataManager { + public: + // Enumerate additional data that one might be interested on an input event, + // which are usually wrapped in X valuators. If you modify any of this, + // make sure to update the kCachedAtoms data structure in the source file + // and the k*Type[Start/End] constants used by IsCMTDataType and + // IsTouchDataType. + enum DataType { + // Define the valuators used the CrOS CMT driver. Used by mice and CrOS + // touchpads. + DT_CMT_SCROLL_X = 0, // Scroll amount on the X (horizontal) direction. + DT_CMT_SCROLL_Y, // Scroll amount on the Y (vertical) direction. + DT_CMT_ORDINAL_X, // Original (unaccelerated) value on the X direction. + // Can be used both for scrolls and flings. + DT_CMT_ORDINAL_Y, // Original (unaccelerated) value on the Y direction. + // Can be used both for scrolls and flings. + DT_CMT_START_TIME, // Gesture start time. + DT_CMT_END_TIME, // Gesture end time. + DT_CMT_FLING_X, // Fling amount on the X (horizontal) direction. + DT_CMT_FLING_Y, // Fling amount on the Y (vertical) direction. + DT_CMT_FLING_STATE, // The state of fling gesture (whether the user just + // start flinging or that he/she taps down). + DT_CMT_FINGER_COUNT, // Finger counts in the current gesture. A same type + // of gesture can have very different meanings based + // on that (e.g. 2f scroll v.s. 3f swipe). + + // End of CMT data types. + // Beginning of touch data types. + + // Define the valuators following the Multi-touch Protocol. Used by + // touchscreen devices. + DT_TOUCH_MAJOR, // Length of the touch area. + DT_TOUCH_MINOR, // Width of the touch area. + DT_TOUCH_ORIENTATION, // Angle between the X-axis and the major axis of the + // touch area. + DT_TOUCH_PRESSURE, // Pressure of the touch contact. + + // NOTE: A touch event can have multiple touch points. So when we receive a + // touch event, we need to determine which point triggered the event. + // A touch point can have both a 'Slot ID' and a 'Tracking ID', and they can + // be (in fact, usually are) different. The 'Slot ID' ranges between 0 and + // (X - 1), where X is the maximum touch points supported by the device. The + // 'Tracking ID' can be any 16-bit value. With XInput 2.0, an XI_Motion + // event that comes from a currently-unused 'Slot ID' indicates the creation + // of a new touch point, and any event that comes with a 0 value for + // 'Tracking ID' marks the removal of a touch point. During the lifetime of + // a touchpoint, we use the 'Slot ID' as its identifier. The XI_ButtonPress + // and XI_ButtonRelease events are ignored. +#if !defined(USE_XI2_MT) + DT_TOUCH_SLOT_ID, // ID of the finger that triggered a touch event + // (useful when tracking multiple simultaneous + // touches). +#endif + // NOTE for XInput MT: 'Tracking ID' is provided in every touch event to + // track individual touch. 'Tracking ID' is an unsigned 32-bit value and + // is increased for each new touch. It will wrap back to 0 when reaching + // the numerical limit. + DT_TOUCH_TRACKING_ID, // ID of the touch point. + + // Kernel timestamp from touch screen (if available). + DT_TOUCH_RAW_TIMESTAMP, + + // End of touch data types. + + DT_LAST_ENTRY // This must come last. + }; + + // Data struct to store extracted data from an input event. + typedef std::map<int, double> EventData; + + // We use int because enums can be casted to ints but not vice versa. + static bool IsCMTDataType(const int type); + static bool IsTouchDataType(const int type); + + // Returns the DeviceDataManager singleton. + static DeviceDataManager* GetInstance(); + + // Natural scroll setter/getter. + bool natural_scroll_enabled() const { return natural_scroll_enabled_; } + void set_natural_scroll_enabled(bool enabled) { + natural_scroll_enabled_ = enabled; + } + + // Get the natural scroll direction multiplier (1.0f or -1.0f). + float GetNaturalScrollFactor(int sourceid) const; + + // Updates the list of devices. + void UpdateDeviceList(Display* display); + + // Get all event data in one pass. We extract only data types that we know + // about (defined in enum DataType). The data is not processed (e.g. not + // filled in by cached values) as in GetEventData. + void GetEventRawData(const XEvent& xev, EventData* data); + + // Get a datum of the specified type. Return true and the value + // is updated if the data is found, false and value unchanged if the data is + // not found. In the case of MT-B/XI2.2, the value can come from a previously + // cached one (see the comment above last_seen_valuator_). + bool GetEventData(const XEvent& xev, const DataType type, double* value); + + // Check if the event comes from touchpad devices. + bool IsTouchpadXInputEvent(const base::NativeEvent& native_event) const; + + // Check if the event comes from devices running CMT driver or using + // CMT valuators (e.g. mouses). Note that doesn't necessarily mean the event + // is a CMT event (e.g. it could be a mouse pointer move). + bool IsCMTDeviceEvent(const base::NativeEvent& native_event) const; + + // Check if the event is one of the CMT gesture events (scroll, fling, + // metrics etc.). + bool IsCMTGestureEvent(const base::NativeEvent& native_event) const; + + // Returns true if the event is of the specific type, false if not. + bool IsScrollEvent(const base::NativeEvent& native_event) const; + bool IsFlingEvent(const base::NativeEvent& native_event) const; + + // Returns true if the event has CMT start/end timestamps. + bool HasGestureTimes(const base::NativeEvent& native_event) const; + + // Extract data from a scroll event (a motion event with the necessary + // valuators). User must first verify the event type with IsScrollEvent. + // Pointers shouldn't be NULL. + void GetScrollOffsets(const base::NativeEvent& native_event, + float* x_offset, + float* y_offset, + float* x_offset_ordinal, + float* y_offset_ordinal, + int* finger_count); + + // Extract data from a fling event. User must first verify the event type + // with IsFlingEvent. Pointers shouldn't be NULL. + void GetFlingData(const base::NativeEvent& native_event, + float* vx, + float* vy, + float* vx_ordinal, + float* vy_ordinal, + bool* is_cancel); + + // Extract the start/end timestamps from CMT events. User must first verify + // the event with HasGestureTimes. Pointers shouldn't be NULL. + void GetGestureTimes(const base::NativeEvent& native_event, + double* start_time, + double* end_time); + + // Normalize the data value on deviceid to fall into [0, 1]. + // *value = (*value - min_value_of_tp) / (max_value_of_tp - min_value_of_tp) + // Returns true and sets the normalized value in|value| if normalization is + // successful. Returns false and |value| is unchanged otherwise. + bool NormalizeData(unsigned int deviceid, + const DataType type, + double* value); + + // Extract the range of the data type. Return true if the range is available + // and written into min & max, false if the range is not available. + bool GetDataRange(unsigned int deviceid, + const DataType type, + double* min, + double* max); + + private: + // Requirement for Singleton. + friend struct DefaultSingletonTraits<DeviceDataManager>; + + DeviceDataManager(); + ~DeviceDataManager(); + + // Check if an XI event contains data of the specified type. + bool HasEventData(const XIDeviceEvent* xiev, const DataType type) const; + + static const int kMaxDeviceNum = 128; + bool natural_scroll_enabled_; + + // A quick lookup table for determining if events from the pointer device + // should be processed. + std::bitset<kMaxDeviceNum> cmt_devices_; + std::bitset<kMaxDeviceNum> touchpads_; + + // Number of valuators on the specific device. + int valuator_count_[kMaxDeviceNum]; + + // Index table to find the valuator for DataType on the specific device + // by valuator_lookup_[device_id][data_type]. + std::vector<int> valuator_lookup_[kMaxDeviceNum]; + + // Index table to find the DataType for valuator on the specific device + // by data_type_lookup_[device_id][valuator]. + std::vector<int> data_type_lookup_[kMaxDeviceNum]; + + // Index table to find the min & max value of the Valuator on a specific + // device. + std::vector<double> valuator_min_[kMaxDeviceNum]; + std::vector<double> valuator_max_[kMaxDeviceNum]; + + // Table to keep track of the last seen value for the specified valuator for + // a device. Defaults to 0 if the valuator was not specified in an earlier + // event. With MT-B/XI2.2, valuators in an XEvent are not reported if the + // values haven't changed from the previous event. So it is necessary to + // remember these valuators so that chrome doesn't think X/device doesn't + // know about the valuators. We currently use this only on touchscreen + // devices. + std::vector<double> last_seen_valuator_[kMaxDeviceNum]; + + // X11 atoms cache. + X11AtomCache atom_cache_; + + DISALLOW_COPY_AND_ASSIGN(DeviceDataManager); +}; + +} // namespace ui + +#endif // UI_BASE_X_DEVICE_DATA_MANAGER_H_ diff --git a/ui/base/x/events_x.cc b/ui/base/x/events_x.cc index 6c50da0..4a37457 100644 --- a/ui/base/x/events_x.cc +++ b/ui/base/x/events_x.cc @@ -16,8 +16,8 @@ #include "ui/base/events/event_utils.h" #include "ui/base/keycodes/keyboard_code_conversion_x.h" #include "ui/base/touch/touch_factory_x11.h" +#include "ui/base/x/device_data_manager.h" #include "ui/base/x/device_list_cache_x.h" -#include "ui/base/x/valuators.h" #include "ui/base/x/x11_atom_cache.h" #include "ui/base/x/x11_util.h" #include "ui/gfx/display.h" @@ -25,31 +25,6 @@ #include "ui/gfx/rect.h" #include "ui/gfx/screen.h" -// Copied from xserver-properties.h -#define AXIS_LABEL_PROP_REL_HWHEEL "Rel Horiz Wheel" -#define AXIS_LABEL_PROP_REL_WHEEL "Rel Vert Wheel" - -// CMT specific timings -#define AXIS_LABEL_PROP_ABS_START_TIME "Abs Start Timestamp" -#define AXIS_LABEL_PROP_ABS_END_TIME "Abs End Timestamp" - -// Ordinal values -#define AXIS_LABEL_PROP_ABS_DBL_ORDINAL_X "Abs Dbl Ordinal X" -#define AXIS_LABEL_PROP_ABS_DBL_ORDINAL_Y "Abs Dbl Ordinal Y" - -// Fling properties -#define AXIS_LABEL_PROP_ABS_FLING_X "Abs Fling X Velocity" -#define AXIS_LABEL_PROP_ABS_FLING_Y "Abs Fling Y Velocity" -#define AXIS_LABEL_PROP_ABS_FLING_STATE "Abs Fling State" - -#define AXIS_LABEL_PROP_ABS_FINGER_COUNT "Abs Finger Count" - -// New versions of the valuators, with double values instead of fixed point. -#define AXIS_LABEL_PROP_ABS_DBL_START_TIME "Abs Dbl Start Timestamp" -#define AXIS_LABEL_PROP_ABS_DBL_END_TIME "Abs Dbl End Timestamp" -#define AXIS_LABEL_PROP_ABS_DBL_FLING_VX "Abs Dbl Fling X Velocity" -#define AXIS_LABEL_PROP_ABS_DBL_FLING_VY "Abs Dbl Fling Y Velocity" - namespace { // Scroll amount for each wheelscroll event. 53 is also the value used for GTK+. @@ -58,24 +33,6 @@ const int kWheelScrollAmount = 53; const int kMinWheelButton = 4; const int kMaxWheelButton = 7; -const char* kCMTCachedAtoms[] = { - AXIS_LABEL_PROP_ABS_DBL_ORDINAL_X, - AXIS_LABEL_PROP_ABS_DBL_ORDINAL_Y, - AXIS_LABEL_PROP_REL_HWHEEL, - AXIS_LABEL_PROP_REL_WHEEL, - AXIS_LABEL_PROP_ABS_START_TIME, - AXIS_LABEL_PROP_ABS_DBL_START_TIME, - AXIS_LABEL_PROP_ABS_END_TIME, - AXIS_LABEL_PROP_ABS_DBL_END_TIME, - AXIS_LABEL_PROP_ABS_FLING_X, - AXIS_LABEL_PROP_ABS_FLING_Y, - AXIS_LABEL_PROP_ABS_DBL_FLING_VX, - AXIS_LABEL_PROP_ABS_DBL_FLING_VY, - AXIS_LABEL_PROP_ABS_FLING_STATE, - AXIS_LABEL_PROP_ABS_FINGER_COUNT, - NULL -}; - // A workaround for some incorrect implemented input drivers: // Ignore their mouse input valuators. bool IgnoreMouseValuators() { @@ -89,373 +46,6 @@ bool IgnoreMouseValuators() { return ignore_valuators; } -// A class to support the detection of scroll events, using X11 valuators. -class CMTEventData { - public: - // Returns the ScrollEventData singleton. - static CMTEventData* GetInstance() { - return Singleton<CMTEventData>::get(); - } - - // Updates the list of devices. - void UpdateDeviceList(Display* display) { - cmt_devices_.reset(); - touchpads_.reset(); - device_to_valuators_.clear(); - -#if defined(USE_XI2_MT) - // Find all the touchpad devices. - XDeviceList dev_list = - ui::DeviceListCacheX::GetInstance()->GetXDeviceList(display); - Atom xi_touchpad = XInternAtom(display, XI_TOUCHPAD, false); - for (int i = 0; i < dev_list.count; ++i) - if (dev_list[i].type == xi_touchpad) - touchpads_[dev_list[i].id] = true; - - XIDeviceList info_list = - ui::DeviceListCacheX::GetInstance()->GetXI2DeviceList(display); - Atom x_axis = atom_cache_.GetAtom(AXIS_LABEL_PROP_REL_HWHEEL); - Atom y_axis = atom_cache_.GetAtom(AXIS_LABEL_PROP_REL_WHEEL); - Atom x_ordinal = atom_cache_.GetAtom(AXIS_LABEL_PROP_ABS_DBL_ORDINAL_X); - Atom y_ordinal = atom_cache_.GetAtom(AXIS_LABEL_PROP_ABS_DBL_ORDINAL_Y); - Atom start_time = atom_cache_.GetAtom(AXIS_LABEL_PROP_ABS_START_TIME); - Atom start_time_dbl = - atom_cache_.GetAtom(AXIS_LABEL_PROP_ABS_DBL_START_TIME); - Atom end_time = atom_cache_.GetAtom(AXIS_LABEL_PROP_ABS_END_TIME); - Atom end_time_dbl = atom_cache_.GetAtom(AXIS_LABEL_PROP_ABS_DBL_END_TIME); - Atom fling_vx = atom_cache_.GetAtom(AXIS_LABEL_PROP_ABS_FLING_X); - Atom fling_vx_dbl = atom_cache_.GetAtom(AXIS_LABEL_PROP_ABS_DBL_FLING_VX); - Atom fling_vy = atom_cache_.GetAtom(AXIS_LABEL_PROP_ABS_FLING_Y); - Atom fling_vy_dbl = atom_cache_.GetAtom(AXIS_LABEL_PROP_ABS_DBL_FLING_VY); - Atom fling_state = atom_cache_.GetAtom(AXIS_LABEL_PROP_ABS_FLING_STATE); - Atom finger_count = atom_cache_.GetAtom(AXIS_LABEL_PROP_ABS_FINGER_COUNT); - - for (int i = 0; i < info_list.count; ++i) { - XIDeviceInfo* info = info_list.devices + i; - - if (info->use != XISlavePointer && info->use != XIFloatingSlave) - continue; - - Valuators valuators; - bool is_cmt = false; - for (int j = 0; j < info->num_classes; ++j) { - if (info->classes[j]->type == XIScrollClass) { - is_cmt = false; - break; - } - if (info->classes[j]->type != XIValuatorClass) - continue; - - XIValuatorClassInfo* v = - reinterpret_cast<XIValuatorClassInfo*>(info->classes[j]); - int number = v->number; - if (number > valuators.max) - valuators.max = number; - if (v->label == x_axis) { - valuators.scroll_x = number; - is_cmt = true; - } else if (v->label == y_axis) { - valuators.scroll_y = number; - is_cmt = true; - } else if (v->label == x_ordinal) { - valuators.ordinal_x = number; - is_cmt = true; - } else if (v->label == y_ordinal) { - valuators.ordinal_y = number; - is_cmt = true; - } else if (v->label == finger_count) { - valuators.finger_count = number; - is_cmt = true; - } else if (v->label == start_time) { - valuators.start_time = number; - is_cmt = true; - } else if (v->label == start_time_dbl) { - valuators.start_time_dbl = number; - is_cmt = true; - } else if (v->label == end_time) { - valuators.end_time = number; - is_cmt = true; - } else if (v->label == end_time_dbl) { - valuators.end_time_dbl = number; - is_cmt = true; - } else if (v->label == fling_vx) { - valuators.fling_vx = number; - is_cmt = true; - } else if (v->label == fling_vx_dbl) { - valuators.fling_vx_dbl = number; - is_cmt = true; - } else if (v->label == fling_vy) { - valuators.fling_vy = number; - is_cmt = true; - } else if (v->label == fling_vy_dbl) { - valuators.fling_vy_dbl = number; - is_cmt = true; - } else if (v->label == fling_state) { - valuators.fling_state = number; - is_cmt = true; - } - } - if (is_cmt) { - // Double valuators override fixed point ones. - if (valuators.start_time_dbl >= 0) - valuators.start_time = -1; - if (valuators.end_time_dbl >= 0) - valuators.end_time = -1; - if (valuators.fling_vx_dbl >= 0) - valuators.fling_vx = -1; - if (valuators.fling_vy_dbl >= 0) - valuators.fling_vy = -1; - device_to_valuators_[info->deviceid] = valuators; - cmt_devices_[info->deviceid] = true; - } - } -#endif // defined(USE_XI2_MT) - } - - bool natural_scroll_enabled() const { return natural_scroll_enabled_; } - void set_natural_scroll_enabled(bool enabled) { - natural_scroll_enabled_ = enabled; - } - - bool IsTouchpadXInputEvent(const base::NativeEvent& native_event) { - if (native_event->type != GenericEvent) - return false; - - XIDeviceEvent* xievent = - static_cast<XIDeviceEvent*>(native_event->xcookie.data); - return touchpads_[xievent->sourceid]; - } - - float GetNaturalScrollFactor(int sourceid) { - // Natural scroll is touchpad-only. - if (!touchpads_[sourceid]) - return -1.0f; - - return natural_scroll_enabled_ ? 1.0f : -1.0f; - } - - // Returns true if this is a scroll event (a motion event with the necessary - // valuators. Also returns the offsets. |x_offset| and |y_offset| can be - // NULL. - bool GetScrollOffsets(const XEvent& xev, - float* x_offset, - float* y_offset, - float* x_offset_ordinal, - float* y_offset_ordinal, - int* finger_count) { - XIDeviceEvent* xiev = static_cast<XIDeviceEvent*>(xev.xcookie.data); - - if (x_offset) - *x_offset = 0; - if (y_offset) - *y_offset = 0; - if (x_offset_ordinal) - *x_offset_ordinal = 0; - if (y_offset_ordinal) - *y_offset_ordinal = 0; - if (finger_count) - *finger_count = 2; - - const int sourceid = xiev->sourceid; - if (!cmt_devices_[sourceid]) - return false; - - const float natural_scroll_factor = GetNaturalScrollFactor(sourceid); - const Valuators v = device_to_valuators_[sourceid]; - const bool has_x_offset = XIMaskIsSet(xiev->valuators.mask, v.scroll_x); - const bool has_y_offset = XIMaskIsSet(xiev->valuators.mask, v.scroll_y); - const bool is_scroll = has_x_offset || has_y_offset; - - if (!is_scroll || (!x_offset && !y_offset)) - return is_scroll; - - double* valuators = xiev->valuators.values; - for (int i = 0; i <= v.max; ++i) { - if (XIMaskIsSet(xiev->valuators.mask, i)) { - if (x_offset && v.scroll_x == i) - *x_offset = *valuators * natural_scroll_factor; - else if (y_offset && v.scroll_y == i) - *y_offset = *valuators * natural_scroll_factor; - else if (x_offset_ordinal && v.ordinal_x == i) - *x_offset_ordinal = *valuators * natural_scroll_factor; - else if (y_offset_ordinal && v.ordinal_y == i) - *y_offset_ordinal = *valuators * natural_scroll_factor; - else if (finger_count && v.finger_count == i) - *finger_count = static_cast<int>(*valuators); - valuators++; - } - } - - return true; - } - - bool GetFlingData(const XEvent& xev, - float* vx, float* vy, - float* vx_ordinal, float* vy_ordinal, - bool* is_cancel) { - XIDeviceEvent* xiev = static_cast<XIDeviceEvent*>(xev.xcookie.data); - - if (vx) - *vx = 0; - if (vy) - *vy = 0; - if (vx_ordinal) - *vx_ordinal = 0; - if (vy_ordinal) - *vy_ordinal = 0; - if (is_cancel) - *is_cancel = false; - - const int sourceid = xiev->sourceid; - if (!cmt_devices_[sourceid]) - return false; - - const float natural_scroll_factor = GetNaturalScrollFactor(sourceid); - const Valuators v = device_to_valuators_[sourceid]; - if ((!XIMaskIsSet(xiev->valuators.mask, v.fling_vx) && - !XIMaskIsSet(xiev->valuators.mask, v.fling_vx_dbl)) || - (!XIMaskIsSet(xiev->valuators.mask, v.fling_vy) && - !XIMaskIsSet(xiev->valuators.mask, v.fling_vy_dbl)) || - !XIMaskIsSet(xiev->valuators.mask, v.fling_state)) - return false; - - double* valuators = xiev->valuators.values; - for (int i = 0; i <= v.max; ++i) { - if (XIMaskIsSet(xiev->valuators.mask, i)) { - // Convert values to unsigned ints representing ms before storing them, - // as that is how they were encoded before conversion to doubles. - if (vx && v.fling_vx_dbl == i) { - *vx = natural_scroll_factor * *valuators; - } else if (vx && v.fling_vx == i) { - *vx = natural_scroll_factor * - static_cast<double>(static_cast<int>(*valuators)) / 1000.0f; - } else if (vy && v.fling_vy_dbl == i) { - *vy = natural_scroll_factor * *valuators; - } else if (vy && v.fling_vy == i) { - *vy = natural_scroll_factor * - static_cast<double>(static_cast<int>(*valuators)) / 1000.0f; - } else if (is_cancel && v.fling_state == i) { - *is_cancel = !!static_cast<unsigned int>(*valuators); - } else if (vx_ordinal && v.ordinal_x == i) { - *vx_ordinal = *valuators * natural_scroll_factor; - } else if (vy_ordinal && v.ordinal_y == i) { - *vy_ordinal = *valuators * natural_scroll_factor; - } - valuators++; - } - } - - return true; - } - - bool GetGestureTimes(const XEvent& xev, - double* start_time, - double* end_time) { - *start_time = 0; - *end_time = 0; - - XIDeviceEvent* xiev = static_cast<XIDeviceEvent*>(xev.xcookie.data); - if (!cmt_devices_[xiev->sourceid]) - return false; - - Valuators v = device_to_valuators_[xiev->sourceid]; - if ((!XIMaskIsSet(xiev->valuators.mask, v.start_time) && - !XIMaskIsSet(xiev->valuators.mask, v.start_time_dbl)) || - (!XIMaskIsSet(xiev->valuators.mask, v.end_time) && - !XIMaskIsSet(xiev->valuators.mask, v.end_time_dbl))) - return false; - - double* valuators = xiev->valuators.values; - for (int i = 0; i <= v.max; ++i) { - if (XIMaskIsSet(xiev->valuators.mask, i)) { - if (v.start_time_dbl == i) { - *start_time = *valuators; - } else if (v.start_time == i) { - // Convert values to unsigned ints representing ms before storing - // them, as that is how they were encoded before conversion - // to doubles. - *start_time = - static_cast<double>( - static_cast<unsigned int>(*valuators)) / 1000; - } else if (v.end_time_dbl == i) { - *end_time = *valuators; - } else if (v.end_time == i) { - // Convert values to unsigned ints representing ms before storing - // them, as that is how they were encoded before conversion - // to doubles. - *end_time = - static_cast<double>( - static_cast<unsigned int>(*valuators)) / 1000; - } - valuators++; - } - } - - return true; - } - - private: - // Requirement for Singleton - friend struct DefaultSingletonTraits<CMTEventData>; - - struct Valuators { - int max; - int scroll_x; - int scroll_y; - int ordinal_x; - int ordinal_y; - int finger_count; - int start_time; - int end_time; - int fling_vx; - int fling_vy; - int fling_state; - // *_dbl valuators take precedence over the fixed precision versions. - int start_time_dbl; - int end_time_dbl; - int fling_vx_dbl; - int fling_vy_dbl; - - Valuators() - : max(-1), - scroll_x(-1), - scroll_y(-1), - ordinal_x(-1), - ordinal_y(-1), - finger_count(-1), - start_time(-1), - end_time(-1), - fling_vx(-1), - fling_vy(-1), - fling_state(-1), - start_time_dbl(-1), - end_time_dbl(-1), - fling_vx_dbl(-1), - fling_vy_dbl(-1) { - } - - }; - - CMTEventData() - : natural_scroll_enabled_(false), - atom_cache_(ui::GetXDisplay(), kCMTCachedAtoms) { - UpdateDeviceList(ui::GetXDisplay()); - } - - ~CMTEventData() {} - - // A quick lookup table for determining if events from the pointer device - // should be processed. - static const int kMaxDeviceNum = 128; - bool natural_scroll_enabled_; - std::bitset<kMaxDeviceNum> cmt_devices_; - std::bitset<kMaxDeviceNum> touchpads_; - std::map<int, Valuators> device_to_valuators_; - ui::X11AtomCache atom_cache_; - - DISALLOW_COPY_AND_ASSIGN(CMTEventData); -}; - // A class to track current modifier state on master device. Only track ctrl, // alt, shift and caps lock keys currently. The tracked state can then be used // by floating device. @@ -540,8 +130,8 @@ bool TouchEventIsGeneratedHack(const base::NativeEvent& native_event) { double radius = ui::GetTouchRadiusX(native_event), min, max; unsigned int deviceid = static_cast<XIDeviceEvent*>(native_event->xcookie.data)->sourceid; - if (!ui::ValuatorTracker::GetInstance()->GetValuatorRange( - deviceid, ui::ValuatorTracker::VAL_TOUCH_MAJOR, &min, &max)) { + if (!ui::DeviceDataManager::GetInstance()->GetDataRange( + deviceid, ui::DeviceDataManager::DT_TOUCH_MAJOR, &min, &max)) { return false; } @@ -645,11 +235,11 @@ ui::EventType GetTouchEventType(const base::NativeEvent& native_event) { // when necessary, by a RWHVV. // TODO(sad): When should _CANCELLED be generated? - ui::ValuatorTracker* valuators = ui::ValuatorTracker::GetInstance(); + ui::DeviceDataManager* manager = ui::DeviceDataManager::GetInstance(); double slot; - if (!valuators->ExtractValuator( - *native_event, ui::ValuatorTracker::VAL_SLOT_ID, &slot)) + if (!manager->GetEventData( + *native_event, ui::DeviceDataManager::DT_TOUCH_SLOT_ID, &slot)) return ui::ET_UNKNOWN; if (!factory->IsSlotUsed(slot)) { @@ -658,8 +248,8 @@ ui::EventType GetTouchEventType(const base::NativeEvent& native_event) { } double tracking; - if (!valuators->ExtractValuator( - *native_event, ui::ValuatorTracker::VAL_TRACKING_ID, &tracking)) + if (!manager->GetEventData( + *native_event, ui::DeviceDataManager::DT_TOUCH_TRACKING_ID, &tracking)) return ui::ET_UNKNOWN; if (tracking == 0l) { @@ -672,9 +262,9 @@ ui::EventType GetTouchEventType(const base::NativeEvent& native_event) { } double GetTouchParamFromXEvent(XEvent* xev, - ui::ValuatorTracker::Valuator val, + ui::DeviceDataManager::DataType val, double default_value) { - ui::ValuatorTracker::GetInstance()->ExtractValuator( + ui::DeviceDataManager::GetInstance()->GetEventData( *xev, val, &default_value); return default_value; } @@ -692,9 +282,8 @@ namespace ui { void UpdateDeviceList() { Display* display = GetXDisplay(); DeviceListCacheX::GetInstance()->UpdateDeviceList(display); - CMTEventData::GetInstance()->UpdateDeviceList(display); TouchFactory::GetInstance()->UpdateDeviceList(display); - ValuatorTracker::GetInstance()->SetupValuator(); + DeviceDataManager::GetInstance()->UpdateDeviceList(display); } EventType EventTypeFromNative(const base::NativeEvent& native_event) { @@ -752,8 +341,8 @@ EventType EventTypeFromNative(const base::NativeEvent& native_event) { bool is_cancel; if (GetFlingData(native_event, NULL, NULL, NULL, NULL, &is_cancel)) { return is_cancel ? ET_SCROLL_FLING_CANCEL : ET_SCROLL_FLING_START; - } else if (GetScrollOffsets( - native_event, NULL, NULL, NULL, NULL, NULL)) { + } else if (DeviceDataManager::GetInstance()->IsScrollEvent( + native_event)) { return IsTouchpadEvent(native_event) ? ET_SCROLL : ET_MOUSEWHEEL; } else if (GetButtonMaskForX2Event(xievent)) { return ET_MOUSE_DRAGGED; @@ -849,8 +438,8 @@ base::TimeDelta EventTimeFromNative(const base::NativeEvent& native_event) { if (GetGestureTimes(native_event, &start, &end)) { // If the driver supports gesture times, use them. return base::TimeDelta::FromMicroseconds(end * 1000000); - } else if (ValuatorTracker::GetInstance()->ExtractValuator(*native_event, - ValuatorTracker::VAL_TOUCH_RAW_TIMESTAMP, &touch_timestamp)) { + } else if (DeviceDataManager::GetInstance()->GetEventData(*native_event, + DeviceDataManager::DT_TOUCH_RAW_TIMESTAMP, &touch_timestamp)) { return base::TimeDelta::FromMicroseconds(touch_timestamp * 1000000); } else { XIDeviceEvent* xide = @@ -998,10 +587,9 @@ int GetChangedMouseButtonFlagsFromNative( } gfx::Vector2d GetMouseWheelOffset(const base::NativeEvent& native_event) { - float x_offset = 0; - float y_offset = 0; - if (native_event->type == GenericEvent && - GetScrollOffsets(native_event, &x_offset, &y_offset, NULL, NULL, NULL)) { + float x_offset, y_offset; + if (GetScrollOffsets( + native_event, &x_offset, &y_offset, NULL, NULL, NULL)) { return gfx::Vector2d(static_cast<int>(x_offset), static_cast<int>(y_offset)); } @@ -1030,12 +618,12 @@ int GetTouchId(const base::NativeEvent& xev) { return slot; } - ui::ValuatorTracker* valuators = ui::ValuatorTracker::GetInstance(); + ui::DeviceDataManager* manager = ui::DeviceDataManager::GetInstance(); #if defined(USE_XI2_MT) double tracking_id; - if (!valuators->ExtractValuator( - *xev, ui::ValuatorTracker::VAL_TRACKING_ID, &tracking_id)) { + if (!manager->GetEventData( + *xev, ui::DeviceDataManager::DT_TOUCH_TRACKING_ID, &tracking_id)) { LOG(ERROR) << "Could not get the slot ID for the event. Using 0."; } else { slot = factory->GetSlotForTrackingID(tracking_id); @@ -1046,8 +634,8 @@ int GetTouchId(const base::NativeEvent& xev) { } } #else - if (!valuators->ExtractValuator( - *xev, ui::ValuatorTracker::VAL_SLOT_ID, &slot)) + if (!manager->GetEventData( + *xev, ui::DeviceDataManager::DT_TOUCH_SLOT_ID, &slot)) LOG(ERROR) << "Could not get the slot ID for the event. Using 0."; #endif return slot; @@ -1055,28 +643,28 @@ int GetTouchId(const base::NativeEvent& xev) { float GetTouchRadiusX(const base::NativeEvent& native_event) { return GetTouchParamFromXEvent(native_event, - ui::ValuatorTracker::VAL_TOUCH_MAJOR, 0.0) / 2.0; + ui::DeviceDataManager::DT_TOUCH_MAJOR, 0.0) / 2.0; } float GetTouchRadiusY(const base::NativeEvent& native_event) { return GetTouchParamFromXEvent(native_event, - ui::ValuatorTracker::VAL_TOUCH_MINOR, 0.0) / 2.0; + ui::DeviceDataManager::DT_TOUCH_MINOR, 0.0) / 2.0; } float GetTouchAngle(const base::NativeEvent& native_event) { return GetTouchParamFromXEvent(native_event, - ui::ValuatorTracker::VAL_ORIENTATION, 0.0) / 2.0; + ui::DeviceDataManager::DT_TOUCH_ORIENTATION, 0.0) / 2.0; } float GetTouchForce(const base::NativeEvent& native_event) { double force = 0.0; force = GetTouchParamFromXEvent(native_event, - ui::ValuatorTracker::VAL_PRESSURE, 0.0); + ui::DeviceDataManager::DT_TOUCH_PRESSURE, 0.0); unsigned int deviceid = static_cast<XIDeviceEvent*>(native_event->xcookie.data)->sourceid; // Force is normalized to fall into [0, 1] - if (!ui::ValuatorTracker::GetInstance()->NormalizeValuator( - deviceid, ui::ValuatorTracker::VAL_PRESSURE, &force)) + if (!ui::DeviceDataManager::GetInstance()->NormalizeData( + deviceid, ui::DeviceDataManager::DT_TOUCH_PRESSURE, &force)) force = 0.0; return force; } @@ -1087,11 +675,30 @@ bool GetScrollOffsets(const base::NativeEvent& native_event, float* x_offset_ordinal, float* y_offset_ordinal, int* finger_count) { - return CMTEventData::GetInstance()->GetScrollOffsets( - *native_event, + if (!DeviceDataManager::GetInstance()->IsScrollEvent(native_event)) + return false; + + // Temp values to prevent passing NULLs to DeviceDataManager. + float x_offset_, y_offset_; + float x_offset_ordinal_, y_offset_ordinal_; + int finger_count_; + if (!x_offset) + x_offset = &x_offset_; + if (!y_offset) + y_offset = &y_offset_; + if (!x_offset_ordinal) + x_offset_ordinal = &x_offset_ordinal_; + if (!y_offset_ordinal) + y_offset_ordinal = &y_offset_ordinal_; + if (!finger_count) + finger_count = &finger_count_; + + DeviceDataManager::GetInstance()->GetScrollOffsets( + native_event, x_offset, y_offset, x_offset_ordinal, y_offset_ordinal, finger_count); + return true; } bool GetFlingData(const base::NativeEvent& native_event, @@ -1100,27 +707,55 @@ bool GetFlingData(const base::NativeEvent& native_event, float* vx_ordinal, float* vy_ordinal, bool* is_cancel) { - return CMTEventData::GetInstance()->GetFlingData( - *native_event, vx, vy, vx_ordinal, vy_ordinal, is_cancel); + if (!DeviceDataManager::GetInstance()->IsFlingEvent(native_event)) + return false; + + float vx_, vy_; + float vx_ordinal_, vy_ordinal_; + bool is_cancel_; + if (!vx) + vx = &vx_; + if (!vy) + vy = &vy_; + if (!vx_ordinal) + vx_ordinal = &vx_ordinal_; + if (!vy_ordinal) + vy_ordinal = &vy_ordinal_; + if (!is_cancel) + is_cancel = &is_cancel_; + + DeviceDataManager::GetInstance()->GetFlingData( + native_event, vx, vy, vx_ordinal, vy_ordinal, is_cancel); + return true; } bool GetGestureTimes(const base::NativeEvent& native_event, double* start_time, double* end_time) { - return CMTEventData::GetInstance()->GetGestureTimes( - *native_event, start_time, end_time); + if (!DeviceDataManager::GetInstance()->HasGestureTimes(native_event)) + return false; + + double start_time_, end_time_; + if (!start_time) + start_time = &start_time_; + if (!end_time) + end_time = &end_time_; + + DeviceDataManager::GetInstance()->GetGestureTimes( + native_event, start_time, end_time); + return true; } void SetNaturalScroll(bool enabled) { - CMTEventData::GetInstance()->set_natural_scroll_enabled(enabled); + DeviceDataManager::GetInstance()->set_natural_scroll_enabled(enabled); } bool IsNaturalScrollEnabled() { - return CMTEventData::GetInstance()->natural_scroll_enabled(); + return DeviceDataManager::GetInstance()->natural_scroll_enabled(); } bool IsTouchpadEvent(const base::NativeEvent& event) { - return CMTEventData::GetInstance()->IsTouchpadXInputEvent(event); + return DeviceDataManager::GetInstance()->IsTouchpadXInputEvent(event); } bool IsNoopEvent(const base::NativeEvent& event) { diff --git a/ui/base/x/valuators.cc b/ui/base/x/valuators.cc deleted file mode 100644 index da0490e..0000000 --- a/ui/base/x/valuators.cc +++ /dev/null @@ -1,184 +0,0 @@ -// Copyright (c) 2012 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/base/x/valuators.h" - -#include <X11/extensions/XInput2.h> - -#include "base/memory/singleton.h" -#include "ui/base/touch/touch_factory_x11.h" -#include "ui/base/x/device_list_cache_x.h" -#include "ui/base/x/x11_util.h" - -namespace { - -#define AXIS_LABEL_ABS_MT_TOUCH_MAJOR "Abs MT Touch Major" -#define AXIS_LABEL_ABS_MT_TOUCH_MINOR "Abs MT Touch Minor" -#define AXIS_LABEL_ABS_MT_ORIENTATION "Abs MT Orientation" -#define AXIS_LABEL_ABS_MT_PRESSURE "Abs MT Pressure" -#define AXIS_LABEL_ABS_MT_SLOT_ID "Abs MT Slot ID" -#define AXIS_LABEL_ABS_MT_TRACKING_ID "Abs MT Tracking ID" -#define AXIS_LABEL_TOUCH_TIMESTAMP "Touch Timestamp" - -// Given the Valuator, return the correspoding XIValuatorClassInfo using -// the X device information through Atom name matching. -XIValuatorClassInfo* FindValuator(Display* display, - XIDeviceInfo* info, - ui::ValuatorTracker::Valuator val) { - // Lookup table for mapping Valuator to Atom string used in X. - // A full set of Atom strings can be found at xserver-properties.h. - static struct { - ui::ValuatorTracker::Valuator val; - Atom atom; - } kValuatorAtom[] = { - { ui::ValuatorTracker::VAL_TOUCH_MAJOR, - XInternAtom(ui::GetXDisplay(), AXIS_LABEL_ABS_MT_TOUCH_MAJOR, false) }, - { ui::ValuatorTracker::VAL_TOUCH_MINOR, - XInternAtom(ui::GetXDisplay(), AXIS_LABEL_ABS_MT_TOUCH_MINOR, false) }, - { ui::ValuatorTracker::VAL_ORIENTATION, - XInternAtom(ui::GetXDisplay(), AXIS_LABEL_ABS_MT_ORIENTATION, false) }, - { ui::ValuatorTracker::VAL_PRESSURE, - XInternAtom(ui::GetXDisplay(), AXIS_LABEL_ABS_MT_PRESSURE, false) }, -#if !defined(USE_XI2_MT) - // For Slot ID, See this chromeos revision: http://git.chromium.org/gitweb/? - // p=chromiumos/overlays/chromiumos-overlay.git; - // a=commit;h=9164d0a75e48c4867e4ef4ab51f743ae231c059a - { ui::ValuatorTracker::VAL_SLOT_ID, - XInternAtom(ui::GetXDisplay(), AXIS_LABEL_ABS_MT_SLOT_ID, false) }, -#endif - { ui::ValuatorTracker::VAL_TRACKING_ID, - XInternAtom(ui::GetXDisplay(), AXIS_LABEL_ABS_MT_TRACKING_ID, false) }, - { ui::ValuatorTracker::VAL_TOUCH_RAW_TIMESTAMP, - XInternAtom(ui::GetXDisplay(), AXIS_LABEL_TOUCH_TIMESTAMP, false) }, - { ui::ValuatorTracker::VAL_LAST_ENTRY, None }, - }; - - Atom atom = None; - - for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kValuatorAtom); i++) { - if (val == kValuatorAtom[i].val) { - atom = kValuatorAtom[i].atom; - break; - } - } - - if (atom == None) - return NULL; - - for (int i = 0; i < info->num_classes; i++) { - if (info->classes[i]->type != XIValuatorClass) - continue; - XIValuatorClassInfo* v = - reinterpret_cast<XIValuatorClassInfo*>(info->classes[i]); - if (v->label && atom == v->label) - return v; - } - - return NULL; -} - -} // namespace - -namespace ui { - -ValuatorTracker::ValuatorTracker() { - SetupValuator(); -} - -ValuatorTracker::~ValuatorTracker() { -} - -// static -ValuatorTracker* ValuatorTracker::GetInstance() { - return Singleton<ValuatorTracker>::get(); -} - -bool ValuatorTracker::ExtractValuator(const XEvent& xev, - Valuator val, - double* value) { - XIDeviceEvent* xiev = static_cast<XIDeviceEvent*>(xev.xcookie.data); - if (xiev->sourceid >= kMaxDeviceNum || xiev->deviceid >= kMaxDeviceNum) - return false; - int val_index = valuator_lookup_[xiev->sourceid][val]; - if (val_index >= 0) { - if (XIMaskIsSet(xiev->valuators.mask, val_index)) { - double* valuators = xiev->valuators.values; - while (val_index--) { - if (XIMaskIsSet(xiev->valuators.mask, val_index)) - ++valuators; - } - *value = *valuators; - last_seen_valuator_[xiev->deviceid][val] = *value; - return true; - } else { - *value = last_seen_valuator_[xiev->deviceid][val]; - } - } - -#if defined(USE_XI2_MT) - // With XInput2 MT, Tracking ID is provided in the detail field. - if (val == VAL_TRACKING_ID) { - *value = xiev->detail; - return true; - } -#endif - - return false; -} - -bool ValuatorTracker::NormalizeValuator(unsigned int deviceid, - Valuator val, - double* value) { - double max_value; - double min_value; - if (GetValuatorRange(deviceid, val, &min_value, &max_value)) { - *value = (*value - min_value) / (max_value - min_value); - DCHECK(*value >= 0.0 && *value <= 1.0); - return true; - } - return false; -} - -bool ValuatorTracker::GetValuatorRange(unsigned int deviceid, - Valuator val, - double* min, - double* max) { - if (valuator_lookup_[deviceid][val] >= 0) { - *min = valuator_min_[deviceid][val]; - *max = valuator_max_[deviceid][val]; - return true; - } - return false; -} - -void ValuatorTracker::SetupValuator() { - memset(valuator_lookup_, -1, sizeof(valuator_lookup_)); - memset(valuator_min_, 0, sizeof(valuator_min_)); - memset(valuator_max_, 0, sizeof(valuator_max_)); - memset(last_seen_valuator_, 0, sizeof(last_seen_valuator_)); - - Display* display = GetXDisplay(); - XIDeviceList info_list = - DeviceListCacheX::GetInstance()->GetXI2DeviceList(display); - TouchFactory* factory = TouchFactory::GetInstance(); - - for (int i = 0; i < info_list.count; i++) { - XIDeviceInfo* info = info_list.devices + i; - - if (!factory->IsTouchDevice(info->deviceid)) - continue; - - for (int j = 0; j < VAL_LAST_ENTRY; j++) { - Valuator val = static_cast<Valuator>(j); - XIValuatorClassInfo* valuator = FindValuator(display, info, val); - if (valuator) { - valuator_lookup_[info->deviceid][j] = valuator->number; - valuator_min_[info->deviceid][j] = valuator->min; - valuator_max_[info->deviceid][j] = valuator->max; - } - } - } -} - -} // namespace ui diff --git a/ui/base/x/valuators.h b/ui/base/x/valuators.h deleted file mode 100644 index 6a3168a..0000000 --- a/ui/base/x/valuators.h +++ /dev/null @@ -1,117 +0,0 @@ -// Copyright (c) 2012 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. - -#ifndef UI_BASE_X_VALUATORS_H_ -#define UI_BASE_X_VALUATORS_H_ - -#include "base/basictypes.h" -#include "ui/base/ui_export.h" - -template <typename T> struct DefaultSingletonTraits; - -typedef union _XEvent XEvent; - -namespace ui { - -// A valuator is not reported in an XEvent if it hasn't changed from the -// previous event from the same device. As a result, it is necessary to track -// the last reported valuator values for a specific device. -// Right now, this is only used to keep track of valuators for events coming in -// from touch-devices, but it can be used for other devices as well. -class UI_EXPORT ValuatorTracker { - private: - ValuatorTracker(); - ~ValuatorTracker(); - - public: - // Define the valuators following the Multi-touch Protocol. - enum Valuator { - VAL_TOUCH_MAJOR = 0, // Length of the touch area. - VAL_TOUCH_MINOR, // Width of the touch area. - VAL_ORIENTATION, // Angle between the X-axis and the major axis of the - // touch area. - VAL_PRESSURE, // Pressure of the touch contact. - - // NOTE: A touch event can have multiple touch points. So when we receive a - // touch event, we need to determine which point triggered the event. - // A touch point can have both a 'Slot ID' and a 'Tracking ID', and they can - // be (in fact, usually are) different. The 'Slot ID' ranges between 0 and - // (X - 1), where X is the maximum touch points supported by the device. The - // 'Tracking ID' can be any 16-bit value. With XInput 2.0, an XI_Motion - // event that comes from a currently-unused 'Slot ID' indicates the creation - // of a new touch point, and any event that comes with a 0 value for - // 'Tracking ID' marks the removal of a touch point. During the lifetime of - // a touchpoint, we use the 'Slot ID' as its identifier. The XI_ButtonPress - // and XI_ButtonRelease events are ignored. -#if !defined(USE_XI2_MT) - VAL_SLOT_ID, // ID of the finger that triggered a touch event - // (useful when tracking multiple simultaneous - // touches) -#endif - // NOTE for XInput MT: 'Tracking ID' is provided in every touch event to - // track individual touch. 'Tracking ID' is an unsigned 32-bit value and - // is increased for each new touch. It will wrap back to 0 when reaching - // the numerical limit. - VAL_TRACKING_ID, // ID of the touch point. - - // Kernel timestamp from touch screen (if available). - VAL_TOUCH_RAW_TIMESTAMP, - - VAL_LAST_ENTRY - }; - - // Returns the ValuatorTracker singleton. - static ValuatorTracker* GetInstance(); - - // Extract the Valuator from the XEvent. Return true and the value is set - // if the Valuator is found, false and value unchanged if the Valuator - // is not found. - bool ExtractValuator(const XEvent& xev, Valuator val, double* value); - - // Normalize the Valuator with value on deviceid to fall into [0, 1]. - // *value = (*value - min_value_of_tp) / (max_value_of_tp - min_value_of_tp) - // Returns true and sets the normalized value in|value| if normalization is - // successful. Returns false and |value| is unchanged otherwise. - bool NormalizeValuator(unsigned int deviceid, Valuator val, double* value); - - // Extract the range of the Valuator. Return true if the range is available - // and written into min & max, false if the range is not available. - bool GetValuatorRange(unsigned int deviceid, - Valuator val, - double* min, - double* max); - - // Sets up the internal bookkeeping of the valuator information. It currently - // does this for touch devices only. - void SetupValuator(); - - private: - // Requirement for Singleton. - friend struct DefaultSingletonTraits<ValuatorTracker>; - - static const int kMaxDeviceNum = 128; - - // Index table to find the valuator for the Valuator on the specific device - // by valuator_lookup_[device_id][valuator]. Use 2-D array to get fast - // index at the expense of space. If the kMaxDeviceNum grows larger so that - // the space waste becomes a concern, the 2D lookup table can be replaced by a - // hash map. - signed char valuator_lookup_[kMaxDeviceNum][VAL_LAST_ENTRY]; - - // Index table to find the min & max value of the Valuator on a specific - // device. - double valuator_min_[kMaxDeviceNum][VAL_LAST_ENTRY]; - double valuator_max_[kMaxDeviceNum][VAL_LAST_ENTRY]; - - // Table to keep track of the last seen value for the specified valuator for - // a device. Defaults to 0 if the valuator was not specified in an earlier - // event. - double last_seen_valuator_[kMaxDeviceNum][VAL_LAST_ENTRY]; - - DISALLOW_COPY_AND_ASSIGN(ValuatorTracker); -}; - -} // namespace ui - -#endif // UI_BASE_X_VALUATORS_H_ diff --git a/ui/base/x/x11_util.cc b/ui/base/x/x11_util.cc index 5034ea1..4d06195 100644 --- a/ui/base/x/x11_util.cc +++ b/ui/base/x/x11_util.cc @@ -35,7 +35,7 @@ #include "ui/base/events/event_utils.h" #include "ui/base/keycodes/keyboard_code_conversion_x.h" #include "ui/base/touch/touch_factory_x11.h" -#include "ui/base/x/valuators.h" +#include "ui/base/x/device_data_manager.h" #include "ui/base/x/x11_util_internal.h" #include "ui/gfx/point_conversions.h" #include "ui/gfx/rect.h" @@ -520,8 +520,8 @@ int CoalescePendingMotionEvents(const XEvent* xev, if (next_event.type == GenericEvent && next_event.xgeneric.evtype == event_type && - !ui::GetScrollOffsets(&next_event, NULL, NULL, NULL, NULL, NULL) && - !ui::GetFlingData(&next_event, NULL, NULL, NULL, NULL, NULL)) { + !ui::DeviceDataManager::GetInstance()->IsCMTGestureEvent( + &next_event)) { XIDeviceEvent* next_xievent = static_cast<XIDeviceEvent*>(next_event.xcookie.data); // Confirm that the motion event is targeted at the same window |