diff options
Diffstat (limited to 'ash/accelerators')
-rw-r--r-- | ash/accelerators/key_hold_detector.cc | 98 | ||||
-rw-r--r-- | ash/accelerators/key_hold_detector.h | 71 | ||||
-rw-r--r-- | ash/accelerators/magnifier_key_scroller.cc | 81 | ||||
-rw-r--r-- | ash/accelerators/magnifier_key_scroller.h | 55 | ||||
-rw-r--r-- | ash/accelerators/magnifier_key_scroller_unittest.cc | 111 | ||||
-rw-r--r-- | ash/accelerators/spoken_feedback_toggler.cc | 58 | ||||
-rw-r--r-- | ash/accelerators/spoken_feedback_toggler.h | 57 | ||||
-rw-r--r-- | ash/accelerators/spoken_feedback_toggler_unittest.cc | 50 |
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 |