summaryrefslogtreecommitdiffstats
path: root/ash/accelerators
diff options
context:
space:
mode:
authoroshima@chromium.org <oshima@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-02-15 03:21:06 +0000
committeroshima@chromium.org <oshima@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-02-15 03:21:06 +0000
commite4ea52364663acf64dc3a197660b78b38761a3fc (patch)
tree7ed815df5517e9c978359777cca0e860950af5ae /ash/accelerators
parent726127fdb3582f187eda5595fab13eb49de11fb2 (diff)
downloadchromium_src-e4ea52364663acf64dc3a197660b78b38761a3fc.zip
chromium_src-e4ea52364663acf64dc3a197660b78b38761a3fc.tar.gz
chromium_src-e4ea52364663acf64dc3a197660b78b38761a3fc.tar.bz2
Long press menu (shift+f6) to toggle spoken feedback.
Factor out KeyHoldDetector. BUG=343277 TEST=SpokenFeedbackTogglerTest Review URL: https://codereview.chromium.org/164823005 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@251490 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'ash/accelerators')
-rw-r--r--ash/accelerators/key_hold_detector.cc98
-rw-r--r--ash/accelerators/key_hold_detector.h71
-rw-r--r--ash/accelerators/magnifier_key_scroller.cc81
-rw-r--r--ash/accelerators/magnifier_key_scroller.h55
-rw-r--r--ash/accelerators/magnifier_key_scroller_unittest.cc111
-rw-r--r--ash/accelerators/spoken_feedback_toggler.cc58
-rw-r--r--ash/accelerators/spoken_feedback_toggler.h57
-rw-r--r--ash/accelerators/spoken_feedback_toggler_unittest.cc50
8 files changed, 581 insertions, 0 deletions
diff --git a/ash/accelerators/key_hold_detector.cc b/ash/accelerators/key_hold_detector.cc
new file mode 100644
index 0000000..4b99820
--- /dev/null
+++ b/ash/accelerators/key_hold_detector.cc
@@ -0,0 +1,98 @@
+// 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 "ash/accelerators/key_hold_detector.h"
+
+#include <X11/Xlib.h>
+
+#undef RootWindow
+#undef Status
+
+#include "ash/shell.h"
+#include "base/message_loop/message_loop.h"
+#include "ui/aura/root_window.h"
+#include "ui/aura/window_tracker.h"
+#include "ui/events/event_dispatcher.h"
+
+namespace ash {
+namespace {
+
+void DispatchPressedEvent(XEvent native_event,
+ scoped_ptr<aura::WindowTracker> tracker) {
+ // The target window may be gone.
+ if (tracker->windows().empty())
+ return;
+ aura::Window* target = *(tracker->windows().begin());
+ ui::KeyEvent event(&native_event, false);
+ event.set_flags(event.flags() | ui::EF_IS_SYNTHESIZED);
+ ui::EventDispatchDetails result ALLOW_UNUSED =
+ target->GetDispatcher()->OnEventFromSource(&event);
+}
+
+void PostPressedEvent(ui::KeyEvent* event) {
+ // Modify RELEASED event to PRESSED event.
+ XEvent xkey = *(event->native_event());
+ xkey.xkey.type = KeyPress;
+ xkey.xkey.state |= ShiftMask;
+ scoped_ptr<aura::WindowTracker> tracker(new aura::WindowTracker);
+ tracker->Add(static_cast<aura::Window*>(event->target()));
+
+ base::MessageLoopForUI::current()->PostTask(
+ FROM_HERE,
+ base::Bind(&DispatchPressedEvent, xkey, base::Passed(&tracker)));
+}
+
+} // namespace
+
+KeyHoldDetector::KeyHoldDetector(scoped_ptr<Delegate> delegate)
+ : state_(INITIAL),
+ delegate_(delegate.Pass()) {}
+
+KeyHoldDetector::~KeyHoldDetector() {}
+
+void KeyHoldDetector::OnKeyEvent(ui::KeyEvent* event) {
+ if (!delegate_->ShouldProcessEvent(event))
+ return;
+
+ if (delegate_->IsStartEvent(event)) {
+ switch (state_) {
+ case INITIAL:
+ // Pass through posted event.
+ if (event->flags() & ui::EF_IS_SYNTHESIZED) {
+ event->set_flags(event->flags() & ~ui::EF_IS_SYNTHESIZED);
+ return;
+ }
+ state_ = PRESSED;
+ // Don't process ET_KEY_PRESSED event yet. The ET_KEY_PRESSED
+ // event will be generated upon ET_KEY_RELEASEED event below.
+ event->StopPropagation();
+ break;
+ case PRESSED:
+ state_ = HOLD;
+ // pass through
+ case HOLD:
+ delegate_->OnKeyHold(event);
+ event->StopPropagation();
+ break;
+ }
+ } else if (event->type() == ui::ET_KEY_RELEASED) {
+ switch (state_) {
+ case INITIAL:
+ break;
+ case PRESSED: {
+ PostPressedEvent(event);
+ event->StopPropagation();
+ break;
+ }
+ case HOLD: {
+ delegate_->OnKeyUnhold(event);
+ event->StopPropagation();
+ break;
+ }
+ }
+ state_ = INITIAL;
+ }
+}
+
+} // namespace ash
diff --git a/ash/accelerators/key_hold_detector.h b/ash/accelerators/key_hold_detector.h
new file mode 100644
index 0000000..b77f4cd
--- /dev/null
+++ b/ash/accelerators/key_hold_detector.h
@@ -0,0 +1,71 @@
+// 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.
+
+#ifndef ASH_ACCELERATOR_KEY_HOLD_DETECTOR_H_
+#define ASH_ACCELERATOR_KEY_HOLD_DETECTOR_H_
+
+#include "ash/ash_export.h"
+#include "base/memory/scoped_ptr.h"
+#include "ui/events/event_handler.h"
+
+namespace ui {
+class KeyEvent;
+}
+
+namespace ash {
+
+// This class is used to implement action when a user press and hold the key.
+// When a user just pressed and released a key, normal pressed event gets
+// generated upon release.
+class ASH_EXPORT KeyHoldDetector : public ui::EventHandler {
+ public:
+ class Delegate {
+ public:
+ virtual ~Delegate() {}
+
+ // If this return false, the event handler does not process
+ // the event at all.
+ virtual bool ShouldProcessEvent(const ui::KeyEvent* event) const = 0;
+
+ // This should return true if the event should start the state transition.
+ virtual bool IsStartEvent(const ui::KeyEvent* event) const = 0;
+
+ // Called when the key is held.
+ virtual void OnKeyHold(const ui::KeyEvent* event) = 0;
+
+ // Called when the key is release after hold.
+ virtual void OnKeyUnhold(const ui::KeyEvent* event) = 0;
+ };
+
+ explicit KeyHoldDetector(scoped_ptr<Delegate> delegate);
+ virtual ~KeyHoldDetector();
+
+ // ui::EventHandler overrides:
+ virtual void OnKeyEvent(ui::KeyEvent* key_event) OVERRIDE;
+
+ private:
+ // A state to keep track of one click and click and hold operation.
+ //
+ // One click:
+ // INITIAL --(first press)--> PRESSED --(release)--> INITIAL[SEND PRESS]
+ //
+ // Click and hold:
+ // INITIAL --(first press)--> PRESSED --(press)-->
+ // HOLD[OnKeyHold] --(press)--> HOLD[OnKeyHold] --(release)-->
+ // INITIAL[OnKeyUnhold]
+ enum State {
+ INITIAL,
+ PRESSED,
+ HOLD
+ };
+
+ State state_;
+ scoped_ptr<Delegate> delegate_;
+
+ DISALLOW_COPY_AND_ASSIGN(KeyHoldDetector);
+};
+
+} // namespace ash
+
+#endif // ASH_ACCELERATOR_KEY_HOLD_DETECTOR_H_
diff --git a/ash/accelerators/magnifier_key_scroller.cc b/ash/accelerators/magnifier_key_scroller.cc
new file mode 100644
index 0000000..709336f
--- /dev/null
+++ b/ash/accelerators/magnifier_key_scroller.cc
@@ -0,0 +1,81 @@
+// 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 "ash/accelerators/magnifier_key_scroller.h"
+
+#include "ash/accelerators/key_hold_detector.h"
+#include "ash/ash_switches.h"
+#include "ash/magnifier/magnification_controller.h"
+#include "ash/shell.h"
+#include "base/command_line.h"
+
+namespace ash {
+namespace {
+bool magnifier_key_scroller_enabled = false;
+}
+
+// static
+bool MagnifierKeyScroller::IsEnabled() {
+ return (magnifier_key_scroller_enabled ||
+ CommandLine::ForCurrentProcess()->HasSwitch(
+ switches::kAshEnableMagnifierKeyScroller)) &&
+ ash::Shell::GetInstance()->magnification_controller()->IsEnabled();
+}
+
+// static
+void MagnifierKeyScroller::SetEnabled(bool enabled) {
+ magnifier_key_scroller_enabled = enabled;
+}
+
+// static
+scoped_ptr<ui::EventHandler> MagnifierKeyScroller::CreateHandler() {
+ scoped_ptr<KeyHoldDetector::Delegate> delegate(new MagnifierKeyScroller());
+ return scoped_ptr<ui::EventHandler>(new KeyHoldDetector(delegate.Pass()));
+}
+
+bool MagnifierKeyScroller::ShouldProcessEvent(const ui::KeyEvent* event) const {
+ return IsEnabled() &&
+ (event->key_code() == ui::VKEY_UP ||
+ event->key_code() == ui::VKEY_DOWN ||
+ event->key_code() == ui::VKEY_LEFT ||
+ event->key_code() == ui::VKEY_RIGHT);
+}
+
+bool MagnifierKeyScroller::IsStartEvent(const ui::KeyEvent* event) const {
+ return event->type() == ui::ET_KEY_PRESSED &&
+ event->flags() & ui::EF_SHIFT_DOWN;
+}
+
+void MagnifierKeyScroller::OnKeyHold(const ui::KeyEvent* event) {
+ MagnificationController* controller =
+ Shell::GetInstance()->magnification_controller();
+ switch (event->key_code()) {
+ case ui::VKEY_UP:
+ controller->SetScrollDirection(MagnificationController::SCROLL_UP);
+ break;
+ case ui::VKEY_DOWN:
+ controller->SetScrollDirection(MagnificationController::SCROLL_DOWN);
+ break;
+ case ui::VKEY_LEFT:
+ controller->SetScrollDirection(MagnificationController::SCROLL_LEFT);
+ break;
+ case ui::VKEY_RIGHT:
+ controller->SetScrollDirection(MagnificationController::SCROLL_RIGHT);
+ break;
+ default:
+ NOTREACHED() << "Unknown keyboard_code:" << event->key_code();
+ }
+}
+
+void MagnifierKeyScroller::OnKeyUnhold(const ui::KeyEvent* event) {
+ MagnificationController* controller =
+ Shell::GetInstance()->magnification_controller();
+ controller->SetScrollDirection(MagnificationController::SCROLL_NONE);
+}
+
+MagnifierKeyScroller::MagnifierKeyScroller() {}
+
+MagnifierKeyScroller::~MagnifierKeyScroller() {}
+
+} // namespace ash
diff --git a/ash/accelerators/magnifier_key_scroller.h b/ash/accelerators/magnifier_key_scroller.h
new file mode 100644
index 0000000..a28db86
--- /dev/null
+++ b/ash/accelerators/magnifier_key_scroller.h
@@ -0,0 +1,55 @@
+// 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.
+
+#ifndef ASH_ACCELERATORS_MAGNIFIER_KEY_SCROLLER_H_
+#define ASH_ACCELERATORS_MAGNIFIER_KEY_SCROLLER_H_
+
+#include "ash/accelerators/key_hold_detector.h"
+#include "ash/ash_export.h"
+#include "base/memory/scoped_ptr.h"
+#include "ui/events/event_handler.h"
+
+namespace ui {
+class KeyEvent;
+}
+
+namespace ash {
+
+// A KeyHoldDetector delegate to control control magnified screen.
+class ASH_EXPORT MagnifierKeyScroller : public KeyHoldDetector::Delegate {
+ public:
+ static bool IsEnabled();
+ static void SetEnabled(bool enabled);
+ static scoped_ptr<ui::EventHandler> CreateHandler();
+
+ // A scoped object to enable and disable the magnifier accelerator for test.
+ class ScopedEnablerForTest {
+ public:
+ ScopedEnablerForTest() {
+ SetEnabled(true);
+ }
+ ~ScopedEnablerForTest() {
+ SetEnabled(false);
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(ScopedEnablerForTest);
+ };
+
+ private:
+ // KeyHoldDetector overrides:
+ virtual bool ShouldProcessEvent(const ui::KeyEvent* event) const OVERRIDE;
+ virtual bool IsStartEvent(const ui::KeyEvent* event) const OVERRIDE;
+ virtual void OnKeyHold(const ui::KeyEvent* event) OVERRIDE;
+ virtual void OnKeyUnhold(const ui::KeyEvent* event) OVERRIDE;
+
+ MagnifierKeyScroller();
+ virtual ~MagnifierKeyScroller();
+
+ DISALLOW_COPY_AND_ASSIGN(MagnifierKeyScroller);
+};
+
+} // namespace ash
+
+#endif // ASH_ACCELERATORS_MAGNIFIER_KEY_SCROLLER_H_
diff --git a/ash/accelerators/magnifier_key_scroller_unittest.cc b/ash/accelerators/magnifier_key_scroller_unittest.cc
new file mode 100644
index 0000000..21eb2ab
--- /dev/null
+++ b/ash/accelerators/magnifier_key_scroller_unittest.cc
@@ -0,0 +1,111 @@
+// 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 "ash/accelerators/magnifier_key_scroller.h"
+
+#include "ash/magnifier/magnification_controller.h"
+#include "ash/shell.h"
+#include "ash/test/ash_test_base.h"
+#include "ash/wm/window_util.h"
+#include "ui/aura/test/event_generator.h"
+#include "ui/aura/test/test_window_delegate.h"
+
+namespace ash {
+namespace {
+
+class KeyEventDelegate : public aura::test::TestWindowDelegate {
+ public:
+ KeyEventDelegate() {}
+ virtual ~KeyEventDelegate() {}
+
+ // ui::EventHandler overrides:
+ virtual void OnKeyEvent(ui::KeyEvent* event) OVERRIDE {
+ key_event.reset(new ui::KeyEvent(
+ event->type(), event->key_code(), event->flags(), false));
+ }
+
+ const ui::KeyEvent* event() const { return key_event.get(); }
+ void reset() { key_event.reset(); }
+
+ private:
+ scoped_ptr<ui::KeyEvent> key_event;
+
+ DISALLOW_COPY_AND_ASSIGN(KeyEventDelegate);
+};
+
+} // namespace
+
+typedef ash::test::AshTestBase MagnifierKeyScrollerTest;
+
+TEST_F(MagnifierKeyScrollerTest, Basic) {
+ KeyEventDelegate delegate;
+ scoped_ptr<aura::Window> window(CreateTestWindowInShellWithDelegate(
+ &delegate,
+ 0,
+ gfx::Rect(10, 10, 100, 100)));
+ wm::ActivateWindow(window.get());
+
+ MagnifierKeyScroller::ScopedEnablerForTest scoped;
+ Shell* shell = Shell::GetInstance();
+ MagnificationController* controller = shell->magnification_controller();
+ controller->SetEnabled(true);
+
+ EXPECT_EQ("200,150", controller->GetWindowPosition().ToString());
+ aura::test::EventGenerator& generator = GetEventGenerator();
+
+ // Click and Release generates the press event upon release.
+ generator.PressKey(ui::VKEY_DOWN, ui::EF_SHIFT_DOWN);
+ EXPECT_EQ("200,150", controller->GetWindowPosition().ToString());
+ EXPECT_FALSE(delegate.event());
+
+ generator.ReleaseKey(ui::VKEY_DOWN, 0);
+ EXPECT_EQ("200,150", controller->GetWindowPosition().ToString());
+ RunAllPendingInMessageLoop();
+ EXPECT_TRUE(delegate.event());
+ EXPECT_EQ(ui::ET_KEY_PRESSED, delegate.event()->type());
+ delegate.reset();
+
+ // Click and hold scrolls the magnifier screen.
+ generator.PressKey(ui::VKEY_DOWN, ui::EF_SHIFT_DOWN);
+ EXPECT_EQ("200,150", controller->GetWindowPosition().ToString());
+ EXPECT_FALSE(delegate.event());
+
+ generator.PressKey(ui::VKEY_DOWN, ui::EF_SHIFT_DOWN);
+ EXPECT_EQ("200,300", controller->GetWindowPosition().ToString());
+ EXPECT_FALSE(delegate.event());
+
+ generator.ReleaseKey(ui::VKEY_DOWN, 0);
+ EXPECT_EQ("200,300", controller->GetWindowPosition().ToString());
+ EXPECT_FALSE(delegate.event());
+
+ // Events are passed normally when the magnifier is off.
+ controller->SetEnabled(false);
+
+ generator.PressKey(ui::VKEY_DOWN, ui::EF_SHIFT_DOWN);
+ EXPECT_TRUE(delegate.event());
+ EXPECT_EQ(ui::ET_KEY_PRESSED, delegate.event()->type());
+ delegate.reset();
+
+ generator.ReleaseKey(ui::VKEY_DOWN, 0);
+ EXPECT_TRUE(delegate.event());
+ EXPECT_EQ(ui::ET_KEY_RELEASED, delegate.event()->type());
+ delegate.reset();
+
+ generator.PressKey(ui::VKEY_DOWN, ui::EF_SHIFT_DOWN);
+ EXPECT_TRUE(delegate.event());
+ EXPECT_EQ(ui::ET_KEY_PRESSED, delegate.event()->type());
+ delegate.reset();
+
+ generator.PressKey(ui::VKEY_DOWN, ui::EF_SHIFT_DOWN);
+ EXPECT_TRUE(delegate.event());
+ EXPECT_EQ(ui::ET_KEY_PRESSED, delegate.event()->type());
+ delegate.reset();
+
+ generator.ReleaseKey(ui::VKEY_DOWN, 0);
+ EXPECT_TRUE(delegate.event());
+ EXPECT_EQ(ui::ET_KEY_RELEASED, delegate.event()->type());
+ delegate.reset();
+}
+
+} // namespace ash
diff --git a/ash/accelerators/spoken_feedback_toggler.cc b/ash/accelerators/spoken_feedback_toggler.cc
new file mode 100644
index 0000000..813974d
--- /dev/null
+++ b/ash/accelerators/spoken_feedback_toggler.cc
@@ -0,0 +1,58 @@
+// 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 "ash/accelerators/spoken_feedback_toggler.h"
+
+#include "ash/accelerators/key_hold_detector.h"
+#include "ash/accessibility_delegate.h"
+#include "ash/shell.h"
+
+namespace ash {
+namespace {
+bool speech_feedback_toggler_enabled = false;
+}
+
+// static
+bool SpokenFeedbackToggler::IsEnabled() {
+ return speech_feedback_toggler_enabled;
+}
+
+// static
+void SpokenFeedbackToggler::SetEnabled(bool enabled) {
+ speech_feedback_toggler_enabled = enabled;
+}
+
+// static
+scoped_ptr<ui::EventHandler> SpokenFeedbackToggler::CreateHandler() {
+ scoped_ptr<KeyHoldDetector::Delegate> delegate(new SpokenFeedbackToggler());
+ return scoped_ptr<ui::EventHandler>(new KeyHoldDetector(delegate.Pass()));
+}
+
+bool SpokenFeedbackToggler::ShouldProcessEvent(
+ const ui::KeyEvent* event) const {
+ return IsEnabled() && event->key_code() == ui::VKEY_F6;
+}
+
+bool SpokenFeedbackToggler::IsStartEvent(const ui::KeyEvent* event) const {
+ return event->type() == ui::ET_KEY_PRESSED &&
+ event->flags() & ui::EF_SHIFT_DOWN;
+}
+
+void SpokenFeedbackToggler::OnKeyHold(const ui::KeyEvent* event) {
+ if (!toggled_) {
+ toggled_ = true;
+ Shell::GetInstance()->accessibility_delegate()->
+ ToggleSpokenFeedback(A11Y_NOTIFICATION_SHOW);
+ }
+}
+
+void SpokenFeedbackToggler::OnKeyUnhold(const ui::KeyEvent* event) {
+ toggled_ = false;
+}
+
+SpokenFeedbackToggler::SpokenFeedbackToggler() : toggled_(false) {}
+
+SpokenFeedbackToggler::~SpokenFeedbackToggler() {}
+
+} // namespace ash
diff --git a/ash/accelerators/spoken_feedback_toggler.h b/ash/accelerators/spoken_feedback_toggler.h
new file mode 100644
index 0000000..592c71c
--- /dev/null
+++ b/ash/accelerators/spoken_feedback_toggler.h
@@ -0,0 +1,57 @@
+// 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.
+
+#ifndef ASH_ACCELERATORS_SPOKEN_FEEDBACK_TOGGLER_H_
+#define ASH_ACCELERATORS_SPOKEN_FEEDBACK_TOGGLER_H_
+
+#include "ash/accelerators/key_hold_detector.h"
+#include "ash/ash_export.h"
+#include "base/memory/scoped_ptr.h"
+#include "ui/events/event_handler.h"
+
+namespace ui {
+class KeyEvent;
+}
+
+namespace ash {
+
+// A KeyHoldDetector delegate to toggle spoken feedback.
+class ASH_EXPORT SpokenFeedbackToggler : public KeyHoldDetector::Delegate {
+ public:
+ static bool IsEnabled();
+ static void SetEnabled(bool enabled);
+ static scoped_ptr<ui::EventHandler> CreateHandler();
+
+ // A scoped object to enable and disable the magnifier accelerator for test.
+ class ScopedEnablerForTest {
+ public:
+ ScopedEnablerForTest() {
+ SetEnabled(true);
+ }
+ ~ScopedEnablerForTest() {
+ SetEnabled(false);
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(ScopedEnablerForTest);
+ };
+
+ private:
+ // KeyHoldDetector overrides:
+ virtual bool ShouldProcessEvent(const ui::KeyEvent* event) const OVERRIDE;
+ virtual bool IsStartEvent(const ui::KeyEvent* event) const OVERRIDE;
+ virtual void OnKeyHold(const ui::KeyEvent* event) OVERRIDE;
+ virtual void OnKeyUnhold(const ui::KeyEvent* event) OVERRIDE;
+
+ SpokenFeedbackToggler();
+ virtual ~SpokenFeedbackToggler();
+
+ bool toggled_;
+
+ DISALLOW_COPY_AND_ASSIGN(SpokenFeedbackToggler);
+};
+
+} // namespace ash
+
+#endif // ASH_ACCELERATORS_SPOKEN_FEEDBACK_TOGGLER_H_
diff --git a/ash/accelerators/spoken_feedback_toggler_unittest.cc b/ash/accelerators/spoken_feedback_toggler_unittest.cc
new file mode 100644
index 0000000..9344471
--- /dev/null
+++ b/ash/accelerators/spoken_feedback_toggler_unittest.cc
@@ -0,0 +1,50 @@
+// 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 "ash/accelerators/spoken_feedback_toggler.h"
+#include "ash/accessibility_delegate.h"
+#include "ash/shell.h"
+#include "ash/test/ash_test_base.h"
+#include "ash/wm/window_util.h"
+#include "ui/aura/test/event_generator.h"
+#include "ui/aura/test/test_window_delegate.h"
+
+namespace ash {
+
+typedef ash::test::AshTestBase SpokenFeedbackTogglerTest;
+
+TEST_F(SpokenFeedbackTogglerTest, Basic) {
+ SpokenFeedbackToggler::ScopedEnablerForTest scoped;
+ Shell* shell = Shell::GetInstance();
+ AccessibilityDelegate* delegate = shell->accessibility_delegate();
+ aura::test::EventGenerator& generator = GetEventGenerator();
+ EXPECT_FALSE(delegate->IsSpokenFeedbackEnabled());
+
+ generator.PressKey(ui::VKEY_F6, ui::EF_SHIFT_DOWN);
+ EXPECT_FALSE(delegate->IsSpokenFeedbackEnabled());
+ generator.ReleaseKey(ui::VKEY_F6, 0);
+ EXPECT_FALSE(delegate->IsSpokenFeedbackEnabled());
+
+ // Click and hold toggles the spoken feedback.
+ generator.PressKey(ui::VKEY_F6, ui::EF_SHIFT_DOWN);
+ EXPECT_FALSE(delegate->IsSpokenFeedbackEnabled());
+ generator.PressKey(ui::VKEY_F6, ui::EF_SHIFT_DOWN);
+ EXPECT_TRUE(delegate->IsSpokenFeedbackEnabled());
+ generator.PressKey(ui::VKEY_F6, ui::EF_SHIFT_DOWN);
+ EXPECT_TRUE(delegate->IsSpokenFeedbackEnabled());
+ generator.ReleaseKey(ui::VKEY_F6, 0);
+ EXPECT_TRUE(delegate->IsSpokenFeedbackEnabled());
+
+ // toggle again
+ generator.PressKey(ui::VKEY_F6, ui::EF_SHIFT_DOWN);
+ EXPECT_TRUE(delegate->IsSpokenFeedbackEnabled());
+ generator.PressKey(ui::VKEY_F6, ui::EF_SHIFT_DOWN);
+ EXPECT_FALSE(delegate->IsSpokenFeedbackEnabled());
+ generator.PressKey(ui::VKEY_F6, ui::EF_SHIFT_DOWN);
+ EXPECT_FALSE(delegate->IsSpokenFeedbackEnabled());
+ generator.ReleaseKey(ui::VKEY_F6, 0);
+ EXPECT_FALSE(delegate->IsSpokenFeedbackEnabled());
+}
+
+} // namespace ash