// Copyright 2015 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 "chrome/browser/chromeos/accessibility/spoken_feedback_event_rewriter.h" #include "ash/shell.h" #include "ash/test/ash_test_base.h" #include "base/macros.h" #include "ui/aura/window.h" #include "ui/aura/window_tree_host.h" #include "ui/events/event.h" #include "ui/events/event_constants.h" #include "ui/events/keycodes/keyboard_codes.h" #include "ui/events/test/event_generator.h" // Records all key events. class EventCapturer : public ui::EventHandler { public: EventCapturer() {} ~EventCapturer() override {} void Reset() { events_.clear(); } void OnEvent(ui::Event* event) override { if (event->IsKeyEvent()) events_.push_back(new ui::KeyEvent(static_cast<ui::KeyEvent&>(*event))); } const ScopedVector<ui::KeyEvent>& captured_events() const { return events_; } private: ScopedVector<ui::KeyEvent> events_; DISALLOW_COPY_AND_ASSIGN(EventCapturer); }; class TestDelegate : public SpokenFeedbackEventRewriterDelegate { public: TestDelegate() : is_spoken_feedback_enabled_(false), dispatch_result_(false) {} ~TestDelegate() override {} void set_is_spoken_feedback_enabled(bool enabled) { is_spoken_feedback_enabled_ = enabled; } void set_dispatch_result(bool result) { dispatch_result_ = result; } private: // SpokenFeedbackEventRewriterDelegate: bool IsSpokenFeedbackEnabled() const override { return is_spoken_feedback_enabled_; } bool DispatchKeyEventToChromeVox(const ui::KeyEvent& key_event, bool capture) override { return dispatch_result_; } bool is_spoken_feedback_enabled_; bool dispatch_result_; DISALLOW_COPY_AND_ASSIGN(TestDelegate); }; class SpokenFeedbackEventRewriterTest : public ash::test::AshTestBase { public: SpokenFeedbackEventRewriterTest() : generator_(nullptr), spoken_feedback_event_rewriter_(new SpokenFeedbackEventRewriter()) { delegate_ = new TestDelegate(); spoken_feedback_event_rewriter_->SetDelegateForTest( scoped_ptr<TestDelegate>(delegate_)); } void SetUp() override { ash::test::AshTestBase::SetUp(); generator_ = &AshTestBase::GetEventGenerator(); CurrentContext()->AddPreTargetHandler(&event_capturer_); CurrentContext()->GetHost()->GetEventSource()->AddEventRewriter( spoken_feedback_event_rewriter_.get()); } void TearDown() override { CurrentContext()->GetHost()->GetEventSource()->RemoveEventRewriter( spoken_feedback_event_rewriter_.get()); CurrentContext()->RemovePreTargetHandler(&event_capturer_); generator_ = nullptr; ash::test::AshTestBase::TearDown(); } protected: TestDelegate* delegate_; ui::test::EventGenerator* generator_; EventCapturer event_capturer_; private: scoped_ptr<SpokenFeedbackEventRewriter> spoken_feedback_event_rewriter_; DISALLOW_COPY_AND_ASSIGN(SpokenFeedbackEventRewriterTest); }; TEST_F(SpokenFeedbackEventRewriterTest, KeysNotEatenWithChromeVoxDisabled) { // Send Search+Shift+Right. generator_->PressKey(ui::VKEY_LWIN, ui::EF_COMMAND_DOWN); ASSERT_EQ(1U, event_capturer_.captured_events().size()); generator_->PressKey(ui::VKEY_SHIFT, ui::EF_COMMAND_DOWN | ui::EF_SHIFT_DOWN); ASSERT_EQ(2U, event_capturer_.captured_events().size()); // Mock successful commands lookup and dispatch; shouldn't matter either way. delegate_->set_dispatch_result(true); generator_->PressKey(ui::VKEY_RIGHT, ui::EF_COMMAND_DOWN | ui::EF_SHIFT_DOWN); ASSERT_EQ(3U, event_capturer_.captured_events().size()); // Released keys shouldn't get eaten. delegate_->set_dispatch_result(false); generator_->ReleaseKey(ui::VKEY_RIGHT, ui::EF_COMMAND_DOWN | ui::EF_SHIFT_DOWN); generator_->ReleaseKey(ui::VKEY_SHIFT, ui::EF_COMMAND_DOWN); generator_->ReleaseKey(ui::VKEY_LWIN, 0); ASSERT_EQ(6U, event_capturer_.captured_events().size()); // Try releasing more keys. generator_->ReleaseKey(ui::VKEY_RIGHT, 0); generator_->ReleaseKey(ui::VKEY_SHIFT, 0); generator_->ReleaseKey(ui::VKEY_LWIN, 0); ASSERT_EQ(9U, event_capturer_.captured_events().size()); }