ws: Queue input events on delivery, not dispatch.

Queue additional events generated by EventRewriters, as needed.
Refactor EventQueue to operate later, closer to EventSink delivery.

Eliminate HostEventQueue and [Test]HostEventDispatcher.
Use Shell via WSDelegate for EventInjector's display -> host lookup.

Update tests and setup code; add a queue unit test for host destruction.
Move content_browsertests' aura::TestScreen ownership to WMTestHelper.

TODO: Remove WindowTreeHost::event_sink(), use GetEventSink().

Alternate WIP sticky keys DCHECK workaround: https://crrev.com/c/1371878

Bug: 913549
Test: No SingleProcessMash sticky keys DCHECK, no input regressions.
Change-Id: I61d67af94fad0ed8414a7945160a7c231dca47a1
Reviewed-on: https://chromium-review.googlesource.com/c/1372629
Commit-Queue: Michael Wasserman <msw@chromium.org>
Reviewed-by: Scott Violet <sky@chromium.org>
Cr-Commit-Position: refs/heads/master@{#616930}
diff --git a/ash/display/extended_mouse_warp_controller_unittest.cc b/ash/display/extended_mouse_warp_controller_unittest.cc
index f523765..d99f540 100644
--- a/ash/display/extended_mouse_warp_controller_unittest.cc
+++ b/ash/display/extended_mouse_warp_controller_unittest.cc
@@ -66,7 +66,7 @@
                                 location_in_host_native, ui::EventTimeForNow(),
                                 event_flag1, event_flag2);
     ui::MouseEvent mouseev(&native_event);
-    host->DispatchEventFromQueue(&mouseev);
+    host->DispatchEvent(&mouseev);
 
     // The test relies on the last_mouse_location, which will be updated by
     // a synthesized event posted asynchronusly. Wait until the synthesized
diff --git a/ash/host/ash_window_tree_host_platform.cc b/ash/host/ash_window_tree_host_platform.cc
index 7f237a7..de050d2 100644
--- a/ash/host/ash_window_tree_host_platform.cc
+++ b/ash/host/ash_window_tree_host_platform.cc
@@ -14,7 +14,7 @@
 #include "ash/ws/window_service_owner.h"
 #include "base/feature_list.h"
 #include "base/trace_event/trace_event.h"
-#include "services/ws/host_event_queue.h"
+#include "services/ws/event_queue.h"
 #include "services/ws/public/cpp/input_devices/input_device_controller_client.h"
 #include "services/ws/public/mojom/window_manager.mojom.h"
 #include "services/ws/window_service.h"
@@ -181,17 +181,11 @@
   ConfineCursorToRootWindow();
 }
 
-void AshWindowTreeHostPlatform::DispatchEvent(ui::Event* event) {
-  host_event_queue_->DispatchOrQueueEvent(event);
-}
-
 void AshWindowTreeHostPlatform::CommonInit() {
   transformer_helper_.Init();
 
-  host_event_queue_ = Shell::Get()
-                          ->window_service_owner()
-                          ->window_service()
-                          ->RegisterHostEventDispatcher(this, this);
+  event_queue_ =
+      Shell::Get()->window_service_owner()->window_service()->event_queue();
 
   if (!base::FeatureList::IsEnabled(features::kMash))
     return;
@@ -201,14 +195,6 @@
   SetSharedInputMethod(input_method_.get());
 }
 
-ui::EventDispatchDetails AshWindowTreeHostPlatform::DispatchEventFromQueue(
-    ui::Event* event) {
-  TRACE_EVENT0("input", "AshWindowTreeHostPlatform::DispatchEvent");
-  if (event->IsLocatedEvent())
-    TranslateLocatedEvent(static_cast<ui::LocatedEvent*>(event));
-  return SendEventToSink(event);
-}
-
 void AshWindowTreeHostPlatform::SetTapToClickPaused(bool state) {
   ws::InputDeviceControllerClient* input_device_controller_client =
       Shell::Get()->shell_delegate()->GetInputDeviceControllerClient();
@@ -226,6 +212,20 @@
   return !target || !ws::WindowService::IsProxyWindow(target);
 }
 
+void AshWindowTreeHostPlatform::DispatchEvent(ui::Event* event) {
+  TRACE_EVENT0("input", "AshWindowTreeHostPlatform::DispatchEvent");
+  if (event->IsLocatedEvent())
+    TranslateLocatedEvent(event->AsLocatedEvent());
+  return aura::WindowTreeHostPlatform::DispatchEvent(event);
+}
+
+ui::EventDispatchDetails AshWindowTreeHostPlatform::DeliverEventToSink(
+    ui::Event* event) {
+  // Queue the event if needed, or deliver it directly to the sink.
+  auto result = event_queue_->DeliverOrQueueEvent(this, event);
+  return result.value_or(ui::EventDispatchDetails());
+}
+
 void AshWindowTreeHostPlatform::SetTextInputState(
     ui::mojom::TextInputStatePtr state) {
   ui::PlatformImeController* ime =
diff --git a/ash/host/ash_window_tree_host_platform.h b/ash/host/ash_window_tree_host_platform.h
index 32267ac1..09476d6 100644
--- a/ash/host/ash_window_tree_host_platform.h
+++ b/ash/host/ash_window_tree_host_platform.h
@@ -10,7 +10,6 @@
 #include "ash/ash_export.h"
 #include "ash/host/ash_window_tree_host.h"
 #include "ash/host/transformer_helper.h"
-#include "services/ws/host_event_dispatcher.h"
 #include "ui/aura/mus/input_method_mus_delegate.h"
 #include "ui/aura/window_tree_host_platform.h"
 
@@ -19,7 +18,7 @@
 }
 
 namespace ws {
-class HostEventQueue;
+class EventQueue;
 }
 
 namespace ui {
@@ -32,8 +31,7 @@
 class ASH_EXPORT AshWindowTreeHostPlatform
     : public AshWindowTreeHost,
       public aura::WindowTreeHostPlatform,
-      public aura::InputMethodMusDelegate,
-      public ws::HostEventDispatcher {
+      public aura::InputMethodMusDelegate {
  public:
   explicit AshWindowTreeHostPlatform(
       ui::PlatformWindowInitProperties properties);
@@ -73,17 +71,15 @@
   void SetBoundsInPixels(const gfx::Rect& bounds,
                          const viz::LocalSurfaceIdAllocation&
                              local_surface_id_allocation) override;
-  void DispatchEvent(ui::Event* event) override;
   bool ShouldSendKeyEventToIme() override;
+  void DispatchEvent(ui::Event* event) override;
+  ui::EventDispatchDetails DeliverEventToSink(ui::Event* event) override;
 
   // aura::InputMethodMusDelegate:
   void SetTextInputState(ui::mojom::TextInputStatePtr state) override;
   void SetImeVisibility(bool visible,
                         ui::mojom::TextInputStatePtr state) override;
 
-  // ws::HostEventDispatcher:
-  ui::EventDispatchDetails DispatchEventFromQueue(ui::Event* event) override;
-
  private:
   // All constructors call into this.
   void CommonInit();
@@ -102,7 +98,7 @@
   // those connections are correctly established.
   std::unique_ptr<aura::InputMethodMus> input_method_;
 
-  std::unique_ptr<ws::HostEventQueue> host_event_queue_;
+  ws::EventQueue* event_queue_ = nullptr;
 
   DISALLOW_COPY_AND_ASSIGN(AshWindowTreeHostPlatform);
 };
diff --git a/ash/ws/window_service_delegate_impl.cc b/ash/ws/window_service_delegate_impl.cc
index 90fe7fc..816600f 100644
--- a/ash/ws/window_service_delegate_impl.cc
+++ b/ash/ws/window_service_delegate_impl.cc
@@ -223,6 +223,11 @@
   return Shell::Get();
 }
 
+aura::Window* WindowServiceDelegateImpl::GetRootWindowForDisplayId(
+    int64_t display_id) {
+  return Shell::Get()->GetRootWindowForDisplayId(display_id);
+}
+
 aura::Window* WindowServiceDelegateImpl::GetTopmostWindowAtPoint(
     const gfx::Point& location_in_screen,
     const std::set<aura::Window*>& ignore,
diff --git a/ash/ws/window_service_delegate_impl.h b/ash/ws/window_service_delegate_impl.h
index 5fc2fa4..da131644 100644
--- a/ash/ws/window_service_delegate_impl.h
+++ b/ash/ws/window_service_delegate_impl.h
@@ -43,6 +43,7 @@
   void SetModalType(aura::Window* window, ui::ModalType type) override;
   ui::SystemInputInjector* GetSystemInputInjector() override;
   ui::EventTarget* GetGlobalEventTarget() override;
+  aura::Window* GetRootWindowForDisplayId(int64_t display_id) override;
   aura::Window* GetTopmostWindowAtPoint(const gfx::Point& location_in_screen,
                                         const std::set<aura::Window*>& ignores,
                                         aura::Window** real_topmost) override;
diff --git a/content/shell/browser/shell.h b/content/shell/browser/shell.h
index 4faf60e..e014d4c 100644
--- a/content/shell/browser/shell.h
+++ b/content/shell/browser/shell.h
@@ -26,10 +26,6 @@
 #elif defined(USE_AURA)
 #if defined(OS_CHROMEOS)
 
-namespace display {
-class Screen;
-}
-
 namespace wm {
 class WMTestHelper;
 }
@@ -293,7 +289,6 @@
 #elif defined(USE_AURA)
 #if defined(OS_CHROMEOS)
   static wm::WMTestHelper* wm_test_helper_;
-  static display::Screen* test_screen_;
 #else
   static wm::WMState* wm_state_;
 #endif
diff --git a/content/shell/browser/shell_views.cc b/content/shell/browser/shell_views.cc
index c7f3ac3..ef4da07 100644
--- a/content/shell/browser/shell_views.cc
+++ b/content/shell/browser/shell_views.cc
@@ -20,7 +20,6 @@
 #include "ui/aura/window_event_dispatcher.h"
 #include "ui/base/clipboard/clipboard.h"
 #include "ui/base/resource/resource_bundle.h"
-#include "ui/display/screen.h"
 #include "ui/events/event.h"
 #include "ui/views/background.h"
 #include "ui/views/controls/button/md_text_button.h"
@@ -35,7 +34,6 @@
 #include "ui/views/widget/widget_delegate.h"
 
 #if defined(OS_CHROMEOS)
-#include "ui/aura/test/test_screen.h"
 #include "ui/wm/test/wm_test_helper.h"
 #else  // !defined(OS_CHROMEOS)
 #include "ui/views/widget/desktop_aura/desktop_screen.h"
@@ -318,8 +316,6 @@
 #if defined(OS_CHROMEOS)
 // static
 wm::WMTestHelper* Shell::wm_test_helper_ = nullptr;
-// static
-display::Screen* Shell::test_screen_ = nullptr;
 #elif defined(USE_AURA)
 // static
 wm::WMState* Shell::wm_state_ = nullptr;
@@ -334,8 +330,6 @@
   _setmode(_fileno(stderr), _O_BINARY);
 #endif
 #if defined(OS_CHROMEOS)
-  test_screen_ = aura::TestScreen::Create(gfx::Size());
-  display::Screen::SetScreenInstance(test_screen_);
   ui::ContextFactory* ui_context_factory =
       aura::Env::GetInstance()->mode() == aura::Env::Mode::LOCAL
           ? GetContextFactory()
@@ -355,9 +349,6 @@
 #if defined(OS_CHROMEOS)
   delete wm_test_helper_;
   wm_test_helper_ = nullptr;
-
-  delete test_screen_;
-  test_screen_ = nullptr;
 #endif
   delete views_delegate_;
   views_delegate_ = nullptr;
diff --git a/services/ws/BUILD.gn b/services/ws/BUILD.gn
index e37828e..83a649d 100644
--- a/services/ws/BUILD.gn
+++ b/services/ws/BUILD.gn
@@ -17,8 +17,7 @@
     "//ash:ash_unittests",
   ]
   public = [
-    "host_event_dispatcher.h",
-    "host_event_queue.h",
+    "event_queue.h",
     "ids.h",
     "window_delegate_impl.h",
     "window_manager_interface.h",
@@ -46,10 +45,8 @@
     "event_observer_helper.cc",
     "event_observer_helper.h",
     "event_queue.cc",
-    "event_queue.h",
     "focus_handler.cc",
     "focus_handler.h",
-    "host_event_queue.cc",
     "injected_event_handler.cc",
     "injected_event_handler.h",
     "proxy_window.cc",
@@ -137,8 +134,6 @@
     "proxy_window_test_helper.h",
     "test_change_tracker.cc",
     "test_change_tracker.h",
-    "test_host_event_dispatcher.cc",
-    "test_host_event_dispatcher.h",
     "test_screen_provider_observer.cc",
     "test_screen_provider_observer.h",
     "test_window_service_delegate.cc",
diff --git a/services/ws/event_injector.cc b/services/ws/event_injector.cc
index 0693947..19e63bb 100644
--- a/services/ws/event_injector.cc
+++ b/services/ws/event_injector.cc
@@ -7,12 +7,10 @@
 #include "base/bind.h"
 #include "base/stl_util.h"
 #include "services/ws/event_queue.h"
-#include "services/ws/host_event_queue.h"
 #include "services/ws/injected_event_handler.h"
 #include "services/ws/window_service.h"
+#include "services/ws/window_service_delegate.h"
 #include "ui/aura/window_tree_host.h"
-#include "ui/display/display.h"
-#include "ui/display/screen.h"
 #include "ui/events/event.h"
 #include "ui/events/event_sink.h"
 
@@ -20,7 +18,7 @@
 
 struct EventInjector::EventAndHost {
   std::unique_ptr<ui::Event> event;
-  aura::WindowTreeHost* window_tree_host = nullptr;
+  aura::WindowTreeHost* host = nullptr;
 };
 
 struct EventInjector::HandlerAndCallback {
@@ -30,9 +28,8 @@
 };
 
 struct EventInjector::QueuedEvent {
-  int64_t display_id;
-  // |callback| is the callback supplied by the client.
-  EventInjector::InjectEventCallback callback;
+  base::WeakPtr<aura::WindowTreeHost> host;  // May be destroyed while queued.
+  EventInjector::InjectEventCallback callback;  // Supplied by the client.
   std::unique_ptr<ui::Event> event;
 };
 
@@ -65,21 +62,15 @@
   NOTREACHED();
 }
 
-aura::WindowTreeHost* EventInjector::GetWindowTreeHostForDisplayId(
-    int64_t display_id) {
-  HostEventQueue* host_event_queue =
-      window_service_->event_queue()->GetHostEventQueueForDisplay(display_id);
-  return host_event_queue ? host_event_queue->window_tree_host() : nullptr;
-}
-
 EventInjector::EventAndHost EventInjector::DetermineEventAndHost(
     int64_t display_id,
     std::unique_ptr<ui::Event> event) {
   EventAndHost event_and_host;
-  aura::WindowTreeHost* window_tree_host =
-      GetWindowTreeHostForDisplayId(display_id);
-  if (!window_tree_host) {
-    DVLOG(1) << "InjectEvent(): invalid display " << display_id;
+  aura::Window* window =
+      window_service_->delegate()->GetRootWindowForDisplayId(display_id);
+  event_and_host.host = window ? window->GetHost() : nullptr;
+  if (!event_and_host.host) {
+    DVLOG(1) << "InjectEvent(): invalid or destroyed display " << display_id;
     return event_and_host;
   }
 
@@ -96,7 +87,6 @@
     // https://chromium.googlesource.com/chromium/src/+/ae087c53f5ce4557bfb0b92a13651342336fe18a/services/ws/event_injector.cc#22
   }
 
-  event_and_host.window_tree_host = window_tree_host;
   event_and_host.event = std::move(event);
   return event_and_host;
 }
@@ -106,9 +96,7 @@
   QueuedEvent queued_event = std::move(queued_events_.front());
   queued_events_.pop_front();
 
-  aura::WindowTreeHost* window_tree_host =
-      GetWindowTreeHostForDisplayId(queued_event.display_id);
-  if (!window_tree_host) {
+  if (!queued_event.host) {
     std::move(queued_event.callback).Run(false);
     return;
   }
@@ -116,8 +104,8 @@
   std::unique_ptr<HandlerAndCallback> handler_and_callback =
       std::make_unique<HandlerAndCallback>();
   handler_and_callback->callback = std::move(queued_event.callback);
-  handler_and_callback->handler =
-      std::make_unique<InjectedEventHandler>(window_service_, window_tree_host);
+  handler_and_callback->handler = std::make_unique<InjectedEventHandler>(
+      window_service_, queued_event.host.get());
   InjectedEventHandler* handler = handler_and_callback->handler.get();
   handlers_.push_back(std::move(handler_and_callback));
   auto callback = base::BindOnce(&EventInjector::OnEventDispatched,
@@ -130,7 +118,7 @@
                                          bool honor_rewriters) {
   EventAndHost event_and_host =
       DetermineEventAndHost(display_id, std::move(event));
-  if (!event_and_host.window_tree_host)
+  if (!event_and_host.host || !event_and_host.event)
     return;
 
   // Reset the latency time. This way telemetry doesn't include the time from
@@ -143,9 +131,12 @@
       ui::INPUT_EVENT_LATENCY_UI_COMPONENT, event_time, 1);
   event_and_host.event->set_latency(latency_info);
 
-  EventQueue::DispatchOrQueueEvent(window_service_,
-                                   event_and_host.window_tree_host,
-                                   event_and_host.event.get(), honor_rewriters);
+  // SendEventToSink send events through rewriters; DeliverEventToSink does not.
+  // The event may be queued before actually being delivered to the EventSink.
+  if (honor_rewriters)
+    event_and_host.host->SendEventToSink(event_and_host.event.get());
+  else
+    event_and_host.host->DeliverEventToSink(event_and_host.event.get());
 }
 
 void EventInjector::InjectEvent(int64_t display_id,
@@ -153,15 +144,15 @@
                                 InjectEventCallback cb) {
   EventAndHost event_and_host =
       DetermineEventAndHost(display_id, std::move(event));
-  if (!event_and_host.window_tree_host) {
+  if (!event_and_host.host || !event_and_host.event) {
     std::move(cb).Run(false);
     return;
   }
 
   QueuedEvent queued_event;
-  queued_event.display_id = display_id;
-  queued_event.callback = std::move(cb);
+  queued_event.host = event_and_host.host->GetWeakPtr();
   queued_event.event = std::move(event_and_host.event);
+  queued_event.callback = std::move(cb);
   queued_events_.push_back(std::move(queued_event));
 
   // Both EventQueue and |this| are owned by WindowService, so Unretained() is
@@ -172,15 +163,13 @@
 
 void EventInjector::InjectEventNoAck(int64_t display_id,
                                      std::unique_ptr<ui::Event> event) {
-  InjectEventNoAckImpl(display_id, std::move(event),
-                       /* honor_rewriters */ true);
+  InjectEventNoAckImpl(display_id, std::move(event), /*honor_rewriters*/ true);
 }
 
 void EventInjector::InjectEventNoAckNoRewriters(
     int64_t display_id,
     std::unique_ptr<ui::Event> event) {
-  InjectEventNoAckImpl(display_id, std::move(event),
-                       /* honor_rewriters */ false);
+  InjectEventNoAckImpl(display_id, std::move(event), /*honor_rewriters*/ false);
 }
 
 }  // namespace ws
diff --git a/services/ws/event_injector.h b/services/ws/event_injector.h
index 4a9edc8..a3abed0 100644
--- a/services/ws/event_injector.h
+++ b/services/ws/event_injector.h
@@ -42,12 +42,9 @@
 
   void OnEventDispatched(InjectedEventHandler* handler);
 
-  aura::WindowTreeHost* GetWindowTreeHostForDisplayId(int64_t display_id);
-
   // Determines the target WindowTreeHost and provides an mapping on |event|
-  // before dispatch. If the returned EventAndHost has a null
-  // |window_tree_host| there was a problem in conversion and the event should
-  // not be dispatched.
+  // before dispatch. If the returned EventAndHost has a null |host|, there was
+  // a problem in conversion and the event should not be dispatched.
   EventAndHost DetermineEventAndHost(int64_t display_id,
                                      std::unique_ptr<ui::Event> event);
 
diff --git a/services/ws/event_injector_unittest.cc b/services/ws/event_injector_unittest.cc
index 2d65def..e804ad2 100644
--- a/services/ws/event_injector_unittest.cc
+++ b/services/ws/event_injector_unittest.cc
@@ -7,6 +7,7 @@
 #include <memory>
 
 #include "services/ws/event_injector.h"
+#include "services/ws/window_delegate_impl.h"
 #include "services/ws/window_service.h"
 #include "services/ws/window_service_test_helper.h"
 #include "services/ws/window_service_test_setup.h"
@@ -33,17 +34,15 @@
 TEST(EventInjectorTest, NoAck) {
   WindowServiceTestSetup test_setup;
   test_setup.service()->OnStart();
-  ui::EventSource* event_source =
-      test_setup.aura_test_helper()->root_window()->GetHost()->GetEventSource();
+  auto* event_source = test_setup.root()->GetHost()->GetEventSource();
   ui::test::TestEventRewriter test_event_rewriter;
   event_source->AddEventRewriter(&test_event_rewriter);
 
-  const int64_t display_id =
-      display::Screen::GetScreen()->GetPrimaryDisplay().id();
   EventInjector* event_injector =
       WindowServiceTestHelper(test_setup.service()).event_injector();
   mojom::EventInjector* mojom_event_injector =
       static_cast<mojom::EventInjector*>(event_injector);
+  auto display_id = display::Screen::GetScreen()->GetPrimaryDisplay().id();
   mojom_event_injector->InjectEventNoAck(display_id, CreateTestEvent());
   EXPECT_EQ(1, test_event_rewriter.events_seen());
   EXPECT_FALSE(event_injector->HasQueuedEvents());
diff --git a/services/ws/event_queue.cc b/services/ws/event_queue.cc
index 2dd345a2..f6b480c 100644
--- a/services/ws/event_queue.cc
+++ b/services/ws/event_queue.cc
@@ -4,9 +4,6 @@
 
 #include "services/ws/event_queue.h"
 
-#include "base/stl_util.h"
-#include "services/ws/host_event_dispatcher.h"
-#include "services/ws/host_event_queue.h"
 #include "services/ws/window_service.h"
 #include "services/ws/window_tree.h"
 #include "ui/aura/window.h"
@@ -32,10 +29,8 @@
 }  // namespace
 
 struct EventQueue::QueuedEvent {
-  HostEventQueue* host = nullptr;
+  base::WeakPtr<aura::WindowTreeHost> host;  // May be destroyed while queued.
   std::unique_ptr<ui::Event> event;
-  bool honor_rewriters = false;
-
   base::OnceClosure callback;
 };
 
@@ -47,39 +42,14 @@
   window_service_->RemoveObserver(this);
 }
 
-std::unique_ptr<HostEventQueue> EventQueue::RegisterHostEventDispatcher(
-    aura::WindowTreeHost* window_tree_host,
-    HostEventDispatcher* dispatcher) {
-  return std::make_unique<HostEventQueue>(weak_factory_.GetWeakPtr(),
-                                          window_tree_host, dispatcher);
-}
+base::Optional<ui::EventDispatchDetails> EventQueue::DeliverOrQueueEvent(
+    aura::WindowTreeHost* host,
+    ui::Event* event) {
+  if (!ShouldQueueEvent(host, *event))
+    return host->GetEventSink()->OnEventFromSource(event);
 
-// static
-base::Optional<ui::EventDispatchDetails> EventQueue::DispatchOrQueueEvent(
-    WindowService* service,
-    aura::WindowTreeHost* window_tree_host,
-    ui::Event* event,
-    bool honor_rewriters) {
-  DCHECK(window_tree_host);
-  HostEventQueue* host_event_queue =
-      service->event_queue()->GetHostEventQueueForDisplay(
-          window_tree_host->GetDisplayId());
-  DCHECK(host_event_queue);
-  return host_event_queue->DispatchOrQueueEvent(event, honor_rewriters);
-}
-
-bool EventQueue::ShouldQueueEvent(HostEventQueue* host_queue,
-                                  const ui::Event& event) {
-  if (!in_flight_event_ || !IsQueableEvent(event))
-    return false;
-  aura::WindowTargeter* targeter =
-      host_queue->window_tree_host()->window()->targeter();
-  if (!targeter)
-    targeter = host_queue->window_tree_host()->dispatcher()->event_targeter();
-  DCHECK(targeter);
-  aura::Window* target =
-      targeter->FindTargetForKeyEvent(host_queue->window_tree_host()->window());
-  return target && WindowService::IsProxyWindow(target);
+  QueueEvent(host, *event);
+  return base::nullopt;
 }
 
 void EventQueue::NotifyWhenReadyToDispatch(base::OnceClosure closure) {
@@ -92,40 +62,24 @@
   }
 }
 
-HostEventQueue* EventQueue::GetHostEventQueueForDisplay(int64_t display_id) {
-  for (HostEventQueue* host_queue : host_event_queues_) {
-    if (host_queue->window_tree_host()->GetDisplayId() == display_id)
-      return host_queue;
-  }
-  return nullptr;
+bool EventQueue::ShouldQueueEvent(aura::WindowTreeHost* host,
+                                  const ui::Event& event) {
+  if (!in_flight_event_ || !IsQueableEvent(event))
+    return false;
+  aura::WindowTargeter* targeter = host->window()->targeter();
+  if (!targeter)
+    targeter = host->dispatcher()->event_targeter();
+  DCHECK(targeter);
+  aura::Window* target = targeter->FindTargetForKeyEvent(host->window());
+  return target && WindowService::IsProxyWindow(target);
 }
 
-void EventQueue::OnClientTookTooLongToAckEvent() {
-  DVLOG(1) << "Client took too long to respond to event";
-  DCHECK(in_flight_event_);
-  OnClientAckedEvent(in_flight_event_->client_id, in_flight_event_->event_id);
-}
-
-void EventQueue::OnHostEventQueueCreated(HostEventQueue* host) {
-  host_event_queues_.insert(host);
-}
-
-void EventQueue::OnHostEventQueueDestroyed(HostEventQueue* host) {
-  base::EraseIf(queued_events_,
-                [&host](const std::unique_ptr<QueuedEvent>& event) {
-                  return event->host == host;
-                });
-  host_event_queues_.erase(host);
-}
-
-void EventQueue::QueueEvent(HostEventQueue* host,
-                            const ui::Event& event,
-                            bool honor_rewriters) {
+void EventQueue::QueueEvent(aura::WindowTreeHost* host,
+                            const ui::Event& event) {
   DCHECK(ShouldQueueEvent(host, event));
   std::unique_ptr<QueuedEvent> queued_event = std::make_unique<QueuedEvent>();
-  queued_event->host = host;
+  queued_event->host = host->GetWeakPtr();
   queued_event->event = ui::Event::Clone(event);
-  queued_event->honor_rewriters = honor_rewriters;
   queued_events_.push_back(std::move(queued_event));
 }
 
@@ -135,14 +89,21 @@
         std::move(*queued_events_.begin());
     queued_events_.pop_front();
     if (queued_event->callback) {
+      DCHECK(!queued_event->event) << "Running callback and ignoring event";
       std::move(queued_event->callback).Run();
-    } else {
-      queued_event->host->DispatchEventDontQueue(queued_event->event.get(),
-                                                 queued_event->honor_rewriters);
+    } else if (queued_event->host) {
+      ignore_result(queued_event->host->GetEventSink()->OnEventFromSource(
+          queued_event->event.get()));
     }
   }
 }
 
+void EventQueue::OnClientTookTooLongToAckEvent() {
+  DVLOG(1) << "Client took too long to respond to event";
+  DCHECK(in_flight_event_);
+  OnClientAckedEvent(in_flight_event_->client_id, in_flight_event_->event_id);
+}
+
 void EventQueue::OnWillSendEventToClient(ClientSpecificId client_id,
                                          uint32_t event_id,
                                          const ui::Event& event) {
diff --git a/services/ws/event_queue.h b/services/ws/event_queue.h
index 0f2d4ff..0fe3972 100644
--- a/services/ws/event_queue.h
+++ b/services/ws/event_queue.h
@@ -8,7 +8,6 @@
 #include <stdint.h>
 
 #include <memory>
-#include <set>
 
 #include "base/callback_forward.h"
 #include "base/component_export.h"
@@ -31,51 +30,30 @@
 
 namespace ws {
 
-class HostEventDispatcher;
-class HostEventQueue;
 class WindowService;
 
-// EventQueue handles the actual queuing, waiting and dispatching of events.
-// HostEventQueues calls into this. EventQueue tracks the dispatch by way of
-// being a WindowServiceObserver. EventQueue also supports adding a callback
-// that is notified when the queue is empty.
+// EventQueue handles queueing, waiting, and delivering events to event sinks.
+// EventQueue tracks the dispatch by way of being a WindowServiceObserver.
+// EventQueue also supports queueing callbacks run in order with queued events.
 class COMPONENT_EXPORT(WINDOW_SERVICE) EventQueue
     : public WindowServiceObserver {
  public:
   explicit EventQueue(WindowService* service);
   ~EventQueue() override;
 
-  // Creates a new HostEventQueue.
-  std::unique_ptr<HostEventQueue> RegisterHostEventDispatcher(
-      aura::WindowTreeHost* window_tree_host,
-      HostEventDispatcher* dispatcher);
-
-  // Convenience to locate the HostEventDispatcher for |window_tree_host|
-  // and call DispatchOrQueueEvent() on it with |event|. If |honor_rewriters|
-  // is true, the event is passed through EventRewriters first. Events received
-  // from the platform go through EventRewriters, so generally
-  // |honor_rewriters| should be true, remote injection may need to circumvent
-  // that though. If the event was not queued, the return value contains the
-  // result of the event processing.
-  static base::Optional<ui::EventDispatchDetails> DispatchOrQueueEvent(
-      WindowService* service,
-      aura::WindowTreeHost* window_tree_host,
-      ui::Event* event,
-      bool honor_rewriters);
-
-  // Returns true if |event| should be queued at this time.
-  bool ShouldQueueEvent(HostEventQueue* host, const ui::Event& event);
+  // Queue the event if needed, or deliver it directly to the host's event sink.
+  // Call WindowTreeHost::SendEventToSink instead, if the event should be passed
+  // through the host's EventRewriters; that calls through here after rewriting.
+  base::Optional<ui::EventDispatchDetails> DeliverOrQueueEvent(
+      aura::WindowTreeHost* host,
+      ui::Event* event);
 
   // Notifies |closure| when this EventQueue is ready to dispatch an event,
   // which may be immediately.
   void NotifyWhenReadyToDispatch(base::OnceClosure closure);
 
-  // Returns the HostEventQueue associated with the specified display.
-  HostEventQueue* GetHostEventQueueForDisplay(int64_t display_id);
-
  private:
   friend class EventQueueTestHelper;
-  friend class HostEventQueue;
 
   struct QueuedEvent;
 
@@ -85,19 +63,16 @@
     uint32_t event_id = 0u;
   };
 
+  // Returns true if |event| should be queued at this time for the given |host|.
+  bool ShouldQueueEvent(aura::WindowTreeHost* host, const ui::Event& event);
+
+  // Adds |event| to |queued_events_| for delivery to |host|.
+  void QueueEvent(aura::WindowTreeHost* host, const ui::Event& event);
+
   // Called by |ack_timer_| if the client does not respond to the event in a
   // timely manner.
   void OnClientTookTooLongToAckEvent();
 
-  // Called when a HostEventQueue is created/deleted.
-  void OnHostEventQueueCreated(HostEventQueue* host);
-  void OnHostEventQueueDestroyed(HostEventQueue* host);
-
-  // Adds |event| to |queued_events_|.
-  void QueueEvent(HostEventQueue* host,
-                  const ui::Event& event,
-                  bool honor_rewriters);
-
   // Processes QueuedEvents until |queued_events_| is empty, or there is an
   // event sent to a client.
   void DispatchNextQueuedEvent();
@@ -117,9 +92,6 @@
   // Set when an event has been sent to a client.
   base::Optional<InFlightEvent> in_flight_event_;
 
-  // Set of HostEventQueues.
-  std::set<HostEventQueue*> host_event_queues_;
-
   base::OneShotTimer ack_timer_;
 
   // Because of destruction order HostEventQueues may outlive this.
diff --git a/services/ws/event_queue_unittest.cc b/services/ws/event_queue_unittest.cc
index 64c07f0..6aa22c8 100644
--- a/services/ws/event_queue_unittest.cc
+++ b/services/ws/event_queue_unittest.cc
@@ -64,8 +64,8 @@
   EXPECT_EQ(CHANGE_TYPE_INPUT_EVENT, (*setup.changes())[0].type);
   setup.changes()->clear();
 
-  // Generator another key event. As still waiting for a response from the
-  // client this event should be queued.
+  // Generate another key event. As the client has not yet responded to the
+  // first event, this event should be queued.
   event_generator.PressKey(ui::VKEY_B, ui::EF_NONE);
   EXPECT_TRUE(event_queue_test_helper.HasInFlightEvent());
   EXPECT_TRUE(setup.changes()->empty());
@@ -145,5 +145,44 @@
   EXPECT_TRUE(was_dispatch_closure_run);
 }
 
+TEST(EventQueueTest, HostDestroyedWhileEventQueued) {
+  WindowServiceTestSetup setup;
+  setup.set_ack_events_immediately(false);
+
+  // Events are only queued if they target a window with a remote client.
+  aura::Window* top_level =
+      setup.window_tree_test_helper()->NewTopLevelWindow();
+  ASSERT_TRUE(top_level);
+  top_level->Show();
+  top_level->Focus();
+  EXPECT_TRUE(top_level->HasFocus());
+
+  // Generate a single key event.
+  setup.changes()->clear();
+  EventQueueTestHelper event_queue_test_helper(setup.service()->event_queue());
+  ui::test::EventGenerator event_generator(setup.root());
+  event_generator.PressKey(ui::VKEY_A, ui::EF_NONE);
+  EXPECT_TRUE(event_queue_test_helper.HasInFlightEvent());
+  ASSERT_EQ(1u, setup.changes()->size());
+  EXPECT_EQ(CHANGE_TYPE_INPUT_EVENT, (*setup.changes())[0].type);
+  setup.changes()->clear();
+
+  // Generate another key event. As the client has not yet responded to the
+  // first event, this event should be queued.
+  event_generator.PressKey(ui::VKEY_B, ui::EF_NONE);
+  EXPECT_TRUE(event_queue_test_helper.HasInFlightEvent());
+  EXPECT_TRUE(setup.changes()->empty());
+
+  // Destroy the window and its host.
+  setup.window_tree_test_helper()->DeleteWindow(top_level);
+  setup.changes()->clear();
+
+  // Ack the first event, the second event should be safely ignored.
+  event_queue_test_helper.AckInFlightEvent();
+  EXPECT_FALSE(event_queue_test_helper.HasInFlightEvent());
+  auto iter = FirstChangeOfType(*setup.changes(), CHANGE_TYPE_INPUT_EVENT);
+  EXPECT_EQ(iter, setup.changes()->end());
+}
+
 }  // namespace
 }  // namespace ws
diff --git a/services/ws/host_event_dispatcher.h b/services/ws/host_event_dispatcher.h
deleted file mode 100644
index f5e9622..0000000
--- a/services/ws/host_event_dispatcher.h
+++ /dev/null
@@ -1,32 +0,0 @@
-// Copyright 2018 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.
-
-#ifndef SERVICES_WS_HOST_EVENT_DISPATCHER_H_
-#define SERVICES_WS_HOST_EVENT_DISPATCHER_H_
-
-#include "base/component_export.h"
-#include "base/macros.h"
-
-namespace ui {
-class Event;
-struct EventDispatchDetails;
-}
-
-namespace ws {
-
-// Used to dispatch events. See HostEventQueue for details.
-class COMPONENT_EXPORT(WINDOW_SERVICE) HostEventDispatcher {
- public:
-  // NOTE: as with other event dispatch related functions, the *caller* owns
-  // |event|, but HostEventDispatcher may modify |event| as necessary (but not
-  // delete it).
-  virtual ui::EventDispatchDetails DispatchEventFromQueue(ui::Event* event) = 0;
-
- protected:
-  virtual ~HostEventDispatcher() = default;
-};
-
-}  // namespace ws
-
-#endif  // SERVICES_WS_HOST_EVENT_DISPATCHER_H_
diff --git a/services/ws/host_event_queue.cc b/services/ws/host_event_queue.cc
deleted file mode 100644
index fc7e5afa..0000000
--- a/services/ws/host_event_queue.cc
+++ /dev/null
@@ -1,46 +0,0 @@
-// Copyright 2018 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 "services/ws/host_event_queue.h"
-
-#include "services/ws/event_queue.h"
-#include "services/ws/host_event_dispatcher.h"
-#include "ui/aura/window_tree_host.h"
-#include "ui/events/event_sink.h"
-
-namespace ws {
-
-HostEventQueue::HostEventQueue(base::WeakPtr<EventQueue> event_queue,
-                               aura::WindowTreeHost* window_tree_host,
-                               HostEventDispatcher* host_event_dispatcher)
-    : event_queue_(event_queue),
-      window_tree_host_(window_tree_host),
-      host_event_dispatcher_(host_event_dispatcher) {
-  event_queue_->OnHostEventQueueCreated(this);
-}
-
-HostEventQueue::~HostEventQueue() {
-  if (event_queue_)
-    event_queue_->OnHostEventQueueDestroyed(this);
-}
-
-base::Optional<ui::EventDispatchDetails> HostEventQueue::DispatchOrQueueEvent(
-    ui::Event* event,
-    bool honor_rewriters) {
-  if (event_queue_ && event_queue_->ShouldQueueEvent(this, *event)) {
-    event_queue_->QueueEvent(this, *event, honor_rewriters);
-    return base::nullopt;
-  }
-  return DispatchEventDontQueue(event, honor_rewriters);
-}
-
-ui::EventDispatchDetails HostEventQueue::DispatchEventDontQueue(
-    ui::Event* event,
-    bool honor_rewriters) {
-  if (honor_rewriters)
-    return host_event_dispatcher_->DispatchEventFromQueue(event);
-  return window_tree_host_->event_sink()->OnEventFromSource(event);
-}
-
-}  // namespace ws
diff --git a/services/ws/host_event_queue.h b/services/ws/host_event_queue.h
deleted file mode 100644
index 98d367e..0000000
--- a/services/ws/host_event_queue.h
+++ /dev/null
@@ -1,74 +0,0 @@
-// Copyright 2018 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.
-
-#ifndef SERVICES_WS_HOST_EVENT_QUEUE_H_
-#define SERVICES_WS_HOST_EVENT_QUEUE_H_
-
-#include "base/component_export.h"
-#include "base/macros.h"
-#include "base/memory/weak_ptr.h"
-#include "base/optional.h"
-
-namespace aura {
-class WindowTreeHost;
-}
-
-namespace ui {
-class Event;
-struct EventDispatchDetails;
-}
-
-namespace ws {
-
-class EventQueue;
-class HostEventDispatcher;
-
-// HostEventQueue is associated with a single WindowTreeHost and used to queue
-// events (if necessary), before the WindowTreeHost does processing.
-// HostEventQueue is created by way of
-// WindowService::RegisterHostEventDispatcher(). The expectation is
-// WindowTreeHost calls to HostEventQueue::DispatchOrQueueEvent() on every
-// event. When necessary, HostEventQueue calls back to HostEventDispatcher to
-// handle the actual dispatch.
-class COMPONENT_EXPORT(WINDOW_SERVICE) HostEventQueue {
- public:
-  HostEventQueue(base::WeakPtr<EventQueue> event_queue,
-                 aura::WindowTreeHost* window_tree_host,
-                 HostEventDispatcher* host_event_dispatcher);
-  ~HostEventQueue();
-
-  // If necessary, queues the event. If the event need not be queued,
-  // HostEventDispatcher::DispatchEventFromQueue() is called synchronously. If
-  // the event was not queued, the return value contains the result of the
-  // event processing.
-  base::Optional<ui::EventDispatchDetails> DispatchOrQueueEvent(
-      ui::Event* event,
-      bool honor_rewriters = true);
-
-  aura::WindowTreeHost* window_tree_host() { return window_tree_host_; }
-
-  HostEventDispatcher* host_event_dispatcher() {
-    return host_event_dispatcher_;
-  }
-
- private:
-  friend class EventQueue;
-
-  // Dispatches an event directly, circumventing any queuing. This is private as
-  // it's only useful internally.
-  ui::EventDispatchDetails DispatchEventDontQueue(ui::Event* event,
-                                                  bool honor_rewriters);
-
-  // Because of shutdown ordering, HostEventQueue may be deleted *after*
-  // EventQueue.
-  base::WeakPtr<EventQueue> event_queue_;
-  aura::WindowTreeHost* window_tree_host_;
-  HostEventDispatcher* host_event_dispatcher_;
-
-  DISALLOW_COPY_AND_ASSIGN(HostEventQueue);
-};
-
-}  // namespace ws
-
-#endif  // SERVICES_WS_HOST_EVENT_QUEUE_H_
diff --git a/services/ws/injected_event_handler.cc b/services/ws/injected_event_handler.cc
index caa047a..7bf38646 100644
--- a/services/ws/injected_event_handler.cc
+++ b/services/ws/injected_event_handler.cc
@@ -5,7 +5,6 @@
 #include "services/ws/injected_event_handler.h"
 
 #include "base/memory/ptr_util.h"
-#include "services/ws/event_queue.h"
 #include "services/ws/window_service.h"
 #include "services/ws/window_service_delegate.h"
 #include "ui/aura/env.h"
@@ -57,16 +56,14 @@
   auto this_ref = weak_factory_.GetWeakPtr();
   pre_target_register_ = std::make_unique<ScopedPreTargetRegister>(
       window_service_->delegate()->GetGlobalEventTarget(), this);
-  auto result = EventQueue::DispatchOrQueueEvent(window_service_,
-                                                 window_tree_host_, event.get(),
-                                                 /* honors_rewriters */ true);
+  auto result = window_tree_host_->SendEventToSink(event.get());
   if (!this_ref)
     return;
   // |pre_target_register_| needs to be a member to ensure it's destroyed
   // if |this| is destroyed.
   pre_target_register_.reset();
 
-  if (result && result->event_discarded) {
+  if (result.event_discarded) {
     DCHECK(!event_id_);
     NotifyCallback();
   }
diff --git a/services/ws/injected_event_handler_unittest.cc b/services/ws/injected_event_handler_unittest.cc
index fd47e41..16d0feb 100644
--- a/services/ws/injected_event_handler_unittest.cc
+++ b/services/ws/injected_event_handler_unittest.cc
@@ -9,11 +9,9 @@
 #include "base/bind.h"
 #include "services/service_manager/public/cpp/connector.h"
 #include "services/service_manager/public/cpp/test/test_connector_factory.h"
-#include "services/ws/host_event_queue.h"
 #include "services/ws/public/cpp/host/gpu_interface_provider.h"
 #include "services/ws/public/mojom/constants.mojom.h"
 #include "services/ws/public/mojom/window_tree.mojom.h"
-#include "services/ws/test_host_event_dispatcher.h"
 #include "services/ws/window_service.h"
 #include "services/ws/window_service_test_setup.h"
 #include "services/ws/window_tree.h"
@@ -83,11 +81,6 @@
       aura::WindowTreeHost::Create(
           ui::PlatformWindowInitProperties{gfx::Rect(20, 30, 100, 50)});
   second_host->InitHost();
-  auto host_event_dispatcher =
-      std::make_unique<TestHostEventDispatcher>(second_host.get());
-  auto host_event_queue = test_setup.service()->RegisterHostEventDispatcher(
-      second_host.get(), host_event_dispatcher.get());
-
   second_host->window()->Show();
 
   // Create a top-level in |second_host|.
diff --git a/services/ws/test_host_event_dispatcher.cc b/services/ws/test_host_event_dispatcher.cc
deleted file mode 100644
index 828896e..0000000
--- a/services/ws/test_host_event_dispatcher.cc
+++ /dev/null
@@ -1,26 +0,0 @@
-// Copyright 2018 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 "services/ws/test_host_event_dispatcher.h"
-
-#include "ui/aura/window_tree_host.h"
-#include "ui/events/event_sink.h"
-#include "ui/events/test/events_test_utils.h"
-
-namespace ws {
-
-TestHostEventDispatcher::TestHostEventDispatcher(
-    aura::WindowTreeHost* window_tree_host)
-    : window_tree_host_(window_tree_host) {
-  DCHECK(window_tree_host_);
-}
-
-TestHostEventDispatcher::~TestHostEventDispatcher() = default;
-
-ui::EventDispatchDetails TestHostEventDispatcher::DispatchEventFromQueue(
-    ui::Event* event) {
-  return ui::EventSourceTestApi(window_tree_host_).SendEventToSink(event);
-}
-
-}  // namespace ws
diff --git a/services/ws/test_host_event_dispatcher.h b/services/ws/test_host_event_dispatcher.h
deleted file mode 100644
index 688defa..0000000
--- a/services/ws/test_host_event_dispatcher.h
+++ /dev/null
@@ -1,34 +0,0 @@
-// Copyright 2018 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.
-
-#ifndef SERVICES_WS_TEST_HOST_EVENT_DISPATCHER_H_
-#define SERVICES_WS_TEST_HOST_EVENT_DISPATCHER_H_
-
-#include "base/component_export.h"
-#include "base/macros.h"
-#include "services/ws/host_event_dispatcher.h"
-
-namespace aura {
-class WindowTreeHost;
-}
-
-namespace ws {
-
-class TestHostEventDispatcher : public HostEventDispatcher {
- public:
-  explicit TestHostEventDispatcher(aura::WindowTreeHost* window_tree_host);
-  ~TestHostEventDispatcher() override;
-
-  // HostEventDispatcher:
-  ui::EventDispatchDetails DispatchEventFromQueue(ui::Event* event) override;
-
- private:
-  aura::WindowTreeHost* window_tree_host_;
-
-  DISALLOW_COPY_AND_ASSIGN(TestHostEventDispatcher);
-};
-
-}  // namespace ws
-
-#endif  // SERVICES_WS_TEST_HOST_EVENT_DISPATCHER_H_
diff --git a/services/ws/test_window_service_delegate.cc b/services/ws/test_window_service_delegate.cc
index 132c575..2b1e394 100644
--- a/services/ws/test_window_service_delegate.cc
+++ b/services/ws/test_window_service_delegate.cc
@@ -6,6 +6,7 @@
 
 #include "ui/aura/mus/property_converter.h"
 #include "ui/aura/window.h"
+#include "ui/display/screen.h"
 
 namespace ws {
 
@@ -75,6 +76,13 @@
   return top_level_parent_->GetRootWindow();
 }
 
+aura::Window* TestWindowServiceDelegate::GetRootWindowForDisplayId(
+    int64_t display_id) {
+  if (display::Screen::GetScreen()->GetAllDisplays().size() > 1)
+    NOTIMPLEMENTED_LOG_ONCE() << "Add test support for multiple displays.";
+  return top_level_parent_->GetRootWindow();
+}
+
 aura::Window* TestWindowServiceDelegate::GetTopmostWindowAtPoint(
     const gfx::Point& location_in_screen,
     const std::set<aura::Window*>& ignore,
diff --git a/services/ws/test_window_service_delegate.h b/services/ws/test_window_service_delegate.h
index 8c7da54..8e1e0bd6 100644
--- a/services/ws/test_window_service_delegate.h
+++ b/services/ws/test_window_service_delegate.h
@@ -68,6 +68,7 @@
                    DragDropCompletedCallback callback) override;
   void CancelDragLoop(aura::Window* window) override;
   ui::EventTarget* GetGlobalEventTarget() override;
+  aura::Window* GetRootWindowForDisplayId(int64_t display_id) override;
   aura::Window* GetTopmostWindowAtPoint(const gfx::Point& location_in_screen,
                                         const std::set<aura::Window*>& ignore,
                                         aura::Window** real_topmost) override;
diff --git a/services/ws/test_ws/test_window_service.cc b/services/ws/test_ws/test_window_service.cc
index 5fb0551..ffe5a19 100644
--- a/services/ws/test_ws/test_window_service.cc
+++ b/services/ws/test_ws/test_window_service.cc
@@ -10,10 +10,7 @@
 #include "base/bind_helpers.h"
 #include "mojo/public/cpp/bindings/map.h"
 #include "services/service_manager/public/cpp/connector.h"
-#include "services/ws/host_event_dispatcher.h"
-#include "services/ws/host_event_queue.h"
 #include "services/ws/public/mojom/constants.mojom.h"
-#include "services/ws/test_host_event_dispatcher.h"
 #include "services/ws/test_ws/test_gpu_interface_provider.h"
 #include "services/ws/window_service.h"
 #include "ui/aura/client/aura_constants.h"
@@ -21,6 +18,7 @@
 #include "ui/aura/mus/property_utils.h"
 #include "ui/aura/window_tracker.h"
 #include "ui/compositor/test/context_factories_for_test.h"
+#include "ui/display/screen.h"
 #include "ui/events/event.h"
 #include "ui/events/event_sink.h"
 #include "ui/gl/test/gl_surface_test_support.h"
@@ -141,6 +139,12 @@
   return aura_test_helper_->root_window();
 }
 
+aura::Window* TestWindowService::GetRootWindowForDisplayId(int64_t display_id) {
+  if (display::Screen::GetScreen()->GetAllDisplays().size() > 1)
+    NOTIMPLEMENTED_LOG_ONCE() << "Add test support for multiple displays.";
+  return aura_test_helper_->root_window();
+}
+
 void TestWindowService::OnStart() {
   CHECK(!started_);
   started_ = true;
@@ -186,10 +190,6 @@
       this, std::move(gpu_interface_provider_),
       aura_test_helper_->focus_client(), /*decrement_client_ids=*/false,
       aura_test_helper_->GetEnv());
-  test_host_event_dispatcher_ =
-      std::make_unique<TestHostEventDispatcher>(aura_test_helper_->host());
-  host_event_queue_ = window_service_->RegisterHostEventDispatcher(
-      aura_test_helper_->host(), test_host_event_dispatcher_.get());
   window_service_->BindServiceRequest(std::move(request));
   pid_receiver->SetPID(base::GetCurrentProcId());
 }
diff --git a/services/ws/test_ws/test_window_service.h b/services/ws/test_ws/test_window_service.h
index 7279ee4..e500031 100644
--- a/services/ws/test_ws/test_window_service.h
+++ b/services/ws/test_ws/test_window_service.h
@@ -34,8 +34,6 @@
 
 namespace ws {
 
-class HostEventQueue;
-class TestHostEventDispatcher;
 class WindowService;
 
 namespace test {
@@ -79,6 +77,7 @@
                    DragDropCompletedCallback callback) override;
   void CancelDragLoop(aura::Window* window) override;
   ui::EventTarget* GetGlobalEventTarget() override;
+  aura::Window* GetRootWindowForDisplayId(int64_t display_id) override;
 
   // service_manager::Service:
   void OnStart() override;
@@ -144,10 +143,6 @@
   // is used in service_unittests where ui features is not used there.
   bool is_in_process_ = false;
 
-  std::unique_ptr<TestHostEventDispatcher> test_host_event_dispatcher_;
-
-  std::unique_ptr<HostEventQueue> host_event_queue_;
-
   std::unique_ptr<VisibilitySynchronizer> visibility_synchronizer_;
 
   DISALLOW_COPY_AND_ASSIGN(TestWindowService);
diff --git a/services/ws/window_service.cc b/services/ws/window_service.cc
index b667a8a47..33f4cef 100644
--- a/services/ws/window_service.cc
+++ b/services/ws/window_service.cc
@@ -14,7 +14,6 @@
 #include "services/ws/embedding.h"
 #include "services/ws/event_injector.h"
 #include "services/ws/event_queue.h"
-#include "services/ws/host_event_queue.h"
 #include "services/ws/proxy_window.h"
 #include "services/ws/public/cpp/host/gpu_interface_provider.h"
 #include "services/ws/public/mojom/window_manager.mojom.h"
@@ -250,13 +249,6 @@
   return proxy_window->GetIdForDebugging();
 }
 
-std::unique_ptr<HostEventQueue> WindowService::RegisterHostEventDispatcher(
-    aura::WindowTreeHost* window_tree_host,
-    HostEventDispatcher* dispatcher) {
-  return event_queue_->RegisterHostEventDispatcher(window_tree_host,
-                                                   dispatcher);
-}
-
 void WindowService::OnStart() {
   test_config_ = base::CommandLine::ForCurrentProcess()->HasSwitch(
       switches::kUseTestConfig);
diff --git a/services/ws/window_service.h b/services/ws/window_service.h
index 212f4bc..e51e55a 100644
--- a/services/ws/window_service.h
+++ b/services/ws/window_service.h
@@ -34,7 +34,6 @@
 namespace aura {
 class Env;
 class Window;
-class WindowTreeHost;
 namespace client {
 class FocusClient;
 }
@@ -61,8 +60,6 @@
 class EventInjector;
 class EventQueue;
 class GpuInterfaceProvider;
-class HostEventDispatcher;
-class HostEventQueue;
 class RemotingEventInjector;
 class ScreenProvider;
 class ProxyWindow;
@@ -173,12 +170,6 @@
   void OnDisplayMetricsChanged(const display::Display& display,
                                uint32_t changed_metrics);
 
-  // Registers the HostEventDispatcher for a WindowTreeHost and returns the
-  // HostEventQueue that |window_tree_host| should use to dispatch events.
-  std::unique_ptr<HostEventQueue> RegisterHostEventDispatcher(
-      aura::WindowTreeHost* window_tree_host,
-      HostEventDispatcher* dispatcher);
-
   // Returns an id useful for debugging. See ProxyWindow::GetIdForDebugging()
   // for details.
   std::string GetIdForDebugging(aura::Window* window);
diff --git a/services/ws/window_service_delegate.h b/services/ws/window_service_delegate.h
index 6938de8..5d59e8c 100644
--- a/services/ws/window_service_delegate.h
+++ b/services/ws/window_service_delegate.h
@@ -121,6 +121,8 @@
   // Returns the EventTarget which can process all of the events on the system.
   virtual ui::EventTarget* GetGlobalEventTarget() = 0;
 
+  virtual aura::Window* GetRootWindowForDisplayId(int64_t display_id) = 0;
+
   // Returns the topmost visible window at the location in screen coordinate,
   // excluding |ignore|. |real_topmost| is updated to the topmost visible window
   // at the location without excluding |ignore|.
diff --git a/services/ws/window_service_test_setup.cc b/services/ws/window_service_test_setup.cc
index da5bdc6c..9f8cb7c 100644
--- a/services/ws/window_service_test_setup.cc
+++ b/services/ws/window_service_test_setup.cc
@@ -7,9 +7,7 @@
 #include "services/ws/embedding.h"
 #include "services/ws/event_queue.h"
 #include "services/ws/event_queue_test_helper.h"
-#include "services/ws/host_event_queue.h"
 #include "services/ws/public/cpp/host/gpu_interface_provider.h"
-#include "services/ws/test_host_event_dispatcher.h"
 #include "services/ws/window_service.h"
 #include "services/ws/window_tree.h"
 #include "services/ws/window_tree_binding.h"
@@ -39,80 +37,55 @@
   DISALLOW_COPY_AND_ASSIGN(TestFocusRules);
 };
 
-// EventTargeterWs sole purpose is to make OnEventFromSource() forward events
-// to the appropriate HostEventQueue. This is normally done by a WindowTreeHost
-// subclass, but because tests create a platform specific WindowTreeHost
-// implementation, that isn't possible.
-class EventTargeterWs : public ui::EventTarget,
-                        public ui::EventTargeter,
-                        public ui::EventSource,
-                        public ui::EventSink {
+// An EventSource that mimics AshWindowTreeHostPlatform's EventQueue usage.
+class EventSourceWithQueue : public ui::EventSource {
  public:
-  EventTargeterWs(WindowServiceTestSetup* test_setup,
-                  HostEventQueue* host_event_queue)
-      : test_setup_(test_setup), host_event_queue_(host_event_queue) {}
-
-  ~EventTargeterWs() 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; }
+  explicit EventSourceWithQueue(WindowServiceTestSetup* test_setup,
+                                aura::Window* root)
+      : test_setup_(test_setup), root_(root) {}
+  ~EventSourceWithQueue() override = default;
 
   // ui::EventSource:
-  ui::EventSink* GetEventSink() override { return this; }
-
-  // ui::EventSink:
-  ui::EventDispatchDetails OnEventFromSource(ui::Event* event) override {
-    host_event_queue_->DispatchOrQueueEvent(event);
-    WindowService* window_service = test_setup_->service();
+  ui::EventSink* GetEventSink() override {
+    return root_->GetHost()->GetEventSink();
+  }
+  ui::EventDispatchDetails DeliverEventToSink(ui::Event* event) override {
+    auto* queue = test_setup_->service()->event_queue();
+    // Queue the event if needed, or deliver it directly to the sink.
+    auto result = queue->DeliverOrQueueEvent(root_->GetHost(), event);
     if (test_setup_->ack_events_immediately() &&
-        EventQueueTestHelper(window_service->event_queue())
-            .HasInFlightEvent()) {
-      EventQueueTestHelper(window_service->event_queue()).AckInFlightEvent();
+        EventQueueTestHelper(queue).HasInFlightEvent()) {
+      EventQueueTestHelper(queue).AckInFlightEvent();
     }
-    return ui::EventDispatchDetails();
+
+    return result.value_or(ui::EventDispatchDetails());
   }
 
  private:
   WindowServiceTestSetup* test_setup_;
-  HostEventQueue* host_event_queue_;
+  aura::Window* root_;
 
-  DISALLOW_COPY_AND_ASSIGN(EventTargeterWs);
+  DISALLOW_COPY_AND_ASSIGN(EventSourceWithQueue);
 };
 
 // EventGeneratorDelegate implementation for mus.
 class EventGeneratorDelegateWs : public aura::test::EventGeneratorDelegateAura {
  public:
-  EventGeneratorDelegateWs(WindowServiceTestSetup* test_setup,
-                           HostEventQueue* host_event_queue)
-      : event_targeter_(test_setup, host_event_queue) {}
+  explicit EventGeneratorDelegateWs(WindowServiceTestSetup* test_setup,
+                                    aura::Window* root)
+      : root_(root), event_source_(test_setup, root) {}
   ~EventGeneratorDelegateWs() override = default;
 
   // EventGeneratorDelegateAura:
   ui::EventTarget* GetTargetAt(const gfx::Point& location) override {
-    return &event_targeter_;
+    return root_;
   }
   ui::EventSource* GetEventSource(ui::EventTarget* target) override {
-    return target == &event_targeter_
-               ? &event_targeter_
-               : EventGeneratorDelegateAura::GetEventSource(target);
+    return target == root_ ? &event_source_
+                           : EventGeneratorDelegateAura::GetEventSource(target);
   }
   gfx::Point CenterOfTarget(const ui::EventTarget* target) const override {
-    if (target != &event_targeter_)
+    if (target != root_)
       return EventGeneratorDelegateAura::CenterOfTarget(target);
     return display::Screen::GetScreen()
         ->GetPrimaryDisplay()
@@ -121,22 +94,23 @@
   }
   void ConvertPointFromTarget(const ui::EventTarget* target,
                               gfx::Point* point) const override {
-    if (target != &event_targeter_)
+    if (target != root_)
       EventGeneratorDelegateAura::ConvertPointFromTarget(target, point);
   }
   void ConvertPointToTarget(const ui::EventTarget* target,
                             gfx::Point* point) const override {
-    if (target != &event_targeter_)
+    if (target != root_)
       EventGeneratorDelegateAura::ConvertPointToTarget(target, point);
   }
   void ConvertPointFromHost(const ui::EventTarget* hosted_target,
                             gfx::Point* point) const override {
-    if (hosted_target != &event_targeter_)
+    if (hosted_target != root_)
       EventGeneratorDelegateAura::ConvertPointFromHost(hosted_target, point);
   }
 
  private:
-  EventTargeterWs event_targeter_;
+  aura::Window* root_;
+  EventSourceWithQueue event_source_;
 
   DISALLOW_COPY_AND_ASSIGN(EventGeneratorDelegateWs);
 };
@@ -148,10 +122,7 @@
     aura::Window* window) {
   DCHECK(root_window);
   DCHECK(root_window->GetHost());
-  return std::make_unique<EventGeneratorDelegateWs>(
-      test_setup,
-      test_setup->service()->event_queue()->GetHostEventQueueForDisplay(
-          root_window->GetHost()->GetDisplayId()));
+  return std::make_unique<EventGeneratorDelegateWs>(test_setup, root_window);
 }
 
 }  // namespace
@@ -175,10 +146,6 @@
   aura::client::SetFocusClient(root(), focus_controller());
   wm::SetActivationClient(root(), focus_controller());
   delegate_.set_top_level_parent(aura_test_helper_.root_window());
-  host_event_dispatcher_ =
-      std::make_unique<TestHostEventDispatcher>(aura_test_helper_.host());
-  host_event_queue_ = service_->RegisterHostEventDispatcher(
-      aura_test_helper_.host(), host_event_dispatcher_.get());
 
   window_tree_ = service_->CreateWindowTree(&window_tree_client_);
   window_tree_->InitFromFactory();
diff --git a/services/ws/window_service_test_setup.h b/services/ws/window_service_test_setup.h
index d2ba022..a20fbe3 100644
--- a/services/ws/window_service_test_setup.h
+++ b/services/ws/window_service_test_setup.h
@@ -22,8 +22,6 @@
 
 namespace ws {
 
-class HostEventQueue;
-class TestHostEventDispatcher;
 class WindowService;
 class WindowTree;
 class WindowTreeTestHelper;
@@ -64,8 +62,6 @@
 
   aura::test::AuraTestHelper* aura_test_helper() { return &aura_test_helper_; }
 
-  HostEventQueue* host_event_queue() { return host_event_queue_.get(); }
-
  private:
   base::test::ScopedTaskEnvironment task_environment_{
       base::test::ScopedTaskEnvironment::MainThreadType::UI};
@@ -74,8 +70,6 @@
   std::unique_ptr<wm::ScopedCaptureClient> scoped_capture_client_;
   TestWindowServiceDelegate delegate_;
   std::unique_ptr<WindowService> service_;
-  std::unique_ptr<TestHostEventDispatcher> host_event_dispatcher_;
-  std::unique_ptr<HostEventQueue> host_event_queue_;
   TestWindowTreeClient window_tree_client_;
   std::unique_ptr<WindowTree> window_tree_;
   std::unique_ptr<WindowTreeTestHelper> window_tree_test_helper_;
diff --git a/testing/buildbot/filters/chromeos.single_process_mash.interactive_ui_tests.filter b/testing/buildbot/filters/chromeos.single_process_mash.interactive_ui_tests.filter
index 79f23c6c..197df33 100644
--- a/testing/buildbot/filters/chromeos.single_process_mash.interactive_ui_tests.filter
+++ b/testing/buildbot/filters/chromeos.single_process_mash.interactive_ui_tests.filter
@@ -8,9 +8,5 @@
 # ChromeOS.
 -BrowserKeyEventsTest.AccessKeys
 
-# crbug.com/913549
--StickyKeysBrowserTest.OpenTrayMenu
--StickyKeysBrowserTest.SearchLeftOmnibox
-
 # This test is flaky. https://crbug.com/897879
 -ExtensionApiTest.DisplayModeWindowIsInFullscreen
diff --git a/ui/aura/window_tree_host.cc b/ui/aura/window_tree_host.cc
index 89ed4c6..8a18313 100644
--- a/ui/aura/window_tree_host.cc
+++ b/ui/aura/window_tree_host.cc
@@ -139,6 +139,10 @@
   return dispatcher_.get();
 }
 
+base::WeakPtr<WindowTreeHost> WindowTreeHost::GetWeakPtr() {
+  return weak_factory_.GetWeakPtr();
+}
+
 gfx::Transform WindowTreeHost::GetRootTransform() const {
   gfx::Transform transform;
   transform.Scale(device_scale_factor_, device_scale_factor_);
@@ -274,6 +278,10 @@
   return dispatch_details;
 }
 
+ui::EventSink* WindowTreeHost::GetEventSink() {
+  return dispatcher_.get();
+}
+
 int64_t WindowTreeHost::GetDisplayId() {
   return display::Screen::GetScreen()->GetDisplayNearestWindow(window()).id();
 }
@@ -495,10 +503,6 @@
     capture_window->ReleaseCapture();
 }
 
-ui::EventSink* WindowTreeHost::GetEventSink() {
-  return dispatcher_.get();
-}
-
 void WindowTreeHost::OnDisplayMetricsChanged(const display::Display& display,
                                              uint32_t metrics) {
   if (metrics & DisplayObserver::DISPLAY_METRIC_COLOR_SPACE) {
diff --git a/ui/aura/window_tree_host.h b/ui/aura/window_tree_host.h
index e89644f9..6db3f3b13 100644
--- a/ui/aura/window_tree_host.h
+++ b/ui/aura/window_tree_host.h
@@ -85,6 +85,7 @@
   Window* window() { return window_; }
   const Window* window() const { return window_; }
 
+  // TODO(msw): Remove this, callers should use GetEventSink().
   ui::EventSink* event_sink();
 
   WindowEventDispatcher* dispatcher() {
@@ -95,6 +96,8 @@
 
   ui::Compositor* compositor() { return compositor_.get(); }
 
+  base::WeakPtr<WindowTreeHost> GetWeakPtr();
+
   // Gets/Sets the root window's transform.
   virtual gfx::Transform GetRootTransform() const;
   virtual void SetRootTransform(const gfx::Transform& transform);
@@ -177,6 +180,9 @@
       ui::KeyEvent* event,
       base::OnceCallback<void(bool)> ack_callback) final;
 
+  // Overridden from ui::EventSource:
+  ui::EventSink* GetEventSink() override;
+
   // Returns the id of the display. Default implementation queries Screen.
   virtual int64_t GetDisplayId();
 
@@ -298,9 +304,6 @@
   // Hides the WindowTreeHost.
   virtual void HideImpl() = 0;
 
-  // Overridden from ui::EventSource:
-  ui::EventSink* GetEventSink() override;
-
   // display::DisplayObserver implementation.
   void OnDisplayMetricsChanged(const display::Display& display,
                                uint32_t metrics) override;
diff --git a/ui/events/event_source.cc b/ui/events/event_source.cc
index 323e8b4..85a6f40 100644
--- a/ui/events/event_source.cc
+++ b/ui/events/event_source.cc
@@ -43,6 +43,12 @@
   return SendEventToSinkFromRewriter(event, nullptr);
 }
 
+EventDispatchDetails EventSource::DeliverEventToSink(Event* event) {
+  EventSink* sink = GetEventSink();
+  CHECK(sink);
+  return sink->OnEventFromSource(event);
+}
+
 EventDispatchDetails EventSource::SendEventToSinkFromRewriter(
     Event* event,
     const EventRewriter* rewriter) {
@@ -102,10 +108,4 @@
   return EventDispatchDetails();
 }
 
-EventDispatchDetails EventSource::DeliverEventToSink(Event* event) {
-  EventSink* sink = GetEventSink();
-  CHECK(sink);
-  return sink->OnEventFromSource(event);
-}
-
 }  // namespace ui
diff --git a/ui/events/event_source.h b/ui/events/event_source.h
index d5b9b1c..ad84e60 100644
--- a/ui/events/event_source.h
+++ b/ui/events/event_source.h
@@ -33,10 +33,14 @@
   void AddEventRewriter(EventRewriter* rewriter);
   void RemoveEventRewriter(EventRewriter* rewriter);
 
- protected:
   // Sends the event through all rewriters and onto the source's EventSink.
   EventDispatchDetails SendEventToSink(Event* event);
 
+  // Send the event to the sink after rewriting; subclass overrides may queue
+  // events before delivery, i.e. for the WindowService.
+  virtual EventDispatchDetails DeliverEventToSink(Event* event);
+
+ protected:
   // Sends the event through the rewriters and onto the source's EventSink.
   // If |rewriter| is valid, |event| is only sent to the subsequent rewriters.
   // This is used for asynchronous reposting of events processed by |rewriter|.
@@ -48,8 +52,6 @@
   friend class EventRewriter;
   friend class EventSourceTestApi;
 
-  EventDispatchDetails DeliverEventToSink(Event* event);
-
   typedef std::vector<EventRewriter*> EventRewriterList;
   EventRewriterList rewriter_list_;
 
diff --git a/ui/wm/test/wm_test_helper.cc b/ui/wm/test/wm_test_helper.cc
index 24996bd..b62bdb6 100644
--- a/ui/wm/test/wm_test_helper.cc
+++ b/ui/wm/test/wm_test_helper.cc
@@ -22,6 +22,7 @@
 #include "ui/aura/mus/window_tree_host_mus_init_params.h"
 #include "ui/aura/test/mus/window_tree_client_test_api.h"
 #include "ui/aura/test/test_focus_client.h"
+#include "ui/aura/test/test_screen.h"
 #include "ui/aura/window.h"
 #include "ui/base/ui_base_features.h"
 #include "ui/platform_window/platform_window_init_properties.h"
@@ -63,6 +64,9 @@
     run_loop.Run();
   }
   host_->window()->RemovePreTargetHandler(root_window_event_filter_.get());
+
+  if (display::Screen::GetScreen() == test_screen_.get())
+    display::Screen::SetScreenInstance(nullptr);
 }
 
 aura::Window* WMTestHelper::GetDefaultParent(aura::Window* window,
@@ -72,6 +76,11 @@
 
 void WMTestHelper::InitLocalHost(const gfx::Size& default_window_size) {
   wm_state_ = std::make_unique<WMState>();
+
+  // Install a screen, like TestWindowService's AuraTestHelper for InitMusHost.
+  test_screen_ = base::WrapUnique(aura::TestScreen::Create(gfx::Size()));
+  display::Screen::SetScreenInstance(test_screen_.get());
+
   host_ = aura::WindowTreeHost::Create(
       ui::PlatformWindowInitProperties{gfx::Rect(default_window_size)});
   host_->InitHost();
diff --git a/ui/wm/test/wm_test_helper.h b/ui/wm/test/wm_test_helper.h
index 390953d..3ce5ac0 100644
--- a/ui/wm/test/wm_test_helper.h
+++ b/ui/wm/test/wm_test_helper.h
@@ -17,6 +17,7 @@
 
 namespace aura {
 class PropertyConverter;
+class TestScreen;
 class Window;
 class WindowTreeClient;
 class WindowTreeHost;
@@ -86,6 +87,7 @@
                          int64_t display_id_for_new_windows) override;
 
   std::unique_ptr<WMState> wm_state_;
+  std::unique_ptr<aura::TestScreen> test_screen_;
   std::unique_ptr<ws::InputDeviceClient> input_device_client_;
   std::unique_ptr<aura::PropertyConverter> property_converter_;
   std::unique_ptr<aura::WindowTreeClient> window_tree_client_;