Commit 73559934 authored by miletus@chromium.org's avatar miletus@chromium.org

Scale touch event radius

Touch event's position resolution could be quite different than the
display's resolution, e.g.  the display could be set as 1920x1080
while the touchscreen is reporting touch position range at 32767x32767.
Touch event's radius is reported in the units the same as touch position.
While we are doing touch position scaling, we should also do the same
for touch radius.

BUG=392172, 233245
TEST=touch radius is scaled to be reasonable value for HP 23TM
     touch monitor.

Review URL: https://codereview.chromium.org/412553005

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@285132 0039d316-1c4b-4281-b951-d872f2087c98
parent 102b81cd
...@@ -18,71 +18,12 @@ ...@@ -18,71 +18,12 @@
#include "ui/gfx/display.h" #include "ui/gfx/display.h"
#include "ui/gfx/screen.h" #include "ui/gfx/screen.h"
#if defined(OS_CHROMEOS)
#include "ui/display/chromeos/display_configurator.h"
#endif // defined(OS_CHROMEOS)
namespace ash { namespace ash {
namespace { namespace {
// Boost factor for non-integrated displays. // Boost factor for non-integrated displays.
const float kBoostForNonIntegrated = 1.20f; const float kBoostForNonIntegrated = 1.20f;
#if defined(OS_CHROMEOS)
gfx::Size GetNativeModeSize(const DisplayInfo& info) {
const std::vector<DisplayMode>& modes = info.display_modes();
for (size_t i = 0; i < modes.size(); ++i) {
if (modes[i].native)
return modes[i].size;
}
return gfx::Size();
}
float GetMirroredDisplayAreaRatio(const gfx::Size& current_size,
const gfx::Size& native_size) {
float area_ratio = 1.0f;
if (current_size.IsEmpty() || native_size.IsEmpty())
return area_ratio;
float width_ratio = static_cast<float>(current_size.width()) /
static_cast<float>(native_size.width());
float height_ratio = static_cast<float>(current_size.height()) /
static_cast<float>(native_size.height());
area_ratio = width_ratio * height_ratio;
return area_ratio;
}
// Key of the map is the touch display's id, and the value of the map is the
// touch display's area ratio in mirror mode defined as:
// mirror_mode_area / native_mode_area.
// This is used for scaling touch event's radius when the touch display is in
// mirror mode: new_touch_radius = sqrt(area_ratio) * old_touch_radius
std::map<int, float> GetMirroredDisplayAreaRatioMap() {
std::map<int, float> area_ratios;
DisplayManager* display_manager =
ash::Shell::GetInstance()->display_manager();
const std::vector<gfx::Display>& displays = display_manager->displays();
for (size_t i = 0; i < displays.size(); ++i) {
const DisplayInfo& info = display_manager->GetDisplayInfo(
displays[i].id());
const gfx::Size current_size = info.size_in_pixel();
const gfx::Size native_size = GetNativeModeSize(info);
if (info.touch_support() == gfx::Display::TOUCH_SUPPORT_AVAILABLE &&
current_size != native_size &&
info.is_aspect_preserving_scaling()) {
area_ratios[info.touch_device_id()] = GetMirroredDisplayAreaRatio(
current_size, native_size);
}
}
return area_ratios;
}
#endif // defined(OS_CHROMEOS)
} // namespace } // namespace
EventTransformationHandler::EventTransformationHandler() EventTransformationHandler::EventTransformationHandler()
...@@ -109,38 +50,4 @@ void EventTransformationHandler::OnScrollEvent(ui::ScrollEvent* event) { ...@@ -109,38 +50,4 @@ void EventTransformationHandler::OnScrollEvent(ui::ScrollEvent* event) {
event->Scale(kBoostForNonIntegrated); event->Scale(kBoostForNonIntegrated);
} }
#if defined(OS_CHROMEOS)
// This is to scale the TouchEvent's radius when the touch display is in
// mirror mode. TouchEvent's radius is often reported in the touchscreen's
// native resolution. In mirror mode, the touch display could be configured
// at a lower resolution. We scale down the radius using the ratio defined as
// the sqrt of
// (mirror_width * mirror_height) / (native_width * native_height)
void EventTransformationHandler::OnTouchEvent(ui::TouchEvent* event) {
// Check display_configurator's output_state instead of checking
// DisplayManager::IsMirrored() because the compositor based mirroring
// won't cause the scaling issue.
if (ash::Shell::GetInstance()->display_configurator()->display_state() !=
ui::MULTIPLE_DISPLAY_STATE_DUAL_MIRROR)
return;
const std::map<int, float> area_ratio_map = GetMirroredDisplayAreaRatioMap();
// TODO(miletus): When there are more than 1 touchscreen (e.g. Link connected
// to an external touchscreen), the correct way to do is to have a way
// to find out which touchscreen is the event originating from and use the
// area ratio of that touchscreen to scale the event's radius.
// Tracked here crbug.com/233245
if (area_ratio_map.size() != 1) {
LOG(ERROR) << "Mirroring mode with " << area_ratio_map.size()
<< " touch display found";
return;
}
float area_ratio_sqrt = std::sqrt(area_ratio_map.begin()->second);
event->set_radius_x(event->radius_x() * area_ratio_sqrt);
event->set_radius_y(event->radius_y() * area_ratio_sqrt);
}
#endif // defined(OS_CHROMEOS)
} // namespace ash } // namespace ash
...@@ -31,9 +31,6 @@ class ASH_EXPORT EventTransformationHandler : public ui::EventHandler { ...@@ -31,9 +31,6 @@ class ASH_EXPORT EventTransformationHandler : public ui::EventHandler {
// Overridden from ui::EventHandler. // Overridden from ui::EventHandler.
virtual void OnScrollEvent(ui::ScrollEvent* event) OVERRIDE; virtual void OnScrollEvent(ui::ScrollEvent* event) OVERRIDE;
#if defined(OS_CHROMEOS)
virtual void OnTouchEvent(ui::TouchEvent* event) OVERRIDE;
#endif // defined(OS_CHROMEOS)
private: private:
TransformationMode transformation_mode_; TransformationMode transformation_mode_;
......
...@@ -13,6 +13,7 @@ ...@@ -13,6 +13,7 @@
#include "ui/display/chromeos/display_configurator.h" #include "ui/display/chromeos/display_configurator.h"
#include "ui/display/types/chromeos/display_snapshot.h" #include "ui/display/types/chromeos/display_snapshot.h"
#include "ui/events/device_data_manager.h" #include "ui/events/device_data_manager.h"
#include "ui/events/x/device_data_manager_x11.h"
namespace ash { namespace ash {
...@@ -24,6 +25,52 @@ DisplayManager* GetDisplayManager() { ...@@ -24,6 +25,52 @@ DisplayManager* GetDisplayManager() {
} // namespace } // namespace
// This is to compute the scale ratio for the TouchEvent's radius. The
// configured resolution of the display is not always the same as the touch
// screen's reporting resolution, e.g. the display could be set as
// 1920x1080 while the touchscreen is reporting touch position range at
// 32767x32767. Touch radius is reported in the units the same as touch position
// so we need to scale the touch radius to be compatible with the display's
// resolution. We compute the scale as
// sqrt of (display_area / touchscreen_area)
double TouchTransformerController::GetTouchResolutionScale(
const DisplayInfo& touch_display) const {
if (touch_display.touch_device_id() == 0)
return 1.0;
double min_x, max_x;
double min_y, max_y;
if (!ui::DeviceDataManagerX11::GetInstance()->GetDataRange(
touch_display.touch_device_id(),
ui::DeviceDataManagerX11::DT_TOUCH_POSITION_X,
&min_x, &max_x) ||
!ui::DeviceDataManagerX11::GetInstance()->GetDataRange(
touch_display.touch_device_id(),
ui::DeviceDataManagerX11::DT_TOUCH_POSITION_Y,
&min_y, &max_y)) {
return 1.0;
}
double width = touch_display.bounds_in_native().width();
double height = touch_display.bounds_in_native().height();
if (max_x == 0.0 || max_y == 0.0 || width == 0.0 || height == 0.0)
return 1.0;
// [0, max_x] -> touchscreen width = max_x + 1
// [0, max_y] -> touchscreen height = max_y + 1
max_x += 1.0;
max_y += 1.0;
double ratio = std::sqrt((width * height) / (max_x * max_y));
VLOG(2) << "Screen width/height: " << width << "/" << height
<< ", Touchscreen width/height: " << max_x << "/" << max_y
<< ", Touch radius scale ratio: " << ratio;
return ratio;
}
// This function computes the extended mode TouchTransformer for // This function computes the extended mode TouchTransformer for
// |touch_display|. The TouchTransformer maps the touch event position // |touch_display|. The TouchTransformer maps the touch event position
// from framebuffer size to the display size. // from framebuffer size to the display size.
...@@ -158,10 +205,17 @@ void TouchTransformerController::UpdateTouchTransformer() const { ...@@ -158,10 +205,17 @@ void TouchTransformerController::UpdateTouchTransformer() const {
display2_id != gfx::Display::kInvalidDisplayID); display2_id != gfx::Display::kInvalidDisplayID);
display1 = GetDisplayManager()->GetDisplayInfo(display1_id); display1 = GetDisplayManager()->GetDisplayInfo(display1_id);
display2 = GetDisplayManager()->GetDisplayInfo(display2_id); display2 = GetDisplayManager()->GetDisplayInfo(display2_id);
device_manager->UpdateTouchRadiusScale(display1.touch_device_id(),
GetTouchResolutionScale(display1));
device_manager->UpdateTouchRadiusScale(display2.touch_device_id(),
GetTouchResolutionScale(display2));
} else { } else {
single_display_id = GetDisplayManager()->first_display_id(); single_display_id = GetDisplayManager()->first_display_id();
DCHECK(single_display_id != gfx::Display::kInvalidDisplayID); DCHECK(single_display_id != gfx::Display::kInvalidDisplayID);
single_display = GetDisplayManager()->GetDisplayInfo(single_display_id); single_display = GetDisplayManager()->GetDisplayInfo(single_display_id);
device_manager->UpdateTouchRadiusScale(
single_display.touch_device_id(),
GetTouchResolutionScale(single_display));
} }
if (display_state == ui::MULTIPLE_DISPLAY_STATE_DUAL_MIRROR) { if (display_state == ui::MULTIPLE_DISPLAY_STATE_DUAL_MIRROR) {
......
...@@ -34,6 +34,8 @@ class ASH_EXPORT TouchTransformerController ...@@ -34,6 +34,8 @@ class ASH_EXPORT TouchTransformerController
TouchTransformerMirrorModePillarboxing); TouchTransformerMirrorModePillarboxing);
FRIEND_TEST_ALL_PREFIXES(TouchTransformerControllerTest, FRIEND_TEST_ALL_PREFIXES(TouchTransformerControllerTest,
TouchTransformerExtendedMode); TouchTransformerExtendedMode);
FRIEND_TEST_ALL_PREFIXES(TouchTransformerControllerTest,
TouchRadiusScale);
bool ShouldComputeMirrorModeTouchTransformer( bool ShouldComputeMirrorModeTouchTransformer(
const DisplayInfo& touch_display) const ; const DisplayInfo& touch_display) const ;
...@@ -44,6 +46,8 @@ class ASH_EXPORT TouchTransformerController ...@@ -44,6 +46,8 @@ class ASH_EXPORT TouchTransformerController
gfx::Transform GetExtendedModeTouchTransformer( gfx::Transform GetExtendedModeTouchTransformer(
const DisplayInfo& touch_display, const gfx::Size& fb_size) const; const DisplayInfo& touch_display, const gfx::Size& fb_size) const;
double GetTouchResolutionScale(const DisplayInfo& touch_display) const;
// For unittests only. // For unittests only.
bool force_compute_mirror_mode_touch_transformer_; bool force_compute_mirror_mode_touch_transformer_;
......
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
#include "ash/test/ash_test_base.h" #include "ash/test/ash_test_base.h"
#include "ui/aura/window_tree_host.h" #include "ui/aura/window_tree_host.h"
#include "ui/events/device_data_manager.h" #include "ui/events/device_data_manager.h"
#include "ui/events/test/events_test_utils_x11.h"
#include "ui/gfx/display.h" #include "ui/gfx/display.h"
namespace ash { namespace ash {
...@@ -203,4 +204,17 @@ TEST_F(TouchTransformerControllerTest, TouchTransformerExtendedMode) { ...@@ -203,4 +204,17 @@ TEST_F(TouchTransformerControllerTest, TouchTransformerExtendedMode) {
EXPECT_EQ(1599, static_cast<int>(y)); EXPECT_EQ(1599, static_cast<int>(y));
} }
TEST_F(TouchTransformerControllerTest, TouchRadiusScale) {
DisplayInfo display = CreateDisplayInfo(1, 5, gfx::Rect(0, 0, 2560, 1600));
std::vector<unsigned int> devices;
devices.push_back(5);
ui::SetUpTouchDevicesForTest(devices);
TouchTransformerController* tt_controller =
Shell::GetInstance()->touch_transformer_controller();
// Default touchscreen position range is 1001x1001;
EXPECT_EQ(sqrt((2560.0 * 1600.0) / (1001.0 * 1001.0)),
tt_controller->GetTouchResolutionScale(display));
}
} // namespace ash } // namespace ash
...@@ -22,8 +22,10 @@ DeviceDataManager::DeviceDataManager() { ...@@ -22,8 +22,10 @@ DeviceDataManager::DeviceDataManager() {
base::AtExitManager::RegisterTask( base::AtExitManager::RegisterTask(
base::Bind(&base::DeletePointer<DeviceDataManager>, this)); base::Bind(&base::DeletePointer<DeviceDataManager>, this));
for (int i = 0; i < kMaxDeviceNum; ++i) for (int i = 0; i < kMaxDeviceNum; ++i) {
touch_device_to_display_map_[i] = gfx::Display::kInvalidDisplayID; touch_device_to_display_map_[i] = gfx::Display::kInvalidDisplayID;
touch_radius_scale_map_[i] = 1.0;
}
} }
DeviceDataManager::~DeviceDataManager() { DeviceDataManager::~DeviceDataManager() {
...@@ -57,6 +59,7 @@ void DeviceDataManager::ClearTouchTransformerRecord() { ...@@ -57,6 +59,7 @@ void DeviceDataManager::ClearTouchTransformerRecord() {
for (int i = 0; i < kMaxDeviceNum; i++) { for (int i = 0; i < kMaxDeviceNum; i++) {
touch_device_transformer_map_[i] = gfx::Transform(); touch_device_transformer_map_[i] = gfx::Transform();
touch_device_to_display_map_[i] = gfx::Display::kInvalidDisplayID; touch_device_to_display_map_[i] = gfx::Display::kInvalidDisplayID;
touch_radius_scale_map_[i] = 1.0;
} }
} }
...@@ -74,6 +77,18 @@ void DeviceDataManager::UpdateTouchInfoForDisplay( ...@@ -74,6 +77,18 @@ void DeviceDataManager::UpdateTouchInfoForDisplay(
} }
} }
void DeviceDataManager::UpdateTouchRadiusScale(int touch_device_id,
double scale) {
if (IsTouchDeviceIdValid(touch_device_id))
touch_radius_scale_map_[touch_device_id] = scale;
}
void DeviceDataManager::ApplyTouchRadiusScale(int touch_device_id,
double* radius) {
if (IsTouchDeviceIdValid(touch_device_id))
*radius = (*radius) * touch_radius_scale_map_[touch_device_id];
}
void DeviceDataManager::ApplyTouchTransformer(int touch_device_id, void DeviceDataManager::ApplyTouchTransformer(int touch_device_id,
float* x, float* x,
float* y) { float* y) {
......
...@@ -30,6 +30,9 @@ class EVENTS_BASE_EXPORT DeviceDataManager { ...@@ -30,6 +30,9 @@ class EVENTS_BASE_EXPORT DeviceDataManager {
void ApplyTouchTransformer(int touch_device_id, float* x, float* y); void ApplyTouchTransformer(int touch_device_id, float* x, float* y);
int64_t GetDisplayForTouchDevice(int touch_device_id) const; int64_t GetDisplayForTouchDevice(int touch_device_id) const;
void UpdateTouchRadiusScale(int touch_device_id, double scale);
void ApplyTouchRadiusScale(int touch_device_id, double* radius);
protected: protected:
DeviceDataManager(); DeviceDataManager();
...@@ -42,6 +45,8 @@ class EVENTS_BASE_EXPORT DeviceDataManager { ...@@ -42,6 +45,8 @@ class EVENTS_BASE_EXPORT DeviceDataManager {
bool IsTouchDeviceIdValid(int touch_device_id) const; bool IsTouchDeviceIdValid(int touch_device_id) const;
double touch_radius_scale_map_[kMaxDeviceNum];
// Table to keep track of which display id is mapped to which touch device. // Table to keep track of which display id is mapped to which touch device.
int64_t touch_device_to_display_map_[kMaxDeviceNum]; int64_t touch_device_to_display_map_[kMaxDeviceNum];
// Index table to find the TouchTransformer for a touch device. // Index table to find the TouchTransformer for a touch device.
......
...@@ -63,6 +63,8 @@ ...@@ -63,6 +63,8 @@
#define AXIS_LABEL_ABS_MT_TOUCH_MINOR "Abs MT Touch Minor" #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_ORIENTATION "Abs MT Orientation"
#define AXIS_LABEL_ABS_MT_PRESSURE "Abs MT Pressure" #define AXIS_LABEL_ABS_MT_PRESSURE "Abs MT Pressure"
#define AXIS_LABEL_ABS_MT_POSITION_X "Abs MT Position X"
#define AXIS_LABEL_ABS_MT_POSITION_Y "Abs MT Position Y"
#define AXIS_LABEL_ABS_MT_TRACKING_ID "Abs MT Tracking ID" #define AXIS_LABEL_ABS_MT_TRACKING_ID "Abs MT Tracking ID"
#define AXIS_LABEL_TOUCH_TIMESTAMP "Touch Timestamp" #define AXIS_LABEL_TOUCH_TIMESTAMP "Touch Timestamp"
...@@ -87,6 +89,8 @@ const char* kCachedAtoms[] = { ...@@ -87,6 +89,8 @@ const char* kCachedAtoms[] = {
AXIS_LABEL_ABS_MT_TOUCH_MINOR, AXIS_LABEL_ABS_MT_TOUCH_MINOR,
AXIS_LABEL_ABS_MT_ORIENTATION, AXIS_LABEL_ABS_MT_ORIENTATION,
AXIS_LABEL_ABS_MT_PRESSURE, AXIS_LABEL_ABS_MT_PRESSURE,
AXIS_LABEL_ABS_MT_POSITION_X,
AXIS_LABEL_ABS_MT_POSITION_Y,
AXIS_LABEL_ABS_MT_TRACKING_ID, AXIS_LABEL_ABS_MT_TRACKING_ID,
AXIS_LABEL_TOUCH_TIMESTAMP, AXIS_LABEL_TOUCH_TIMESTAMP,
......
...@@ -83,6 +83,9 @@ class EVENTS_BASE_EXPORT DeviceDataManagerX11 : public DeviceDataManager { ...@@ -83,6 +83,9 @@ class EVENTS_BASE_EXPORT DeviceDataManagerX11 : public DeviceDataManager {
// touch area. // touch area.
DT_TOUCH_PRESSURE, // Pressure of the touch contact. 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 // 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 // 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 // is increased for each new touch. It will wrap back to 0 when reaching
......
...@@ -286,6 +286,13 @@ double GetTouchParamFromXEvent(XEvent* xev, ...@@ -286,6 +286,13 @@ double GetTouchParamFromXEvent(XEvent* xev,
return default_value; return default_value;
} }
void ScaleTouchRadius(XEvent* xev, double* radius) {
DCHECK_EQ(GenericEvent, xev->type);
XIDeviceEvent* xiev = static_cast<XIDeviceEvent*>(xev->xcookie.data);
ui::DeviceDataManagerX11::GetInstance()->ApplyTouchRadiusScale(
xiev->sourceid, radius);
}
} // namespace } // namespace
namespace ui { namespace ui {
...@@ -704,13 +711,17 @@ int GetTouchId(const base::NativeEvent& xev) { ...@@ -704,13 +711,17 @@ int GetTouchId(const base::NativeEvent& xev) {
} }
float GetTouchRadiusX(const base::NativeEvent& native_event) { float GetTouchRadiusX(const base::NativeEvent& native_event) {
return GetTouchParamFromXEvent(native_event, double radius = GetTouchParamFromXEvent(native_event,
ui::DeviceDataManagerX11::DT_TOUCH_MAJOR, 0.0) / 2.0; ui::DeviceDataManagerX11::DT_TOUCH_MAJOR, 0.0) / 2.0;
ScaleTouchRadius(native_event, &radius);
return radius;
} }
float GetTouchRadiusY(const base::NativeEvent& native_event) { float GetTouchRadiusY(const base::NativeEvent& native_event) {
return GetTouchParamFromXEvent(native_event, double radius = GetTouchParamFromXEvent(native_event,
ui::DeviceDataManagerX11::DT_TOUCH_MINOR, 0.0) / 2.0; ui::DeviceDataManagerX11::DT_TOUCH_MINOR, 0.0) / 2.0;
ScaleTouchRadius(native_event, &radius);
return radius;
} }
float GetTouchAngle(const base::NativeEvent& native_event) { float GetTouchAngle(const base::NativeEvent& native_event) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment