touchui: Create touch-events.
Create and process touch-events. The touch-events are created from
pointer-events. The way to decide whether a 'pointer event' originated from a
touch-device is not yet well-defined. So for now, use the --touch-devices
command line parameter to specify which pointer devices should be treated as
touch-device. For example, you can run:
./out/Debug/chrome --touch-devices=7,8
to treat the events coming in from devices with id 7 and 8 as touch events.
(these are the slave ids you get from 'xinput list')
BUG=None
TEST=None
Review URL: http://codereview.chromium.org/4738001
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@67133 0039d316-1c4b-4281-b951-d872f2087c98
diff --git a/chrome/browser/renderer_host/render_widget_host.cc b/chrome/browser/renderer_host/render_widget_host.cc
index cd1a472..7f84227 100644
--- a/chrome/browser/renderer_host/render_widget_host.cc
+++ b/chrome/browser/renderer_host/render_widget_host.cc
@@ -628,6 +628,13 @@
// only handled by RenderView.
}
+#if defined(TOUCH_UI)
+void RenderWidgetHost::ForwardTouchEvent(
+ const WebKit::WebTouchEvent& touch_event) {
+ ForwardInputEvent(touch_event, sizeof(WebKit::WebTouchEvent), false);
+}
+#endif
+
void RenderWidgetHost::RendererExited() {
// Clearing this flag causes us to re-create the renderer when recovering
// from a crashed renderer.
diff --git a/chrome/browser/renderer_host/render_widget_host.h b/chrome/browser/renderer_host/render_widget_host.h
index 8514ce0..9f2225b6 100644
--- a/chrome/browser/renderer_host/render_widget_host.h
+++ b/chrome/browser/renderer_host/render_widget_host.h
@@ -279,6 +279,10 @@
const std::string& value);
virtual void ForwardEditCommandsForNextKeyEvent(
const EditCommands& edit_commands);
+#if defined(TOUCH_UI)
+ virtual void ForwardTouchEvent(const WebKit::WebTouchEvent& touch_event);
+#endif
+
// Update the text direction of the focused input element and notify it to a
// renderer process.
diff --git a/chrome/browser/renderer_host/render_widget_host_view_views.cc b/chrome/browser/renderer_host/render_widget_host_view_views.cc
index 591e3985..a9bc958 100644
--- a/chrome/browser/renderer_host/render_widget_host_view_views.cc
+++ b/chrome/browser/renderer_host/render_widget_host_view_views.cc
@@ -33,6 +33,7 @@
using WebKit::WebInputEventFactory;
using WebKit::WebMouseWheelEvent;
+using WebKit::WebTouchEvent;
namespace {
@@ -51,6 +52,48 @@
return modifiers;
}
+WebKit::WebTouchPoint::State TouchPointStateFromEvent(
+ const views::TouchEvent* event) {
+ switch (event->GetType()) {
+ case views::Event::ET_TOUCH_PRESSED:
+ return WebKit::WebTouchPoint::StatePressed;
+ case views::Event::ET_TOUCH_RELEASED:
+ return WebKit::WebTouchPoint::StateReleased;
+ case views::Event::ET_TOUCH_MOVED:
+ return WebKit::WebTouchPoint::StateMoved;
+ case views::Event::ET_TOUCH_CANCELLED:
+ return WebKit::WebTouchPoint::StateCancelled;
+ default:
+ return WebKit::WebTouchPoint::StateUndefined;
+ }
+}
+
+WebKit::WebInputEvent::Type TouchEventTypeFromEvent(
+ const views::TouchEvent* event) {
+ switch (event->GetType()) {
+ case views::Event::ET_TOUCH_PRESSED:
+ return WebKit::WebInputEvent::TouchStart;
+ case views::Event::ET_TOUCH_RELEASED:
+ return WebKit::WebInputEvent::TouchEnd;
+ case views::Event::ET_TOUCH_MOVED:
+ return WebKit::WebInputEvent::TouchMove;
+ case views::Event::ET_TOUCH_CANCELLED:
+ return WebKit::WebInputEvent::TouchCancel;
+ default:
+ return WebKit::WebInputEvent::Undefined;
+ }
+}
+
+void UpdateTouchPointPosition(const views::TouchEvent* event,
+ const gfx::Point& origin,
+ WebKit::WebTouchPoint* tpoint) {
+ tpoint->position.x = event->x();
+ tpoint->position.y = event->y();
+
+ tpoint->screenPosition.x = tpoint->position.x + origin.x();
+ tpoint->screenPosition.y = tpoint->position.y + origin.y();
+}
+
void InitializeWebMouseEventFromViewsEvent(const views::LocatedEvent& e,
const gfx::Point& origin,
WebKit::WebMouseEvent* wmevent) {
@@ -78,7 +121,9 @@
is_loading_(false),
native_cursor_(NULL),
is_showing_context_menu_(false),
- visually_deemphasized_(false) {
+ visually_deemphasized_(false),
+ touch_event_()
+ {
SetFocusable(true);
host_->set_view(this);
}
@@ -581,6 +626,75 @@
host_->ForwardKeyboardEvent(event);
}
+bool RenderWidgetHostViewViews::OnTouchEvent(const views::TouchEvent& e) {
+ // Update the list of touch points first.
+ WebKit::WebTouchPoint* point = NULL;
+
+ switch (e.GetType()) {
+ case views::Event::ET_TOUCH_PRESSED:
+ // Add a new touch point.
+ if (touch_event_.touchPointsLength <
+ WebTouchEvent::touchPointsLengthCap) {
+ point = &touch_event_.touchPoints[touch_event_.touchPointsLength++];
+ point->id = e.identity();
+ }
+ break;
+ case views::Event::ET_TOUCH_RELEASED:
+ case views::Event::ET_TOUCH_CANCELLED:
+ case views::Event::ET_TOUCH_MOVED: {
+ // The touch point should have been added to the event from an earlier
+ // _PRESSED event. So find that.
+ // At the moment, only a maximum of 4 touch-points are allowed. So a
+ // simple loop should be sufficient.
+ for (int i = 0; i < WebTouchEvent::touchPointsLengthCap; ++i) {
+ point = touch_event_.touchPoints + i;
+ if (point->id == e.identity()) {
+ break;
+ }
+ point = NULL;
+ }
+ DCHECK(point != NULL) << "Touchpoint not found for event " << e.GetType();
+ break;
+ }
+ default:
+ DLOG(WARNING) << "Unknown touch event " << e.GetType();
+ break;
+ }
+
+ if (!point)
+ return false;
+
+ // Update the location and state of the point.
+ UpdateTouchPointPosition(&e, GetPosition(), point);
+ point->state = TouchPointStateFromEvent(&e);
+
+ // Mark the rest of the points as stationary.
+ for (int i = 0; i < touch_event_.touchPointsLength; ++i) {
+ WebKit::WebTouchPoint* iter = touch_event_.touchPoints + i;
+ if (iter != point) {
+ iter->state = WebKit::WebTouchPoint::StateStationary;
+ }
+ }
+
+ // Update the type of the touch event.
+ touch_event_.type = TouchEventTypeFromEvent(&e);
+
+ // The event and all the touches have been updated. Dispatch.
+ host_->ForwardTouchEvent(touch_event_);
+
+ // If the touch was released, then remove it from the list of touch points.
+ if (e.GetType() == views::Event::ET_TOUCH_RELEASED) {
+ --touch_event_.touchPointsLength;
+ for (int i = point - touch_event_.touchPoints;
+ i < touch_event_.touchPointsLength;
+ ++i) {
+ touch_event_.touchPoints[i] = touch_event_.touchPoints[i + 1];
+ }
+ }
+
+ return true;
+}
+
// static
RenderWidgetHostView*
RenderWidgetHostView::GetRenderWidgetHostViewFromNativeView(
diff --git a/chrome/browser/renderer_host/render_widget_host_view_views.h b/chrome/browser/renderer_host/render_widget_host_view_views.h
index 88a4746d..0689fbe 100644
--- a/chrome/browser/renderer_host/render_widget_host_view_views.h
+++ b/chrome/browser/renderer_host/render_widget_host_view_views.h
@@ -14,6 +14,7 @@
#include "base/time.h"
#include "chrome/browser/renderer_host/render_widget_host_view.h"
#include "gfx/native_widget_types.h"
+#include "third_party/WebKit/WebKit/chromium/public/WebInputEvent.h"
#include "views/controls/native/native_view_host.h"
#include "views/event.h"
#include "views/view.h"
@@ -22,10 +23,6 @@
class RenderWidgetHost;
struct NativeWebKeyboardEvent;
-namespace WebKit {
-class WebMouseEvent;
-}
-
// -----------------------------------------------------------------------------
// See comments in render_widget_host_view.h about this class and its members.
// -----------------------------------------------------------------------------
@@ -85,7 +82,7 @@
gfx::NativeCursor GetCursorForPoint(views::Event::EventType type,
const gfx::Point& point);
- // Views mouse events
+ // Views mouse events, overridden from views::View.
virtual bool OnMousePressed(const views::MouseEvent& event);
virtual bool OnMouseDragged(const views::MouseEvent& event);
virtual void OnMouseReleased(const views::MouseEvent& event, bool canceled);
@@ -94,7 +91,7 @@
virtual void OnMouseExited(const views::MouseEvent& event);
virtual bool OnMouseWheel(const views::MouseWheelEvent& e);
- // Views keyboard events
+ // Views keyboard events, overridden from views::View.
virtual bool OnKeyPressed(const views::KeyEvent &e);
virtual bool OnKeyReleased(const views::KeyEvent &e);
@@ -104,6 +101,9 @@
// Forwards a keyboard event to renderer.
void ForwardKeyboardEvent(const NativeWebKeyboardEvent& event);
+ // Views touch events, overridden from views::View.
+ virtual bool OnTouchEvent(const views::TouchEvent& e);
+
private:
friend class RenderWidgetHostViewViewsWidget;
@@ -162,6 +162,11 @@
// The size that we want the renderer to be.
gfx::Size requested_size_;
+ // The touch-event. Its touch-points are updated as necessary. A new
+ // touch-point is added from an ET_TOUCH_PRESSED event, and a touch-point is
+ // removed from the list on an ET_TOUCH_RELEASED event.
+ WebKit::WebTouchEvent touch_event_;
+
DISALLOW_COPY_AND_ASSIGN(RenderWidgetHostViewViews);
};
diff --git a/chrome/browser/ui/browser_init.cc b/chrome/browser/ui/browser_init.cc
index 9d1e89c..ac4932da 100644
--- a/chrome/browser/ui/browser_init.cc
+++ b/chrome/browser/ui/browser_init.cc
@@ -15,6 +15,7 @@
#include "base/path_service.h"
#include "base/scoped_ptr.h"
#include "base/string_number_conversions.h"
+#include "base/string_split.h"
#include "base/thread_restrictions.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/automation/automation_provider.h"
@@ -96,6 +97,10 @@
#include "chrome/browser/dom_ui/mediaplayer_ui.h"
#endif
+#if defined(HAVE_XINPUT2)
+#include "views/focus/accelerator_handler.h"
+#endif
+
namespace {
class SetAsDefaultBrowserTask : public Task {
@@ -1017,6 +1022,30 @@
}
#endif
+#if defined(HAVE_XINPUT2)
+ // Get a list of pointer-devices that should be treated as touch-devices.
+ // TODO(sad): Instead of/in addition to getting the list from the
+ // command-line, query X for a list of touch devices.
+ std::string touch_devices =
+ command_line.GetSwitchValueASCII(switches::kTouchDevices);
+
+ if (!touch_devices.empty()) {
+ std::vector<std::string> devs;
+ std::vector<unsigned int> device_ids;
+ unsigned int devid;
+ base::SplitString(touch_devices, ',', &devs);
+ for (std::vector<std::string>::iterator iter = devs.begin();
+ iter != devs.end(); ++iter) {
+ if (base::StringToInt(*iter, reinterpret_cast<int*>(&devid))) {
+ device_ids.push_back(devid);
+ } else {
+ DLOG(WARNING) << "Invalid touch-device id: " << *iter;
+ }
+ }
+ views::SetTouchDeviceList(device_ids);
+ }
+#endif
+
// If we don't want to launch a new browser window or tab (in the case
// of an automation request), we are done here.
if (!silent_launch) {
diff --git a/chrome/chrome_browser.gypi b/chrome/chrome_browser.gypi
index 62185c6..41123a0 100644
--- a/chrome/chrome_browser.gypi
+++ b/chrome/chrome_browser.gypi
@@ -3472,6 +3472,7 @@
'../build/linux/system.gyp:gtk',
'../build/linux/system.gyp:gtkprint',
'../build/linux/system.gyp:nss',
+ '../build/linux/system.gyp:x11',
'../third_party/undoview/undoview.gyp:undoview',
],
'link_settings': {
@@ -3545,6 +3546,7 @@
'../build/linux/system.gyp:gtk',
'../build/linux/system.gyp:gtkprint',
'../build/linux/system.gyp:nss',
+ '../build/linux/system.gyp:x11',
],
'sources': [
'browser/file_path_watcher_stub.cc',
diff --git a/chrome/common/chrome_switches.cc b/chrome/common/chrome_switches.cc
index 34dbc285..8e99e8e 100644
--- a/chrome/common/chrome_switches.cc
+++ b/chrome/common/chrome_switches.cc
@@ -1313,6 +1313,11 @@
const char kWebSocketLiveExperimentHost[] = "websocket-live-experiment-host";
#endif
+#if defined(HAVE_XINPUT2)
+const char kTouchDevices[] = "touch-devices";
+#endif
+
+
// USE_SECCOMP_SANDBOX controls whether the seccomp sandbox is opt-in or -out.
// TODO(evan): unify all of these once we turn the seccomp sandbox always
// on. Also remove the #include of command_line.h above.
diff --git a/chrome/common/chrome_switches.h b/chrome/common/chrome_switches.h
index 422cb40..1154171 100644
--- a/chrome/common/chrome_switches.h
+++ b/chrome/common/chrome_switches.h
@@ -390,6 +390,10 @@
extern const char kRendererCheckFalseTest[];
#endif
+#if defined(HAVE_XINPUT2)
+extern const char kTouchDevices[];
+#endif
+
#if defined(USE_SECCOMP_SANDBOX)
extern const char kDisableSeccompSandbox[];
#else