Commit 0c0f3795 authored by Katie Dektar's avatar Katie Dektar Committed by Commit Bot

Use an EventRewriter to ensure Select-to-Speak always gets key events.

The EventRewriter is able to get events before they are even passed to
the system menus, which allows Select-to-Speak to have a chance to
process key events before the menus can stop key event propagation.

This change basically refactors select_to_speak_event_handler* to
select_to_speak_event_rewriter*. It neither adds nor removes tests.

Bug: 791809,793950
Change-Id: Ied4c937e0ff1bcb2c56121f048d185290f4a168e
Reviewed-on: https://chromium-review.googlesource.com/823280
Commit-Queue: Katie D <katie@chromium.org>
Reviewed-by: default avatarJames Cook <jamescook@chromium.org>
Reviewed-by: default avatarDominic Mazzoni <dmazzoni@chromium.org>
Cr-Commit-Position: refs/heads/master@{#524748}
parent 40f1f1b0
...@@ -114,10 +114,10 @@ source_set("chromeos") { ...@@ -114,10 +114,10 @@ source_set("chromeos") {
"//components/session_manager/core", "//components/session_manager/core",
"//components/signin/core/browser", "//components/signin/core/browser",
"//components/ssl_config", "//components/ssl_config",
"//components/startup_metric_utils/browser:lib",
"//components/storage_monitor", "//components/storage_monitor",
"//components/sync_preferences", "//components/sync_preferences",
"//components/sync_wifi", "//components/sync_wifi",
"//components/startup_metric_utils/browser:lib",
"//components/toolbar", "//components/toolbar",
"//components/tracing:startup_tracing", "//components/tracing:startup_tracing",
"//components/ukm/content", "//components/ukm/content",
...@@ -241,8 +241,8 @@ source_set("chromeos") { ...@@ -241,8 +241,8 @@ source_set("chromeos") {
"accessibility/event_handler_common.h", "accessibility/event_handler_common.h",
"accessibility/magnification_manager.cc", "accessibility/magnification_manager.cc",
"accessibility/magnification_manager.h", "accessibility/magnification_manager.h",
"accessibility/select_to_speak_event_handler.cc", "accessibility/select_to_speak_event_rewriter.cc",
"accessibility/select_to_speak_event_handler.h", "accessibility/select_to_speak_event_rewriter.h",
"accessibility/spoken_feedback_event_rewriter.cc", "accessibility/spoken_feedback_event_rewriter.cc",
"accessibility/spoken_feedback_event_rewriter.h", "accessibility/spoken_feedback_event_rewriter.h",
"accessibility/switch_access_event_handler.cc", "accessibility/switch_access_event_handler.cc",
...@@ -1714,7 +1714,7 @@ source_set("unit_tests") { ...@@ -1714,7 +1714,7 @@ source_set("unit_tests") {
"../policy/default_geolocation_policy_handler_unittest.cc", "../policy/default_geolocation_policy_handler_unittest.cc",
"../ui/browser_finder_chromeos_unittest.cc", "../ui/browser_finder_chromeos_unittest.cc",
"accessibility/magnification_manager_unittest.cc", "accessibility/magnification_manager_unittest.cc",
"accessibility/select_to_speak_event_handler_unittest.cc", "accessibility/select_to_speak_event_rewriter_unittest.cc",
"accessibility/spoken_feedback_event_rewriter_unittest.cc", "accessibility/spoken_feedback_event_rewriter_unittest.cc",
"arc/accessibility/arc_accessibility_helper_bridge_unittest.cc", "arc/accessibility/arc_accessibility_helper_bridge_unittest.cc",
"arc/arc_play_store_enabled_preference_handler_unittest.cc", "arc/arc_play_store_enabled_preference_handler_unittest.cc",
......
...@@ -42,7 +42,6 @@ ...@@ -42,7 +42,6 @@
#include "chrome/browser/chromeos/accessibility/accessibility_extension_loader.h" #include "chrome/browser/chromeos/accessibility/accessibility_extension_loader.h"
#include "chrome/browser/chromeos/accessibility/accessibility_highlight_manager.h" #include "chrome/browser/chromeos/accessibility/accessibility_highlight_manager.h"
#include "chrome/browser/chromeos/accessibility/magnification_manager.h" #include "chrome/browser/chromeos/accessibility/magnification_manager.h"
#include "chrome/browser/chromeos/accessibility/select_to_speak_event_handler.h"
#include "chrome/browser/chromeos/accessibility/switch_access_event_handler.h" #include "chrome/browser/chromeos/accessibility/switch_access_event_handler.h"
#include "chrome/browser/chromeos/app_mode/kiosk_app_manager.h" #include "chrome/browser/chromeos/app_mode/kiosk_app_manager.h"
#include "chrome/browser/chromeos/ash_config.h" #include "chrome/browser/chromeos/ash_config.h"
...@@ -969,14 +968,10 @@ void AccessibilityManager::UpdateSelectToSpeakFromPref() { ...@@ -969,14 +968,10 @@ void AccessibilityManager::UpdateSelectToSpeakFromPref() {
return; return;
select_to_speak_enabled_ = enabled; select_to_speak_enabled_ = enabled;
if (enabled) { if (enabled)
select_to_speak_loader_->Load(profile_, base::Closure() /* done_cb */); select_to_speak_loader_->Load(profile_, base::Closure() /* done_cb */);
select_to_speak_event_handler_.reset( else
new chromeos::SelectToSpeakEventHandler());
} else {
select_to_speak_loader_->Unload(); select_to_speak_loader_->Unload();
select_to_speak_event_handler_.reset(nullptr);
}
} }
void AccessibilityManager::SetSwitchAccessEnabled(bool enabled) { void AccessibilityManager::SetSwitchAccessEnabled(bool enabled) {
......
...@@ -42,7 +42,6 @@ namespace chromeos { ...@@ -42,7 +42,6 @@ namespace chromeos {
class AccessibilityExtensionLoader; class AccessibilityExtensionLoader;
class AccessibilityHighlightManager; class AccessibilityHighlightManager;
class ScopedKeyboardStateSetter; class ScopedKeyboardStateSetter;
class SelectToSpeakEventHandler;
class SwitchAccessEventHandler; class SwitchAccessEventHandler;
enum AccessibilityNotificationType { enum AccessibilityNotificationType {
...@@ -439,9 +438,6 @@ class AccessibilityManager ...@@ -439,9 +438,6 @@ class AccessibilityManager
std::unique_ptr<AccessibilityExtensionLoader> select_to_speak_loader_; std::unique_ptr<AccessibilityExtensionLoader> select_to_speak_loader_;
std::unique_ptr<chromeos::SelectToSpeakEventHandler>
select_to_speak_event_handler_;
std::unique_ptr<AccessibilityExtensionLoader> switch_access_loader_; std::unique_ptr<AccessibilityExtensionLoader> switch_access_loader_;
std::unique_ptr<chromeos::SwitchAccessEventHandler> std::unique_ptr<chromeos::SwitchAccessEventHandler>
......
// Copyright 2016 The Chromium Authors. All rights reserved. // Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
#include "chrome/browser/chromeos/accessibility/select_to_speak_event_handler.h" #include "chrome/browser/chromeos/accessibility/select_to_speak_event_rewriter.h"
#include <memory>
#include <string>
#include <utility>
#include "ash/root_window_controller.h"
#include "ash/shell.h" #include "ash/shell.h"
#include "base/logging.h" #include "chrome/browser/chromeos/accessibility/accessibility_manager.h"
#include "chrome/browser/chromeos/accessibility/event_handler_common.h" #include "chrome/browser/chromeos/accessibility/event_handler_common.h"
#include "chrome/common/extensions/extension_constants.h" #include "chrome/common/extensions/extension_constants.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/render_view_host.h" #include "content/public/browser/render_view_host.h"
#include "content/public/browser/render_widget_host.h" #include "content/public/browser/render_widget_host.h"
#include "content/public/browser/web_contents.h"
#include "extensions/browser/event_router.h"
#include "extensions/browser/extension_host.h"
#include "third_party/WebKit/public/platform/WebMouseEvent.h" #include "third_party/WebKit/public/platform/WebMouseEvent.h"
#include "ui/aura/client/screen_position_client.h" #include "ui/aura/client/screen_position_client.h"
#include "ui/aura/window.h" #include "ui/aura/window.h"
#include "ui/aura/window_tree_host.h"
#include "ui/content_accelerators/accelerator_util.h"
#include "ui/display/display.h" #include "ui/display/display.h"
#include "ui/events/blink/web_input_event.h" #include "ui/events/blink/web_input_event.h"
#include "ui/events/event.h" #include "ui/events/event.h"
#include "ui/views/view.h" #include "ui/events/event_sink.h"
#include "ui/views/widget/widget.h"
namespace chromeos {
namespace { namespace {
...@@ -38,22 +44,26 @@ gfx::PointF GetScreenLocationFromEvent(const ui::LocatedEvent& event) { ...@@ -38,22 +44,26 @@ gfx::PointF GetScreenLocationFromEvent(const ui::LocatedEvent& event) {
} }
} // namespace } // namespace
SelectToSpeakEventHandler::SelectToSpeakEventHandler() { SelectToSpeakEventRewriter::SelectToSpeakEventRewriter(
if (ash::Shell::HasInstance()) aura::Window* root_window)
ash::Shell::Get()->GetPrimaryRootWindow()->AddPreTargetHandler(this); : root_window_(root_window) {
DCHECK(root_window_);
} }
SelectToSpeakEventHandler::~SelectToSpeakEventHandler() { SelectToSpeakEventRewriter::~SelectToSpeakEventRewriter() = default;
if (ash::Shell::HasInstance())
ash::Shell::Get()->GetPrimaryRootWindow()->RemovePreTargetHandler(this);
}
void SelectToSpeakEventHandler::CaptureForwardedEventsForTesting( void SelectToSpeakEventRewriter::CaptureForwardedEventsForTesting(
SelectToSpeakForwardedEventDelegateForTesting* delegate) { SelectToSpeakEventDelegateForTesting* delegate) {
event_delegate_for_testing_ = delegate; event_delegate_for_testing_ = delegate;
} }
void SelectToSpeakEventHandler::OnKeyEvent(ui::KeyEvent* event) { bool SelectToSpeakEventRewriter::IsSelectToSpeakEnabled() {
if (event_delegate_for_testing_)
return true;
return chromeos::AccessibilityManager::Get()->IsSelectToSpeakEnabled();
}
bool SelectToSpeakEventRewriter::OnKeyEvent(const ui::KeyEvent* event) {
DCHECK(event); DCHECK(event);
// We can only call TtsController on the UI thread, make sure we // We can only call TtsController on the UI thread, make sure we
...@@ -86,19 +96,18 @@ void SelectToSpeakEventHandler::OnKeyEvent(ui::KeyEvent* event) { ...@@ -86,19 +96,18 @@ void SelectToSpeakEventHandler::OnKeyEvent(ui::KeyEvent* event) {
} }
// Forward the key to the extension. // Forward the key to the extension.
extensions::ExtensionHost* host = extensions::ExtensionHost* host = chromeos::GetAccessibilityExtensionHost(
GetAccessibilityExtensionHost(extension_misc::kSelectToSpeakExtensionId); extension_misc::kSelectToSpeakExtensionId);
if (host) if (host)
ForwardKeyToExtension(*event, host); chromeos::ForwardKeyToExtension(*event, host);
if (cancel_event) return cancel_event;
CancelEvent(event);
} }
void SelectToSpeakEventHandler::OnMouseEvent(ui::MouseEvent* event) { bool SelectToSpeakEventRewriter::OnMouseEvent(const ui::MouseEvent* event) {
DCHECK(event); DCHECK(event);
if (state_ == INACTIVE) if (state_ == INACTIVE)
return; return false;
if ((state_ == SEARCH_DOWN || state_ == MOUSE_RELEASED) && if ((state_ == SEARCH_DOWN || state_ == MOUSE_RELEASED) &&
event->type() == ui::ET_MOUSE_PRESSED) { event->type() == ui::ET_MOUSE_PRESSED) {
...@@ -107,45 +116,81 @@ void SelectToSpeakEventHandler::OnMouseEvent(ui::MouseEvent* event) { ...@@ -107,45 +116,81 @@ void SelectToSpeakEventHandler::OnMouseEvent(ui::MouseEvent* event) {
if (state_ == WAIT_FOR_MOUSE_RELEASE && if (state_ == WAIT_FOR_MOUSE_RELEASE &&
event->type() == ui::ET_MOUSE_RELEASED) { event->type() == ui::ET_MOUSE_RELEASED) {
CancelEvent(event);
state_ = INACTIVE; state_ = INACTIVE;
return; return false;
} }
if (state_ != CAPTURING) if (state_ != CAPTURING)
return; return false;
if (event->type() == ui::ET_MOUSE_RELEASED) if (event->type() == ui::ET_MOUSE_RELEASED)
state_ = MOUSE_RELEASED; state_ = MOUSE_RELEASED;
ui::MouseEvent mutable_event(*event);
ConvertMouseEventToDIPs(&mutable_event);
// If we're in the capturing state, forward the mouse event to // If we're in the capturing state, forward the mouse event to
// select-to-speak. // select-to-speak.
if (event_delegate_for_testing_) { if (event_delegate_for_testing_) {
event_delegate_for_testing_->OnForwardEventToSelectToSpeakExtension(*event); event_delegate_for_testing_->OnForwardEventToSelectToSpeakExtension(
mutable_event);
} else { } else {
extensions::ExtensionHost* host = GetAccessibilityExtensionHost( extensions::ExtensionHost* host = chromeos::GetAccessibilityExtensionHost(
extension_misc::kSelectToSpeakExtensionId); extension_misc::kSelectToSpeakExtensionId);
if (!host) if (!host)
return; return false;
content::RenderViewHost* rvh = host->render_view_host(); content::RenderViewHost* rvh = host->render_view_host();
if (!rvh) if (!rvh)
return; return false;
const blink::WebMouseEvent web_event = const blink::WebMouseEvent web_event = ui::MakeWebMouseEvent(
ui::MakeWebMouseEvent(*event, base::Bind(&GetScreenLocationFromEvent)); mutable_event, base::Bind(&GetScreenLocationFromEvent));
rvh->GetWidget()->ForwardMouseEvent(web_event); rvh->GetWidget()->ForwardMouseEvent(web_event);
} }
CancelEvent(event); return true;
} }
void SelectToSpeakEventHandler::CancelEvent(ui::Event* event) { void SelectToSpeakEventRewriter::ConvertMouseEventToDIPs(
DCHECK(event); ui::MouseEvent* mouse_event) {
if (event->cancelable()) { // The event is in Pixels, and needs to be scaled to DIPs.
event->SetHandled(); gfx::Point location = mouse_event->location();
event->StopPropagation(); gfx::Point root_location = mouse_event->root_location();
root_window_->GetHost()->ConvertPixelsToDIP(&location);
root_window_->GetHost()->ConvertPixelsToDIP(&root_location);
mouse_event->set_location(location);
mouse_event->set_root_location(root_location);
}
ui::EventRewriteStatus SelectToSpeakEventRewriter::RewriteEvent(
const ui::Event& event,
std::unique_ptr<ui::Event>* new_event) {
if (!IsSelectToSpeakEnabled())
return ui::EVENT_REWRITE_CONTINUE;
if (event.type() == ui::ET_KEY_PRESSED ||
event.type() == ui::ET_KEY_RELEASED) {
const ui::KeyEvent key_event = static_cast<const ui::KeyEvent&>(event);
if (OnKeyEvent(&key_event))
return ui::EVENT_REWRITE_DISCARD;
}
if (event.type() == ui::ET_MOUSE_PRESSED ||
event.type() == ui::ET_MOUSE_DRAGGED ||
event.type() == ui::ET_MOUSE_RELEASED ||
event.type() == ui::ET_MOUSE_MOVED) {
const ui::MouseEvent mouse_event =
static_cast<const ui::MouseEvent&>(event);
if (OnMouseEvent(&mouse_event))
return ui::EVENT_REWRITE_DISCARD;
} }
return ui::EVENT_REWRITE_CONTINUE;
} }
} // namespace chromeos ui::EventRewriteStatus SelectToSpeakEventRewriter::NextDispatchEvent(
const ui::Event& last_event,
std::unique_ptr<ui::Event>* new_event) {
return ui::EVENT_REWRITE_CONTINUE;
}
// Copyright 2016 The Chromium Authors. All rights reserved. // Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
#ifndef CHROME_BROWSER_CHROMEOS_ACCESSIBILITY_SELECT_TO_SPEAK_EVENT_HANDLER_H_ #ifndef CHROME_BROWSER_CHROMEOS_ACCESSIBILITY_SELECT_TO_SPEAK_EVENT_REWRITER_H_
#define CHROME_BROWSER_CHROMEOS_ACCESSIBILITY_SELECT_TO_SPEAK_EVENT_HANDLER_H_ #define CHROME_BROWSER_CHROMEOS_ACCESSIBILITY_SELECT_TO_SPEAK_EVENT_REWRITER_H_
#include <set> #include <memory>
#include "base/macros.h" #include "base/macros.h"
#include "ui/events/event_handler.h" #include "ui/aura/window.h"
#include "ui/events/keycodes/keyboard_codes.h" #include "ui/events/event_rewriter.h"
namespace chromeos { namespace ui {
class KeyEvent;
class MouseEvent;
} // namespace ui
class SelectToSpeakForwardedEventDelegateForTesting { class SelectToSpeakEventDelegateForTesting {
public: public:
virtual ~SelectToSpeakEventDelegateForTesting() = default;
virtual void OnForwardEventToSelectToSpeakExtension( virtual void OnForwardEventToSelectToSpeakExtension(
const ui::MouseEvent& event) = 0; const ui::MouseEvent& event) = 0;
}; };
// Intercepts mouse events while the Search key is held down, and sends class SelectToSpeakEventRewriter : public ui::EventRewriter {
// accessibility events to the Select-to-speak extension instead.
class SelectToSpeakEventHandler : public ui::EventHandler {
public: public:
SelectToSpeakEventHandler(); explicit SelectToSpeakEventRewriter(aura::Window* root_window);
~SelectToSpeakEventHandler() override; ~SelectToSpeakEventRewriter() override;
// For testing, call the provided callback with any events that would have
// been forwarded to the Select-to-speak extension instead.
void CaptureForwardedEventsForTesting( void CaptureForwardedEventsForTesting(
SelectToSpeakForwardedEventDelegateForTesting* delegate); SelectToSpeakEventDelegateForTesting* delegate);
private: private:
// EventHandler: // Returns true if Select to Speak is enabled.
void OnKeyEvent(ui::KeyEvent* event) override; bool IsSelectToSpeakEnabled();
void OnMouseEvent(ui::MouseEvent* event) override;
// Returns true if the event was consumed and should be canceled.
bool OnKeyEvent(const ui::KeyEvent* event);
// Returns true if the event was consumed and should be canceled.
bool OnMouseEvent(const ui::MouseEvent* event);
void CancelEvent(ui::Event* event); // Converts an event in pixels to the same event in DIPs.
void ConvertMouseEventToDIPs(ui::MouseEvent* mouse_event);
// EventRewriter:
ui::EventRewriteStatus RewriteEvent(
const ui::Event& event,
std::unique_ptr<ui::Event>* new_event) override;
ui::EventRewriteStatus NextDispatchEvent(
const ui::Event& last_event,
std::unique_ptr<ui::Event>* new_event) override;
enum State { enum State {
// Neither the Search key nor the mouse button are down. // Neither the Search key nor the mouse button are down.
...@@ -64,13 +79,11 @@ class SelectToSpeakEventHandler : public ui::EventHandler { ...@@ -64,13 +79,11 @@ class SelectToSpeakEventHandler : public ui::EventHandler {
}; };
State state_ = INACTIVE; State state_ = INACTIVE;
aura::Window* root_window_;
SelectToSpeakForwardedEventDelegateForTesting* event_delegate_for_testing_ = SelectToSpeakEventDelegateForTesting* event_delegate_for_testing_ = nullptr;
nullptr;
DISALLOW_COPY_AND_ASSIGN(SelectToSpeakEventHandler); DISALLOW_COPY_AND_ASSIGN(SelectToSpeakEventRewriter);
}; };
} // namespace chromeos #endif // CHROME_BROWSER_CHROMEOS_ACCESSIBILITY_SELECT_TO_SPEAK_EVENT_REWRITER_H_
#endif // CHROME_BROWSER_CHROMEOS_ACCESSIBILITY_SELECT_TO_SPEAK_EVENT_HANDLER_H_
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
#include "ash/public/cpp/shelf_model.h" #include "ash/public/cpp/shelf_model.h"
#include "ash/public/interfaces/constants.mojom.h" #include "ash/public/interfaces/constants.mojom.h"
#include "ash/public/interfaces/process_creation_time_recorder.mojom.h" #include "ash/public/interfaces/process_creation_time_recorder.mojom.h"
#include "ash/root_window_controller.h"
#include "ash/shell.h" #include "ash/shell.h"
#include "ash/sticky_keys/sticky_keys_controller.h" #include "ash/sticky_keys/sticky_keys_controller.h"
#include "base/bind.h" #include "base/bind.h"
...@@ -39,6 +40,7 @@ ...@@ -39,6 +40,7 @@
#include "chrome/browser/chrome_notification_types.h" #include "chrome/browser/chrome_notification_types.h"
#include "chrome/browser/chromeos/accessibility/accessibility_manager.h" #include "chrome/browser/chromeos/accessibility/accessibility_manager.h"
#include "chrome/browser/chromeos/accessibility/magnification_manager.h" #include "chrome/browser/chromeos/accessibility/magnification_manager.h"
#include "chrome/browser/chromeos/accessibility/select_to_speak_event_rewriter.h"
#include "chrome/browser/chromeos/accessibility/spoken_feedback_event_rewriter.h" #include "chrome/browser/chromeos/accessibility/spoken_feedback_event_rewriter.h"
#include "chrome/browser/chromeos/app_mode/arc/arc_kiosk_app_manager.h" #include "chrome/browser/chromeos/app_mode/arc/arc_kiosk_app_manager.h"
#include "chrome/browser/chromeos/app_mode/kiosk_app_launch_error.h" #include "chrome/browser/chromeos/app_mode/kiosk_app_launch_error.h"
...@@ -1093,6 +1095,11 @@ void ChromeBrowserMainPartsChromeos::PostBrowserStart() { ...@@ -1093,6 +1095,11 @@ void ChromeBrowserMainPartsChromeos::PostBrowserStart() {
std::unique_ptr<ui::EventRewriter>(new KeyboardDrivenEventRewriter())); std::unique_ptr<ui::EventRewriter>(new KeyboardDrivenEventRewriter()));
keyboard_event_rewriters_->AddEventRewriter( keyboard_event_rewriters_->AddEventRewriter(
std::unique_ptr<ui::EventRewriter>(new SpokenFeedbackEventRewriter())); std::unique_ptr<ui::EventRewriter>(new SpokenFeedbackEventRewriter()));
keyboard_event_rewriters_->AddEventRewriter(
std::unique_ptr<ui::EventRewriter>(new SelectToSpeakEventRewriter(
ash::Shell::Get()
->GetPrimaryRootWindowController()
->GetRootWindow())));
event_rewriter_delegate_ = base::MakeUnique<EventRewriterDelegateImpl>(); event_rewriter_delegate_ = base::MakeUnique<EventRewriterDelegateImpl>();
keyboard_event_rewriters_->AddEventRewriter( keyboard_event_rewriters_->AddEventRewriter(
base::MakeUnique<ui::EventRewriterChromeOS>( base::MakeUnique<ui::EventRewriterChromeOS>(
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment