Chromium Code Reviews| Index: ui/events/x/device_data_manager.cc |
| diff --git a/ui/events/x/device_data_manager.cc b/ui/events/x/device_data_manager.cc |
| index cac9dfda0bdbb6f93a7adf451f54070c25041984..19e66fe78df5c3c17e4994de8ea23be8be5f5613 100644 |
| --- a/ui/events/x/device_data_manager.cc |
| +++ b/ui/events/x/device_data_manager.cc |
| @@ -8,11 +8,19 @@ |
| #include <X11/extensions/XInput2.h> |
| #include <X11/Xlib.h> |
| +#include "base/command_line.h" |
| #include "base/logging.h" |
| #include "base/memory/singleton.h" |
| +#include "base/strings/string_number_conversions.h" |
| +#include "base/strings/string_util.h" |
| +#include "base/sys_info.h" |
| #include "ui/events/event_constants.h" |
| +#include "ui/events/event_switches.h" |
| +#include "ui/events/platform/platform_event_observer.h" |
| +#include "ui/events/platform/x11/x11_event_source.h" |
| #include "ui/events/x/device_list_cache_x.h" |
| #include "ui/events/x/touch_factory_x11.h" |
| +#include "ui/gfx/display.h" |
| #include "ui/gfx/x/x11_types.h" |
| // XIScrollClass was introduced in XI 2.1 so we need to define it here |
| @@ -97,6 +105,137 @@ const int kTouchDataTypeEnd = ui::DeviceDataManager::DT_TOUCH_RAW_TIMESTAMP; |
| namespace ui { |
| +// Accomplishes 2 tasks concerning touch event calibration: |
| +// 1. Being a message-pump observer, |
| +// routes all the touch events to the X root window, |
| +// where they can be calibrated later. |
|
sadrul
2014/05/07 20:00:27
Is this step still necessary?
Yufeng Shen (Slow to review)
2014/05/07 22:02:58
I saw you filed another bug on this. Let's address
spang
2014/05/20 16:38:16
What bug?
Please CC if you try to move this code.
Yufeng Shen (Slow to review)
2014/05/20 16:53:42
crbug.com/371060 I think.
I am not worrying about
|
| +// 2. Has the Calibrate method that does the actual bezel calibration, |
| +// when invoked from X root window's event dispatcher. |
| +class DeviceDataManager::TouchEventCalibrate |
| + : public ui::PlatformEventObserver { |
| + public: |
| + TouchEventCalibrate() : left_(0), right_(0), top_(0), bottom_(0) { |
| + if (ui::PlatformEventSource::GetInstance()) |
| + ui::PlatformEventSource::GetInstance()->AddPlatformEventObserver(this); |
| +#if defined(USE_XI2_MT) |
| + std::vector<std::string> parts; |
| + if (Tokenize(CommandLine::ForCurrentProcess()->GetSwitchValueASCII( |
| + switches::kTouchCalibration), |
| + ",", |
| + &parts) >= 4) { |
| + if (!base::StringToInt(parts[0], &left_)) |
| + DLOG(ERROR) << "Incorrect left border calibration value passed."; |
| + if (!base::StringToInt(parts[1], &right_)) |
| + DLOG(ERROR) << "Incorrect right border calibration value passed."; |
| + if (!base::StringToInt(parts[2], &top_)) |
| + DLOG(ERROR) << "Incorrect top border calibration value passed."; |
| + if (!base::StringToInt(parts[3], &bottom_)) |
| + DLOG(ERROR) << "Incorrect bottom border calibration value passed."; |
| + } |
| +#endif // defined(USE_XI2_MT) |
| + } |
| + |
| + virtual ~TouchEventCalibrate() { |
| + if (ui::PlatformEventSource::GetInstance()) |
| + ui::PlatformEventSource::GetInstance()->RemovePlatformEventObserver(this); |
| + } |
| + |
| + // Modify the location of the |event|, |
| + // expanding it from |bounds| to (|bounds| + bezels). |
| + // Required when touchscreen is bigger than screen (i.e. has bezels), |
| + // because we receive events in touchscreen coordinates, |
| + // which need to be expanded when converting to screen coordinates, |
| + // so that location on bezels will be outside of screen area. |
| + void Calibrate(ui::TouchEvent* event, const gfx::Rect& bounds) { |
| +#if defined(USE_XI2_MT) |
| + int x = event->x(); |
| + int y = event->y(); |
| + |
| + if (!left_ && !right_ && !top_ && !bottom_) |
| + return; |
| + |
| + const int resolution_x = bounds.width(); |
| + const int resolution_y = bounds.height(); |
| + // The "grace area" (10% in this case) is to make it easier for the user to |
| + // navigate to the corner. |
| + const double kGraceAreaFraction = 0.1; |
| + if (left_ || right_) { |
| + // Offset the x position to the real |
| + x -= left_; |
| + // Check if we are in the grace area of the left side. |
| + // Note: We might not want to do this when the gesture is locked? |
| + if (x < 0 && x > -left_ * kGraceAreaFraction) |
| + x = 0; |
| + // Check if we are in the grace area of the right side. |
| + // Note: We might not want to do this when the gesture is locked? |
| + if (x > resolution_x - left_ && |
| + x < resolution_x - left_ + right_ * kGraceAreaFraction) |
| + x = resolution_x - left_; |
| + // Scale the screen area back to the full resolution of the screen. |
| + x = (x * resolution_x) / (resolution_x - (right_ + left_)); |
| + } |
| + if (top_ || bottom_) { |
| + // When there is a top bezel we add our border, |
| + y -= top_; |
| + |
| + // Check if we are in the grace area of the top side. |
| + // Note: We might not want to do this when the gesture is locked? |
| + if (y < 0 && y > -top_ * kGraceAreaFraction) |
| + y = 0; |
| + |
| + // Check if we are in the grace area of the bottom side. |
| + // Note: We might not want to do this when the gesture is locked? |
| + if (y > resolution_y - top_ && |
| + y < resolution_y - top_ + bottom_ * kGraceAreaFraction) |
| + y = resolution_y - top_; |
| + // Scale the screen area back to the full resolution of the screen. |
| + y = (y * resolution_y) / (resolution_y - (bottom_ + top_)); |
| + } |
| + |
| + // Set the modified coordinate back to the event. |
| + if (event->root_location() == event->location()) { |
| + // Usually those will be equal, |
| + // if not, I am not sure what the correct value should be. |
| + event->set_root_location(gfx::Point(x, y)); |
| + } |
| + event->set_location(gfx::Point(x, y)); |
| +#endif // defined(USE_XI2_MT) |
| + } |
| + |
| + private: |
| + // ui::PlatformEventObserver: |
| + virtual void WillProcessEvent(const ui::PlatformEvent& event) OVERRIDE { |
| +#if defined(USE_XI2_MT) |
| + if (event->type == GenericEvent && |
| + (event->xgeneric.evtype == XI_TouchBegin || |
| + event->xgeneric.evtype == XI_TouchUpdate || |
| + event->xgeneric.evtype == XI_TouchEnd)) { |
| + XIDeviceEvent* xievent = static_cast<XIDeviceEvent*>(event->xcookie.data); |
| + LOG(ERROR) << "Raw " << xievent->event_x << " " << xievent->event_y |
| + << " " << xievent->root_x << " " << xievent->root_y; |
| + xievent->event = xievent->root; |
| + xievent->event_x = xievent->root_x; |
| + xievent->event_y = xievent->root_y; |
| + } |
| +#endif // defined(USE_XI2_MT) |
| + } |
| + |
| + virtual void DidProcessEvent(const ui::PlatformEvent& event) OVERRIDE {} |
| + |
| + // The difference in screen's native resolution pixels between |
| + // the border of the touchscreen and the border of the screen, |
| + // aka bezel sizes. |
| + int left_; |
| + int right_; |
| + int top_; |
| + int bottom_; |
| + |
| + DISALLOW_COPY_AND_ASSIGN(TouchEventCalibrate); |
| +}; |
| + |
| +//////////////////////////////////////////////////////////////////////////////// |
| +// DeviceDataManager |
| + |
| bool DeviceDataManager::IsCMTDataType(const int type) { |
| return (type >= kCMTDataTypeStart) && (type <= kCMTDataTypeEnd); |
| } |
| @@ -112,7 +251,8 @@ DeviceDataManager* DeviceDataManager::GetInstance() { |
| DeviceDataManager::DeviceDataManager() |
| : xi_opcode_(-1), |
| atom_cache_(gfx::GetXDisplay(), kCachedAtoms), |
| - button_map_count_(0) { |
| + button_map_count_(0), |
| + touch_calibrate_(new TouchEventCalibrate) { |
| CHECK(gfx::GetXDisplay()); |
| InitializeXInputInternal(); |
| @@ -120,6 +260,8 @@ DeviceDataManager::DeviceDataManager() |
| CHECK(arraysize(kCachedAtoms) == static_cast<size_t>(DT_LAST_ENTRY) + 1); |
| UpdateDeviceList(gfx::GetXDisplay()); |
| UpdateButtonMap(); |
| + for (int i = 0; i < kMaxDeviceNum; i++) |
| + touch_device_to_display_map_[i] = gfx::Display::kInvalidDisplayID; |
| } |
| DeviceDataManager::~DeviceDataManager() { |
| @@ -634,4 +776,48 @@ void DeviceDataManager::InitializeValuatorsForTest(int deviceid, |
| } |
| } |
| +void DeviceDataManager::CalibrateTouchEvent(TouchEvent* event, |
| + int touch_device_id, |
| + const gfx::Rect& bounds) { |
| +#if defined(OS_CHROMEOS) && defined(USE_XI2_MT) |
| + int64 touch_display_id = GetDisplayForTouchDevice(touch_device_id); |
| + if (base::SysInfo::IsRunningOnChromeOS() && |
| + touch_display_id == gfx::Display::InternalDisplayId()) { |
| + touch_calibrate_->Calibrate(event, bounds); |
| + } |
| +#endif // defined(OS_CHROMEOS) && defined(USE_XI2_MT) |
| +} |
| + |
| +void DeviceDataManager::ClearTouchTransformerRecord() { |
| + for (int i = 0; i < kMaxDeviceNum; i++) { |
| + touch_device_transformer_map_[i] = TouchTransformer(); |
| + touch_device_to_display_map_[i] = gfx::Display::kInvalidDisplayID; |
| + } |
| +} |
| + |
| +void DeviceDataManager::UpdateTouchInfoForDisplay( |
| + int64 display_id, |
| + int touch_device_id, |
| + const TouchTransformer& touch_transformer) { |
| + if (touch_device_id > 0 && touch_device_id < kMaxDeviceNum) { |
|
sadrul
2014/05/07 20:00:27
Have a separate IsTouchDevideIdValid() and use tha
Yufeng Shen (Slow to review)
2014/05/07 22:02:58
Done.
|
| + touch_device_to_display_map_[touch_device_id] = display_id; |
| + touch_device_transformer_map_[touch_device_id] = touch_transformer; |
| + } |
| +} |
| + |
| +void DeviceDataManager::ApplyTouchTransformer(int touch_device_id, |
| + float* x, float* y) { |
| + if (touch_device_id > 0 && touch_device_id < kMaxDeviceNum) { |
| + TouchTransformer trans = touch_device_transformer_map_[touch_device_id]; |
| + *x = *x * trans.x_scale + trans.x_offset; |
| + *y = *y * trans.y_scale + trans.y_offset; |
| + } |
| +} |
| + |
| +int64 DeviceDataManager::GetDisplayForTouchDevice(int touch_device_id) const { |
| + if (touch_device_id > 0 && touch_device_id < kMaxDeviceNum) |
| + return touch_device_to_display_map_[touch_device_id]; |
| + return gfx::Display::kInvalidDisplayID; |
| +} |
| + |
| } // namespace ui |