| // Copyright 2014 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "ui/aura/test/event_generator_delegate_aura.h" |
| |
| #include "base/macros.h" |
| #include "base/run_loop.h" |
| #include "services/service_manager/public/cpp/connector.h" |
| #include "services/ws/public/mojom/constants.mojom.h" |
| #include "services/ws/public/mojom/event_injector.mojom.h" |
| #include "ui/aura/client/screen_position_client.h" |
| #include "ui/aura/env.h" |
| #include "ui/aura/mus/window_port_mus.h" |
| #include "ui/aura/test/env_test_helper.h" |
| #include "ui/aura/test/mus/window_tree_client_private.h" |
| #include "ui/aura/window_event_dispatcher.h" |
| #include "ui/aura/window_tree_host.h" |
| #include "ui/base/ime/input_method.h" |
| #include "ui/display/screen.h" |
| #include "ui/events/event_sink.h" |
| #include "ui/events/event_source.h" |
| #include "ui/events/event_target_iterator.h" |
| |
| namespace aura { |
| namespace test { |
| namespace { |
| |
| class DefaultEventGeneratorDelegate : public EventGeneratorDelegateAura { |
| public: |
| explicit DefaultEventGeneratorDelegate(gfx::NativeWindow root_window) |
| : root_window_(root_window) {} |
| |
| ~DefaultEventGeneratorDelegate() override = default; |
| |
| // EventGeneratorDelegateAura: |
| ui::EventTarget* GetTargetAt(const gfx::Point& location) override { |
| return root_window_->GetHost()->window(); |
| } |
| |
| client::ScreenPositionClient* GetScreenPositionClient( |
| const aura::Window* window) const override { |
| return nullptr; |
| } |
| |
| private: |
| Window* root_window_; |
| |
| DISALLOW_COPY_AND_ASSIGN(DefaultEventGeneratorDelegate); |
| }; |
| |
| // EventTargeterMus serves to send events to the remote window-service by way |
| // of the RemoteEventInjector interface. |
| class EventTargeterMus : public ui::EventTarget, |
| public ui::EventTargeter, |
| public ui::EventSource, |
| public ui::EventSink { |
| public: |
| explicit EventTargeterMus(service_manager::Connector* connector) |
| : connector_(connector) { |
| DCHECK(connector); |
| } |
| ~EventTargeterMus() override = default; |
| |
| // ui::EventTargeter: |
| ui::EventTarget* FindTargetForEvent(ui::EventTarget* root, |
| ui::Event* event) override { |
| return this; |
| } |
| ui::EventTarget* FindNextBestTarget(ui::EventTarget* previous_target, |
| ui::Event* event) override { |
| return this; |
| } |
| |
| // ui::EventTarget: |
| bool CanAcceptEvent(const ui::Event& event) override { return true; } |
| ui::EventTarget* GetParentTarget() override { return nullptr; } |
| std::unique_ptr<ui::EventTargetIterator> GetChildIterator() const override { |
| return nullptr; |
| } |
| ui::EventTargeter* GetEventTargeter() override { return this; } |
| |
| // ui::EventSource: |
| ui::EventSink* GetEventSink() override { return this; } |
| |
| // ui::EventSink: |
| ui::EventDispatchDetails OnEventFromSource(ui::Event* event) override { |
| if (!remote_event_injector_) { |
| connector_->BindInterface(ws::mojom::kServiceName, |
| &remote_event_injector_); |
| } |
| base::RunLoop run_loop; |
| std::unique_ptr<ui::Event> cloned_event; |
| // TODO: event conversion should not be necessary. https://crbug.com/865781 |
| if (event->IsMouseEvent()) |
| cloned_event = std::make_unique<ui::PointerEvent>(*event->AsMouseEvent()); |
| else if (event->IsTouchEvent()) |
| cloned_event = std::make_unique<ui::PointerEvent>(*event->AsTouchEvent()); |
| else |
| DCHECK(!event->IsGestureEvent()); |
| ui::Event* event_to_send = cloned_event ? cloned_event.get() : event; |
| remote_event_injector_->InjectEvent( |
| display::Screen::GetScreen()->GetPrimaryDisplay().id(), |
| ui::Event::Clone(*event_to_send), |
| base::BindOnce( |
| [](base::RunLoop* run_loop, bool success) { |
| // NOTE: a failure is not necessarily fatal, or result in the test |
| // failing. |
| if (!success) |
| LOG(ERROR) << "Remote event injection failed"; |
| run_loop->Quit(); |
| }, |
| &run_loop)); |
| run_loop.Run(); |
| return ui::EventDispatchDetails(); |
| } |
| |
| private: |
| service_manager::Connector* connector_; |
| ws::mojom::EventInjectorPtr remote_event_injector_; |
| |
| DISALLOW_COPY_AND_ASSIGN(EventTargeterMus); |
| }; |
| |
| // EventGeneratorDelegate implementation for mus. |
| class EventGeneratorDelegateMus : public EventGeneratorDelegateAura { |
| public: |
| explicit EventGeneratorDelegateMus(service_manager::Connector* connector) |
| : event_targeter_(connector) {} |
| |
| ~EventGeneratorDelegateMus() override = default; |
| |
| // EventGeneratorDelegateAura: |
| ui::EventTarget* GetTargetAt(const gfx::Point& location) override { |
| return &event_targeter_; |
| } |
| client::ScreenPositionClient* GetScreenPositionClient( |
| const aura::Window* window) const override { |
| return client::GetScreenPositionClient(window->GetRootWindow()); |
| } |
| ui::EventSource* GetEventSource(ui::EventTarget* target) override { |
| return target == &event_targeter_ |
| ? &event_targeter_ |
| : EventGeneratorDelegateAura::GetEventSource(target); |
| } |
| gfx::Point CenterOfTarget(const ui::EventTarget* target) const override { |
| if (target != &event_targeter_) |
| return EventGeneratorDelegateAura::CenterOfTarget(target); |
| return display::Screen::GetScreen() |
| ->GetPrimaryDisplay() |
| .bounds() |
| .CenterPoint(); |
| } |
| void ConvertPointFromTarget(const ui::EventTarget* target, |
| gfx::Point* point) const override { |
| if (target != &event_targeter_) |
| EventGeneratorDelegateAura::ConvertPointFromTarget(target, point); |
| } |
| void ConvertPointToTarget(const ui::EventTarget* target, |
| gfx::Point* point) const override { |
| if (target != &event_targeter_) |
| EventGeneratorDelegateAura::ConvertPointToTarget(target, point); |
| } |
| void ConvertPointFromHost(const ui::EventTarget* hosted_target, |
| gfx::Point* point) const override { |
| if (hosted_target != &event_targeter_) |
| EventGeneratorDelegateAura::ConvertPointFromHost(hosted_target, point); |
| } |
| void DispatchEventToPointerWatchers(ui::EventTarget* target, |
| const ui::PointerEvent& event) override { |
| // Does nothing as events are injected into mus, which should trigger |
| // pointer events to be handled. |
| } |
| |
| private: |
| EventTargeterMus event_targeter_; |
| |
| DISALLOW_COPY_AND_ASSIGN(EventGeneratorDelegateMus); |
| }; |
| |
| const Window* WindowFromTarget(const ui::EventTarget* event_target) { |
| return static_cast<const Window*>(event_target); |
| } |
| |
| } // namespace |
| |
| // static |
| std::unique_ptr<ui::test::EventGeneratorDelegate> |
| EventGeneratorDelegateAura::Create(service_manager::Connector* connector, |
| ui::test::EventGenerator* owner, |
| gfx::NativeWindow root_window, |
| gfx::NativeWindow window) { |
| // Do not create EventGeneratorDelegateMus if a root window is supplied. |
| // Assume that if a root is supplied the event generator should target the |
| // specified window, and there is no need to dispatch remotely. |
| if (connector && !root_window) |
| return std::make_unique<EventGeneratorDelegateMus>(connector); |
| return std::make_unique<DefaultEventGeneratorDelegate>(root_window); |
| } |
| |
| EventGeneratorDelegateAura::EventGeneratorDelegateAura() = default; |
| |
| EventGeneratorDelegateAura::~EventGeneratorDelegateAura() = default; |
| |
| ui::EventSource* EventGeneratorDelegateAura::GetEventSource( |
| ui::EventTarget* target) { |
| return static_cast<Window*>(target)->GetHost()->GetEventSource(); |
| } |
| |
| gfx::Point EventGeneratorDelegateAura::CenterOfTarget( |
| const ui::EventTarget* target) const { |
| gfx::Point center = |
| gfx::Rect(WindowFromTarget(target)->bounds().size()).CenterPoint(); |
| ConvertPointFromTarget(target, ¢er); |
| return center; |
| } |
| |
| gfx::Point EventGeneratorDelegateAura::CenterOfWindow( |
| gfx::NativeWindow window) const { |
| return CenterOfTarget(window); |
| } |
| |
| void EventGeneratorDelegateAura::ConvertPointFromTarget( |
| const ui::EventTarget* event_target, |
| gfx::Point* point) const { |
| DCHECK(point); |
| const Window* target = WindowFromTarget(event_target); |
| aura::client::ScreenPositionClient* client = GetScreenPositionClient(target); |
| if (client) |
| client->ConvertPointToScreen(target, point); |
| else |
| aura::Window::ConvertPointToTarget(target, target->GetRootWindow(), point); |
| } |
| |
| void EventGeneratorDelegateAura::ConvertPointToTarget( |
| const ui::EventTarget* event_target, |
| gfx::Point* point) const { |
| DCHECK(point); |
| const Window* target = WindowFromTarget(event_target); |
| aura::client::ScreenPositionClient* client = GetScreenPositionClient(target); |
| if (client) |
| client->ConvertPointFromScreen(target, point); |
| else |
| aura::Window::ConvertPointToTarget(target->GetRootWindow(), target, point); |
| } |
| |
| void EventGeneratorDelegateAura::ConvertPointFromHost( |
| const ui::EventTarget* hosted_target, |
| gfx::Point* point) const { |
| const Window* window = WindowFromTarget(hosted_target); |
| window->GetHost()->ConvertPixelsToDIP(point); |
| } |
| |
| ui::EventDispatchDetails EventGeneratorDelegateAura::DispatchKeyEventToIME( |
| ui::EventTarget* target, |
| ui::KeyEvent* event) { |
| Window* window = static_cast<Window*>(target); |
| return window->GetHost()->GetInputMethod()->DispatchKeyEvent(event); |
| } |
| |
| void EventGeneratorDelegateAura::DispatchEventToPointerWatchers( |
| ui::EventTarget* target, |
| const ui::PointerEvent& event) { |
| // In non-mus aura PointerWatchers are handled by system-wide EventHandlers, |
| // for example ash::Shell and ash::PointerWatcherAdapter. |
| if (!Env::GetInstance()->HasWindowTreeClient()) |
| return; |
| |
| Window* window = static_cast<Window*>(target); |
| if (!WindowPortMus::Get(window)) |
| return; |
| // Route the event through WindowTreeClient as in production mus. Does nothing |
| // if there are no PointerWatchers installed. |
| WindowTreeClient* window_tree_client = EnvTestHelper().GetWindowTreeClient(); |
| WindowTreeClientPrivate(window_tree_client) |
| .CallOnPointerEventObserved(window, ui::Event::Clone(event)); |
| } |
| |
| } // namespace test |
| } // namespace aura |