| // Copyright 2018 The Fuchsia Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #ifndef SRC_UI_SCENIC_LIB_INPUT_INPUT_SYSTEM_H_ |
| #define SRC_UI_SCENIC_LIB_INPUT_INPUT_SYSTEM_H_ |
| |
| #include <fuchsia/ui/input/accessibility/cpp/fidl.h> |
| #include <fuchsia/ui/input/cpp/fidl.h> |
| #include <fuchsia/ui/scenic/cpp/fidl.h> |
| |
| #include <map> |
| #include <optional> |
| |
| #include "src/ui/scenic/lib/input/a11y_legacy_contender.h" |
| #include "src/ui/scenic/lib/input/a11y_registry.h" |
| #include "src/ui/scenic/lib/input/gesture_arena.h" |
| #include "src/ui/scenic/lib/input/gfx_legacy_contender.h" |
| #include "src/ui/scenic/lib/input/injector.h" |
| #include "src/ui/scenic/lib/input/input_command_dispatcher.h" |
| #include "src/ui/scenic/lib/input/pointerinjector_registry.h" |
| #include "src/ui/scenic/lib/scenic/system.h" |
| #include "src/ui/scenic/lib/scheduling/id.h" |
| #include "src/ui/scenic/lib/view_tree/snapshot_types.h" |
| |
| namespace scenic_impl::input { |
| |
| // RequestFocusFunc should attempt to move focus to the passed in zx_koid_t. |
| // If the passed in koid is ZX_KOID_INVALID, then focus should be moved to |
| // the current root of the focus chain. If there is no root, then the call should |
| // silently fail. |
| using RequestFocusFunc = fit::function<void(zx_koid_t)>; |
| |
| // Tracks input APIs. |
| class InputSystem : public System, public fuchsia::ui::input::PointerCaptureListenerRegistry { |
| public: |
| struct PointerCaptureListener { |
| fuchsia::ui::input::PointerCaptureListenerPtr listener_ptr; |
| fuchsia::ui::views::ViewRef view_ref; |
| }; |
| |
| static constexpr TypeId kTypeId = kInput; |
| static const char* kName; |
| |
| explicit InputSystem(SystemContext context, fxl::WeakPtr<gfx::SceneGraph> scene_graph, |
| RequestFocusFunc request_focus); |
| ~InputSystem() override = default; |
| |
| CommandDispatcherUniquePtr CreateCommandDispatcher( |
| scheduling::SessionId session_id, std::shared_ptr<EventReporter> event_reporter, |
| std::shared_ptr<ErrorReporter> error_reporter) override; |
| |
| fuchsia::ui::input::accessibility::PointerEventListenerPtr& accessibility_pointer_event_listener() |
| const { |
| return a11y_pointer_event_registry_->accessibility_pointer_event_listener(); |
| } |
| |
| void OnNewViewTreeSnapshot(std::shared_ptr<const view_tree::Snapshot> snapshot) { |
| pointerinjector_registry_->OnNewViewTreeSnapshot(snapshot); |
| view_tree_snapshot_ = std::move(snapshot); |
| } |
| |
| // |fuchsia.ui.pointercapture.ListenerRegistry| |
| void RegisterListener( |
| fidl::InterfaceHandle<fuchsia::ui::input::PointerCaptureListener> listener_handle, |
| fuchsia::ui::views::ViewRef view_ref, RegisterListenerCallback success_callback) override; |
| |
| void DispatchPointerCommand(const fuchsia::ui::input::SendPointerInputCmd& command, |
| scheduling::SessionId session_id); |
| |
| // For tests. |
| // TODO(fxbug.dev/72919): Remove when integration tests are properly separated out. |
| void RegisterA11yListener( |
| fidl::InterfaceHandle<fuchsia::ui::input::accessibility::PointerEventListener> listener, |
| A11yPointerEventRegistry::RegisterCallback callback) { |
| a11y_pointer_event_registry_->Register(std::move(listener), std::move(callback)); |
| } |
| // For tests. |
| // TODO(fxbug.dev/72919): Remove when integration tests are properly separated out. |
| void RegisterPointerinjector( |
| fuchsia::ui::pointerinjector::Config config, |
| fidl::InterfaceRequest<fuchsia::ui::pointerinjector::Device> injector, |
| fuchsia::ui::pointerinjector::Registry::RegisterCallback callback) { |
| pointerinjector_registry_->Register(std::move(config), std::move(injector), |
| std::move(callback)); |
| } |
| |
| private: |
| // Perform a hit test with |event| in |view_tree| and returns the koids of all hit views, in order |
| // from closest to furthest. |
| std::vector<zx_koid_t> HitTest(const InternalPointerEvent& event, bool semantic_hit_test) const; |
| |
| // Injects a touch event directly to the View with koid |target|. |
| void InjectTouchEventExclusive(const InternalPointerEvent& event); |
| |
| // Injects a touch event by hit testing for appropriate targets. |
| void InjectTouchEventHitTested(const InternalPointerEvent& event, StreamId stream_id); |
| void InjectMouseEventHitTested(const InternalPointerEvent& event); |
| |
| // Send a copy of the event to the singleton listener of the pointer capture API if there is one. |
| // TODO(fxbug.dev/48150): Delete when we delete the PointerCapture functionality. |
| void ReportPointerEventToPointerCaptureListener(const InternalPointerEvent& event) const; |
| |
| // Enqueue the pointer event into the EventReporter of a View. |
| void ReportPointerEventToGfxLegacyView(const InternalPointerEvent& event, zx_koid_t view_ref_koid, |
| fuchsia::ui::input::PointerEventType type) const; |
| |
| // Takes a ViewRef koid and creates a GfxLegacyContender that delivers events to the corresponding |
| // SessionListener on contest victory. |
| ContenderId AddGfxLegacyContender(StreamId stream_id, zx_koid_t view_ref_koid); |
| |
| fuchsia::ui::input::accessibility::PointerEvent CreateAccessibilityEvent( |
| const InternalPointerEvent& event); |
| |
| // Collects all the GestureContenders for a new touch event stream. |
| std::vector<ContenderId> CollectContenders(StreamId stream_id, const InternalPointerEvent& event); |
| |
| // Updates the gesture arena and all contenders for stream |stream_id| with a new event. |
| void UpdateGestureContest(const InternalPointerEvent& event, StreamId stream_id); |
| |
| // Records a set of responses from a gesture disambiguation contender. |
| void RecordGestureDisambiguationResponse(StreamId stream_id, ContenderId contender_id, |
| const std::vector<GestureResponse>& responses); |
| |
| // Destroy the arena if the contest is complete (i.e. no contenders left or contest over and |
| // stream ended). |
| void DestroyArenaIfComplete(StreamId stream_id); |
| |
| // Helper methods for getting transforms out of |view_tree_snapshot_|. Return std::nullopt if the |
| // passed in koids weren't represented in the |view_tree_snapshot_|. |
| |
| // Returns the transform from world space to view space. |
| std::optional<glm::mat4> GetViewFromWorldTransform(zx_koid_t view_ref_koid) const; |
| // Returns the transform from view space to world space. |
| std::optional<glm::mat4> GetWorldFromViewTransform(zx_koid_t view_ref_koid) const; |
| // Returns the transform from source view space to destination view space. |
| std::optional<glm::mat4> GetDestinationViewFromSourceViewTransform(zx_koid_t source, |
| zx_koid_t destination) const; |
| |
| // TODO(fxbug.dev/64206): Remove when we no longer have any legacy clients. |
| fxl::WeakPtr<gfx::SceneGraph> scene_graph_; |
| |
| const RequestFocusFunc request_focus_; |
| |
| std::unique_ptr<A11yPointerEventRegistry> a11y_pointer_event_registry_; |
| std::unique_ptr<PointerinjectorRegistry> pointerinjector_registry_; |
| |
| fidl::BindingSet<fuchsia::ui::input::PointerCaptureListenerRegistry> pointer_capture_registry_; |
| // A singleton listener who wants to be notified when pointer events happen. |
| // We honor the first pointer capture listener to register. A call to RegisterListener() |
| // above will fail if there is already a registered listener. |
| std::optional<PointerCaptureListener> pointer_capture_listener_; |
| |
| // Tracks the View each mouse pointer is delivered to; a map from device ID to a ViewRef KOID. |
| // This is used to ensure consistent delivery of mouse events for a given device. A focus change |
| // triggered by other pointer events should *not* affect delivery of events to existing mice. |
| std::unordered_map<uint32_t, std::vector</*view_ref_koids*/ zx_koid_t>> mouse_targets_; |
| |
| // GestureContender for the accessibility. Defined while a11y is active, null otherwise. |
| std::unique_ptr<A11yLegacyContender> a11y_legacy_contender_; |
| ContenderId a11y_contender_id_ = 1; |
| |
| // Mapping of {device_id, pointer_id} to stream id for gfx legacy injection. |
| std::map<std::pair<uint32_t, uint32_t>, StreamId> gfx_legacy_streams_; |
| std::unordered_map<ContenderId, GfxLegacyContender> gfx_legacy_contenders_; |
| ContenderId next_contender_id_ = 2; |
| |
| // Map of all active contenders. If any contender is deleted, it must be removed from this map. |
| std::unordered_map<ContenderId, GestureContender*> contenders_; |
| |
| std::unordered_map<StreamId, GestureArena> gesture_arenas_; |
| |
| // Snapshot of the ViewTree. Replaced with a new snapshot on call to OnNewViewTreeSnapshot(), |
| // which happens once per rendered frame. This is the source of truth for the state of the |
| // graphics system. |
| std::shared_ptr<const view_tree::Snapshot> view_tree_snapshot_ = |
| std::make_shared<const view_tree::Snapshot>(); |
| }; |
| |
| } // namespace scenic_impl::input |
| |
| #endif // SRC_UI_SCENIC_LIB_INPUT_INPUT_SYSTEM_H_ |