From d01290dd34c0274f49adcd75b7488c90fe70f562 Mon Sep 17 00:00:00 2001 From: Valentin Shergin Date: Fri, 8 Jun 2018 20:16:17 -0700 Subject: [PATCH] Fabric: Data model of Touch Events Summary: The data model of Touch events and payload serialization. The implementation mimics W3C standard and current React Native implementation. Reviewed By: fkgozali Differential Revision: D8246711 fbshipit-source-id: 955b2068674f290d8bdb82da1ebfb796dd32971b --- ReactCommon/fabric/view/ViewEventHandlers.cpp | 49 ++++++++++ ReactCommon/fabric/view/ViewEventHandlers.h | 90 +++++++++++++++++++ 2 files changed, 139 insertions(+) diff --git a/ReactCommon/fabric/view/ViewEventHandlers.cpp b/ReactCommon/fabric/view/ViewEventHandlers.cpp index e673d077ef..3cdadd3527 100644 --- a/ReactCommon/fabric/view/ViewEventHandlers.cpp +++ b/ReactCommon/fabric/view/ViewEventHandlers.cpp @@ -38,5 +38,54 @@ void ViewEventHandlers::onLayout(const LayoutMetrics &layoutMetrics) const { dispatchEvent("layout", payload); } +#pragma mark - Touches + +static folly::dynamic touchPayload(const Touch &touch) { + folly::dynamic object = folly::dynamic::object(); + object["locationX"] = touch.offsetPoint.x; + object["locationY"] = touch.offsetPoint.x; + object["pageX"] = touch.pagePoint.x; + object["pageY"] = touch.pagePoint.x; + object["screenX"] = touch.screenPoint.x; + object["screenY"] = touch.screenPoint.x; + object["identifier"] = touch.identifier; + object["target"] = touch.target; + object["timestamp"] = touch.timestamp * 1000; + object["force"] = touch.force; + return object; +} + +static folly::dynamic touchesPayload(const Touches &touches) { + folly::dynamic array = folly::dynamic::array(); + for (auto &&touch : touches) { + array.push_back(touchPayload(touch)); + } + return array; +} + +static folly::dynamic touchEventPayload(const TouchEvent &event) { + folly::dynamic object = folly::dynamic::object(); + object["touches"] = touchesPayload(event.touches); + object["changedTouches"] = touchesPayload(event.changedTouches); + object["targetTouches"] = touchesPayload(event.targetTouches); + return object; +} + +void ViewEventHandlers::onTouchStart(const TouchEvent &event) const { + dispatchEvent("touchStart", touchEventPayload(event)); +} + +void ViewEventHandlers::onTouchMove(const TouchEvent &event) const { + dispatchEvent("touchMove", touchEventPayload(event)); +} + +void ViewEventHandlers::onTouchEnd(const TouchEvent &event) const { + dispatchEvent("touchEnd", touchEventPayload(event)); +} + +void ViewEventHandlers::onTouchCancel(const TouchEvent &event) const { + dispatchEvent("touchCancel", touchEventPayload(event)); +} + } // namespace react } // namespace facebook diff --git a/ReactCommon/fabric/view/ViewEventHandlers.h b/ReactCommon/fabric/view/ViewEventHandlers.h index e72e41f345..654649ed38 100644 --- a/ReactCommon/fabric/view/ViewEventHandlers.h +++ b/ReactCommon/fabric/view/ViewEventHandlers.h @@ -10,10 +10,93 @@ #include #include +#include namespace facebook { namespace react { +/* + * Describes an individual touch point for a touch event. + * See https://www.w3.org/TR/touch-events/ for more details. + */ +struct Touch { + /* + * The coordinate of point relative to the root component in points. + */ + Point pagePoint; + + /* + * The coordinate of point relative to the target component in points. + */ + Point offsetPoint; + + /* + * The coordinate of point relative to the screen component in points. + */ + Point screenPoint; + + /* + * An identification number for each touch point. + */ + int identifier; + + /* + * The tag of a component on which the touch point started when it was first placed on the surface, + * even if the touch point has since moved outside the interactive area of that element. + */ + Tag target; + + /* + * The force of the touch. + */ + Float force; + + /* + * The time in seconds when the touch occurred or when it was last mutated. + */ + Float timestamp; + + /* + * The particular implementation of `Hasher` and (especially) `Comparator` + * make sense only when `Touch` object is used as a *key* in indexed collections. + * Because of that they are expressed as separate classes. + */ + struct Hasher { + size_t operator()(const Touch &touch) const { + return std::hash()(touch.identifier); + } + }; + + struct Comparator { + bool operator()(const Touch &lhs, const Touch &rhs) const { + return lhs.identifier == rhs.identifier; + } + }; +}; + +using Touches = std::unordered_set; + +/* + * Defines the `touchstart`, `touchend`, `touchmove`, and `touchcancel` event types. + */ +struct TouchEvent { + /* + * A list of Touches for every point of contact currently touching the surface. + */ + Touches touches; + + /* + * A list of Touches for every point of contact which contributed to the event. + */ + Touches changedTouches; + + /* + * A list of Touches for every point of contact that is touching the surface + * and started on the element that is the target of the current event. + */ + Touches targetTouches; +}; + class ViewEventHandlers; using SharedViewEventHandlers = std::shared_ptr; @@ -34,6 +117,13 @@ public: #pragma mark - Layout void onLayout(const LayoutMetrics &layoutMetrics) const; + +#pragma mark - Touches + + void onTouchStart(const TouchEvent &event) const; + void onTouchMove(const TouchEvent &event) const; + void onTouchEnd(const TouchEvent &event) const; + void onTouchCancel(const TouchEvent &event) const; }; } // namespace react