blob: daadcb877bd40fe01f074e82646e64d8548ca708 [file] [log] [blame]
// Copyright 2014 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 <bitset>
#include <functional>
#include <map>
#include <memory>
#include <set>
#include <vector>
#include "base/macros.h"
#include "ui/events/devices/device_data_manager.h"
#include "ui/events/devices/x11/events_devices_x11_export.h"
#include "ui/events/event_constants.h"
#include "ui/events/keycodes/keyboard_codes.h"
#include "ui/events/platform_event.h"
#include "ui/gfx/geometry/rect.h"
#include "ui/gfx/x/x11.h"
#include "ui/gfx/x/x11_types.h"
namespace ui {
// CrOS touchpad metrics gesture types
enum GestureMetricsType {
kGestureMetricsTypeNoisyGround = 0,
// A bitfield describing which scroll axes are enabled for a device.
enum ScrollType {
// A class that extracts and tracks the input events data. It currently handles
// mouse, touchpad and touchscreen devices.
class EVENTS_DEVICES_X11_EXPORT DeviceDataManagerX11
: public DeviceDataManager {
// 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
// started flinging or they tapped down).
DT_CMT_METRICS_TYPE, // Metrics type of the metrics gesture, which are
// used to wrap interesting patterns that we would
// like to track via the UMA system.
DT_CMT_METRICS_DATA1, // Complementary data 1 of the metrics gesture.
DT_CMT_METRICS_DATA2, // Complementary data 2 of the metrics gesture.
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.
DT_TOUCH_POSITION_X, // Touch X position.
DT_TOUCH_POSITION_Y, // Touch Y position.
// 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).
// End of touch data types.
DT_LAST_ENTRY // This must come last.
// A Device ID number that can be passed to InvalidateScrollClasses that
// invalidates all devices.
static const int kAllDevices = -1;
// Data struct to store extracted data from an input event.
typedef std::map<int, double> EventData;
static void CreateInstance();
// 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 DeviceDataManagerX11 singleton.
static DeviceDataManagerX11* GetInstance();
// Returns if XInput2 is available on the system.
bool IsXInput2Available() const;
// Updates the list of devices.
void UpdateDeviceList(Display* display);
// For multitouch events we use slot number to distinguish touches from
// different fingers. This function returns true if the associated slot
// for |xiev| can be found and it is saved in |slot|, returns false if
// no slot can be found.
bool GetSlotNumber(const XIDeviceEvent* xiev, int* slot);
// Check if an XI event contains data of the specified type.
bool HasEventData(const XIDeviceEvent* xiev, const DataType type) const;
// 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 is an XI input event in the strict sense
// (i.e. XIDeviceEvent). This rules out things like hierarchy changes,
/// device changes, property changes and so on.
bool IsXIDeviceEvent(const XEvent& xev) const;
// Check if the event comes from touchpad devices.
bool IsTouchpadXInputEvent(const XEvent& xev) 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 XEvent& xev) const;
// Check if the event contains information about a ScrollClass, and
// report which scroll axes are contained in this event, defined by
// ScrollType.
int GetScrollClassEventDetail(const XEvent& xev) const;
// Check if the event comes from a device that has a ScrollClass, and
// report which scroll axes it supports as a bit field, defined by
// ScrollType.
int GetScrollClassDeviceDetail(const XEvent& xev) const;
// Check if the event is one of the CMT gesture events (scroll, fling,
// metrics etc.).
bool IsCMTGestureEvent(const XEvent& xev) const;
// Returns true if the event is of the specific type, false if not.
bool IsScrollEvent(const XEvent& xev) const;
bool IsFlingEvent(const XEvent& xev) const;
bool IsCMTMetricsEvent(const XEvent& xev) const;
// Returns true if the event has CMT start/end timestamps.
bool HasGestureTimes(const XEvent& xev) 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 XEvent& xev,
float* x_offset,
float* y_offset,
float* x_offset_ordinal,
float* y_offset_ordinal,
int* finger_count);
// Extract data from a scroll class event (smooth scrolling). User must
// first verify the event type with GetScrollClassEventDetail.
// Pointers shouldn't be NULL.
void GetScrollClassOffsets(const XEvent& xev,
double* x_offset,
double* y_offset);
// Invalidate stored scroll class counters, since they can change when
// pointing at other windows. If kAllDevices is specified, all devices are
// invalidated.
void InvalidateScrollClasses(int device_id);
// Extract data from a fling event. User must first verify the event type
// with IsFlingEvent. Pointers shouldn't be NULL.
void GetFlingData(const XEvent& xev,
float* vx,
float* vy,
float* vx_ordinal,
float* vy_ordinal,
bool* is_cancel);
// Extract data from a CrOS metrics gesture event. User must first verify
// the event type with IsCMTMetricsEvent. Pointers shouldn't be NULL.
void GetMetricsData(const XEvent& xev,
GestureMetricsType* type,
float* data1,
float* data2);
// Returns the mapped button.
int GetMappedButton(int button);
// Updates button mapping. This is usually called when a MappingNotify event
// is received.
void UpdateButtonMap();
// Extract the start/end timestamps from CMT events. User must first verify
// the event with HasGestureTimes. Pointers shouldn't be NULL.
void GetGestureTimes(const XEvent& xev, 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(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(int deviceid,
const DataType type,
double* min,
double* max);
// Sets up relevant valuator informations for device ids in the device lists.
// This function is only for test purpose. It does not query the X server for
// the actual device info, but rather inits the relevant valuator structures
// to have safe default values for testing.
void SetDeviceListForTest(const std::vector<int>& touchscreen,
const std::vector<int>& cmt_devices,
const std::vector<int>& other_devices);
void SetValuatorDataForTest(XIDeviceEvent* xievent,
DataType type,
double value);
// Sets the keys which are still allowed on a disabled keyboard device.
void SetDisabledKeyboardAllowedKeys(
std::unique_ptr<std::set<KeyboardCode>> excepted_keys);
// Disables and enables events from devices by device id.
void DisableDevice(int deviceid);
void EnableDevice(int deviceid);
bool IsDeviceEnabled(int device_id) const;
// Returns true if |native_event| should be blocked.
bool IsEventBlocked(const XEvent& xev);
const std::vector<int>& master_pointers() const {
return master_pointers_;
// DeviceHotplugEventObserver:
void OnKeyboardDevicesUpdated(
const std::vector<InputDevice>& devices) override;
// Information about scroll valuators
struct ScrollInfo {
struct AxisInfo {
// The scroll valuator number of this scroll axis.
int number;
// The scroll increment; a value of n indicates n movement equals one
// traditional scroll unit.
double increment;
// Current scroll position; used to find the difference between events.
double position;
// If true then scroll has been seen in this direction.
bool seen;
AxisInfo vertical, horizontal;
// Information from XIValuatorClassInfo.
struct ValuatorInfo {
// The valuator number.
int number = -1;
// The valuator min value.
double min = 0.0;
// The valuator max value.
double max = 0.0;
~DeviceDataManagerX11() override;
// Initialize the XInput related system information.
bool InitializeXInputInternal();
void InitializeValuatorsForTest(int deviceid,
int start_valuator,
int end_valuator,
double min_value,
double max_value);
// Updates a device based on a Valuator class info. Returns true if the
// device is a possible CMT device.
bool UpdateValuatorClassDevice(XIValuatorClassInfo* valuator_class_info,
Atom* atoms,
int deviceid);
// Updates a device based on a Scroll class info.
void UpdateScrollClassDevice(XIScrollClassInfo* scroll_class_info,
int deviceid);
// Normalize the scroll amount according to the increment size.
// *value /= increment
// *value is expected to be 1 or -1.
// Returns true and sets the normalized value in |value| if normalization is
// successful. Returns false and |value| is unchanged otherwise.
double ExtractAndUpdateScrollOffset(
DeviceDataManagerX11::ScrollInfo::AxisInfo* axis,
double valuator) const;
static const int kMaxXIEventType = XI_LASTEVENT + 1;
static const int kMaxSlotNum = 10;
// Major opcode for the XInput extension. Used to identify XInput events.
int xi_opcode_;
// A quick lookup table for determining if the XI event is an XIDeviceEvent.
std::bitset<kMaxXIEventType> xi_device_event_types_;
// A quick lookup table for determining if events from the pointer device
// should be processed.
std::bitset<kMaxDeviceNum> cmt_devices_;
std::bitset<kMaxDeviceNum> touchpads_;
// List of the master pointer devices.
std::vector<int> master_pointers_;
// A quick lookup table for determining if events from the XI device
// should be blocked.
std::bitset<kMaxDeviceNum> blocked_devices_;
// The set of keys allowed while the keyboard is blocked.
std::unique_ptr<std::set<KeyboardCode>> blocked_keyboard_allowed_keys_;
// Number of valuators on the specific device.
int valuator_count_[kMaxDeviceNum];
// Index table to find valuator number, min and max for DataType on the
// specific device by valuator_lookup_[device_id][data_type].
std::vector<ValuatorInfo> valuator_lookup_[kMaxDeviceNum];
// Indicates if the user has disabled high precision scrolling support.
bool high_precision_scrolling_disabled_;
// Index table to find the horizontal and vertical scroll valuator
// numbers, scroll increments and scroll position.
ScrollInfo scroll_data_[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];
// Table to keep track of the last seen value for the specified valuator for
// a specified slot of a device. Defaults to 0 if the valuator for that slot
// 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][kMaxSlotNum];
// Map that stores meta-data for blocked keyboards. This is needed to restore
// devices when they are re-enabled.
std::map<int, ui::InputDevice> blocked_keyboard_devices_;
unsigned char button_map_[256];
int button_map_count_;
} // namespace ui