summaryrefslogtreecommitdiffstats
path: root/ash
diff options
context:
space:
mode:
authoroshima@chromium.org <oshima@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-06-19 17:58:51 +0000
committeroshima@chromium.org <oshima@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2014-06-19 17:58:51 +0000
commit0bb0c5a32a4348037c515372c5aa4b4bd5c0893f (patch)
tree09dd59ad4214ad83818d7ac2587d8530fdc131fd /ash
parentbfcaff5da257f13f967c50162958b2a7be7cf2d6 (diff)
downloadchromium_src-0bb0c5a32a4348037c515372c5aa4b4bd5c0893f.zip
chromium_src-0bb0c5a32a4348037c515372c5aa4b4bd5c0893f.tar.gz
chromium_src-0bb0c5a32a4348037c515372c5aa4b4bd5c0893f.tar.bz2
Revert 278342 "Convert sticky keys to a chromeos::EventRewriter ..."
> Convert sticky keys to a chromeos::EventRewriter phase. > > BUG=354035 > TEST=unit_tests,ash_unittests,manual > R=sadrul@chromium.org,derat@chromium.org > > Review URL: https://codereview.chromium.org/255033003 TBR=kpschoedel@chromium.org Review URL: https://codereview.chromium.org/341923006 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@278419 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'ash')
-rw-r--r--ash/shell.cc11
-rw-r--r--ash/sticky_keys/sticky_keys_controller.cc515
-rw-r--r--ash/sticky_keys/sticky_keys_controller.h168
-rw-r--r--ash/sticky_keys/sticky_keys_overlay_unittest.cc200
-rw-r--r--ash/sticky_keys/sticky_keys_unittest.cc815
5 files changed, 1150 insertions, 559 deletions
diff --git a/ash/shell.cc b/ash/shell.cc
index 2c39306..c8b3279 100644
--- a/ash/shell.cc
+++ b/ash/shell.cc
@@ -889,6 +889,13 @@ void Shell::Init(const ShellInitParams& init_params) {
// The order in which event filters are added is significant.
+#if defined(OS_CHROMEOS)
+ // The StickyKeysController also rewrites events and must be added
+ // before observers, but after the EventRewriterEventFilter.
+ sticky_keys_controller_.reset(new StickyKeysController);
+ AddPreTargetHandler(sticky_keys_controller_.get());
+#endif
+
// wm::UserActivityDetector passes events to observers, so let them get
// rewritten first.
user_activity_detector_.reset(new ::wm::UserActivityDetector);
@@ -923,10 +930,6 @@ void Shell::Init(const ShellInitParams& init_params) {
keyboard::InitializeKeyboard();
#endif
-#if defined(OS_CHROMEOS)
- sticky_keys_controller_.reset(new StickyKeysController);
-#endif
-
lock_state_controller_.reset(new LockStateController);
power_button_controller_.reset(new PowerButtonController(
lock_state_controller_.get()));
diff --git a/ash/sticky_keys/sticky_keys_controller.cc b/ash/sticky_keys/sticky_keys_controller.cc
index 6237004..53be1fc 100644
--- a/ash/sticky_keys/sticky_keys_controller.cc
+++ b/ash/sticky_keys/sticky_keys_controller.cc
@@ -4,6 +4,12 @@
#include "ash/sticky_keys/sticky_keys_controller.h"
+#if defined(USE_X11)
+#include <X11/extensions/XInput2.h>
+#include <X11/Xlib.h>
+#undef RootWindow
+#endif
+
#include "ash/sticky_keys/sticky_keys_overlay.h"
#include "base/basictypes.h"
#include "base/debug/stack_trace.h"
@@ -19,26 +25,79 @@ namespace ash {
namespace {
// Returns true if the type of mouse event should be modified by sticky keys.
-bool ShouldModifyMouseEvent(const ui::MouseEvent& event) {
- ui::EventType type = event.type();
+bool ShouldModifyMouseEvent(ui::MouseEvent* event) {
+ ui::EventType type = event->type();
return type == ui::ET_MOUSE_PRESSED || type == ui::ET_MOUSE_RELEASED ||
type == ui::ET_MOUSEWHEEL;
}
-// Handle the common tail of event rewriting.
-ui::EventRewriteStatus RewriteUpdate(bool consumed,
- bool released,
- int mod_down_flags,
- int* flags) {
- int changed_down_flags = mod_down_flags & ~*flags;
- *flags |= mod_down_flags;
- if (consumed)
- return ui::EVENT_REWRITE_DISCARD;
- if (released)
- return ui::EVENT_REWRITE_DISPATCH_ANOTHER;
- if (changed_down_flags)
- return ui::EVENT_REWRITE_REWRITTEN;
- return ui::EVENT_REWRITE_CONTINUE;
+// An implementation of StickyKeysHandler::StickyKeysHandlerDelegate.
+class StickyKeysHandlerDelegateImpl :
+ public StickyKeysHandler::StickyKeysHandlerDelegate {
+ public:
+ StickyKeysHandlerDelegateImpl();
+ virtual ~StickyKeysHandlerDelegateImpl();
+
+ // StickyKeysHandlerDelegate overrides.
+ virtual void DispatchKeyEvent(ui::KeyEvent* event,
+ aura::Window* target) OVERRIDE;
+
+ virtual void DispatchMouseEvent(ui::MouseEvent* event,
+ aura::Window* target) OVERRIDE;
+
+ virtual void DispatchScrollEvent(ui::ScrollEvent* event,
+ aura::Window* target) OVERRIDE;
+ private:
+ void DispatchEvent(ui::Event* event, aura::Window* target);
+
+ DISALLOW_COPY_AND_ASSIGN(StickyKeysHandlerDelegateImpl);
+};
+
+StickyKeysHandlerDelegateImpl::StickyKeysHandlerDelegateImpl() {
+}
+
+StickyKeysHandlerDelegateImpl::~StickyKeysHandlerDelegateImpl() {
+}
+
+void StickyKeysHandlerDelegateImpl::DispatchKeyEvent(ui::KeyEvent* event,
+ aura::Window* target) {
+ DispatchEvent(event, target);
+}
+
+void StickyKeysHandlerDelegateImpl::DispatchMouseEvent(ui::MouseEvent* event,
+ aura::Window* target) {
+ DCHECK(target);
+ // We need to send a new, untransformed mouse event to the host.
+ if (event->IsMouseWheelEvent()) {
+ aura::Window* source = static_cast<aura::Window*>(event->target());
+ ui::MouseWheelEvent new_event(*static_cast<ui::MouseWheelEvent*>(event),
+ source,
+ source->GetRootWindow());
+ // Transform the location back to host coordinates before dispatching.
+ new_event.UpdateForRootTransform(source->GetHost()->GetRootTransform());
+ DispatchEvent(&new_event, target);
+ } else {
+ aura::Window* source = static_cast<aura::Window*>(event->target());
+ ui::MouseEvent new_event(*event, source, source->GetRootWindow());
+ // Transform the location back to host coordinates before dispatching.
+ new_event.UpdateForRootTransform(source->GetHost()->GetRootTransform());
+ DispatchEvent(&new_event, target);
+ }
+}
+
+void StickyKeysHandlerDelegateImpl::DispatchScrollEvent(
+ ui::ScrollEvent* event,
+ aura::Window* target) {
+ DispatchEvent(event, target);
+}
+
+void StickyKeysHandlerDelegateImpl::DispatchEvent(ui::Event* event,
+ aura::Window* target) {
+ DCHECK(target);
+ ui::EventDispatchDetails details =
+ target->GetHost()->event_processor()->OnEventFromSource(event);
+ if (details.dispatcher_destroyed)
+ return;
}
} // namespace
@@ -61,11 +120,21 @@ void StickyKeysController::Enable(bool enabled) {
// Reset key handlers when activating sticky keys to ensure all
// the handlers' states are reset.
if (enabled_) {
- shift_sticky_key_.reset(new StickyKeysHandler(ui::EF_SHIFT_DOWN));
- alt_sticky_key_.reset(new StickyKeysHandler(ui::EF_ALT_DOWN));
- altgr_sticky_key_.reset(new StickyKeysHandler(ui::EF_ALTGR_DOWN));
- ctrl_sticky_key_.reset(new StickyKeysHandler(ui::EF_CONTROL_DOWN));
- mod3_sticky_key_.reset(new StickyKeysHandler(ui::EF_MOD3_DOWN));
+ shift_sticky_key_.reset(
+ new StickyKeysHandler(ui::EF_SHIFT_DOWN,
+ new StickyKeysHandlerDelegateImpl()));
+ alt_sticky_key_.reset(
+ new StickyKeysHandler(ui::EF_ALT_DOWN,
+ new StickyKeysHandlerDelegateImpl()));
+ altgr_sticky_key_.reset(
+ new StickyKeysHandler(ui::EF_ALTGR_DOWN,
+ new StickyKeysHandlerDelegateImpl()));
+ ctrl_sticky_key_.reset(
+ new StickyKeysHandler(ui::EF_CONTROL_DOWN,
+ new StickyKeysHandlerDelegateImpl()));
+ mod3_sticky_key_.reset(
+ new StickyKeysHandler(ui::EF_MOD3_DOWN,
+ new StickyKeysHandlerDelegateImpl()));
overlay_.reset(new StickyKeysOverlay());
overlay_->SetModifierVisible(ui::EF_ALTGR_DOWN, altgr_enabled_);
@@ -86,103 +155,56 @@ void StickyKeysController::SetModifiersEnabled(bool mod3_enabled,
}
}
-bool StickyKeysController::HandleKeyEvent(const ui::KeyEvent& event,
- ui::KeyboardCode key_code,
- int* mod_down_flags,
- bool* released) {
- return shift_sticky_key_->HandleKeyEvent(
- event, key_code, mod_down_flags, released) ||
- alt_sticky_key_->HandleKeyEvent(
- event, key_code, mod_down_flags, released) ||
- altgr_sticky_key_->HandleKeyEvent(
- event, key_code, mod_down_flags, released) ||
- ctrl_sticky_key_->HandleKeyEvent(
- event, key_code, mod_down_flags, released) ||
- mod3_sticky_key_->HandleKeyEvent(
- event, key_code, mod_down_flags, released);
-}
-
-bool StickyKeysController::HandleMouseEvent(const ui::MouseEvent& event,
- int* mod_down_flags,
- bool* released) {
- return shift_sticky_key_->HandleMouseEvent(
- event, mod_down_flags, released) ||
- alt_sticky_key_->HandleMouseEvent(
- event, mod_down_flags, released) ||
- altgr_sticky_key_->HandleMouseEvent(
- event, mod_down_flags, released) ||
- ctrl_sticky_key_->HandleMouseEvent(
- event, mod_down_flags, released) ||
- mod3_sticky_key_->HandleMouseEvent(
- event, mod_down_flags, released);
-}
-
-bool StickyKeysController::HandleScrollEvent(const ui::ScrollEvent& event,
- int* mod_down_flags,
- bool* released) {
- return shift_sticky_key_->HandleScrollEvent(
- event, mod_down_flags, released) ||
- alt_sticky_key_->HandleScrollEvent(
- event, mod_down_flags, released) ||
- altgr_sticky_key_->HandleScrollEvent(
- event, mod_down_flags, released) ||
- ctrl_sticky_key_->HandleScrollEvent(
- event, mod_down_flags, released) ||
- mod3_sticky_key_->HandleScrollEvent(
- event, mod_down_flags, released);
-}
-
-ui::EventRewriteStatus StickyKeysController::RewriteKeyEvent(
- const ui::KeyEvent& event,
- ui::KeyboardCode key_code,
- int* flags) {
- if (!enabled_)
- return ui::EVENT_REWRITE_CONTINUE;
- int mod_down_flags = 0;
- bool released = false;
- bool consumed = HandleKeyEvent(event, key_code, &mod_down_flags, &released);
- UpdateOverlay();
- return RewriteUpdate(consumed, released, mod_down_flags, flags);
-}
-
-ui::EventRewriteStatus StickyKeysController::RewriteMouseEvent(
- const ui::MouseEvent& event,
- int* flags) {
- if (!enabled_)
- return ui::EVENT_REWRITE_CONTINUE;
- int mod_down_flags = 0;
- bool released = false;
- bool consumed = HandleMouseEvent(event, &mod_down_flags, &released);
- UpdateOverlay();
- return RewriteUpdate(consumed, released, mod_down_flags, flags);
-}
-
-ui::EventRewriteStatus StickyKeysController::RewriteScrollEvent(
- const ui::ScrollEvent& event,
- int* flags) {
- if (!enabled_)
- return ui::EVENT_REWRITE_CONTINUE;
- int mod_down_flags = 0;
- bool released = false;
- bool consumed = HandleScrollEvent(event, &mod_down_flags, &released);
- UpdateOverlay();
- return RewriteUpdate(consumed, released, mod_down_flags, flags);
-}
-
-ui::EventRewriteStatus StickyKeysController::NextDispatchEvent(
- scoped_ptr<ui::Event>* new_event) {
- DCHECK(new_event);
- new_event->reset();
- int remaining = shift_sticky_key_->GetModifierUpEvent(new_event) +
- alt_sticky_key_->GetModifierUpEvent(new_event) +
- altgr_sticky_key_->GetModifierUpEvent(new_event) +
- ctrl_sticky_key_->GetModifierUpEvent(new_event) +
- mod3_sticky_key_->GetModifierUpEvent(new_event);
- if (!new_event)
- return ui::EVENT_REWRITE_CONTINUE;
- if (remaining)
- return ui::EVENT_REWRITE_DISPATCH_ANOTHER;
- return ui::EVENT_REWRITE_REWRITTEN;
+bool StickyKeysController::HandleKeyEvent(ui::KeyEvent* event) {
+ return shift_sticky_key_->HandleKeyEvent(event) ||
+ alt_sticky_key_->HandleKeyEvent(event) ||
+ altgr_sticky_key_->HandleKeyEvent(event) ||
+ ctrl_sticky_key_->HandleKeyEvent(event) ||
+ mod3_sticky_key_->HandleKeyEvent(event);
+}
+
+bool StickyKeysController::HandleMouseEvent(ui::MouseEvent* event) {
+ return shift_sticky_key_->HandleMouseEvent(event) ||
+ alt_sticky_key_->HandleMouseEvent(event) ||
+ altgr_sticky_key_->HandleMouseEvent(event) ||
+ ctrl_sticky_key_->HandleMouseEvent(event) ||
+ mod3_sticky_key_->HandleMouseEvent(event);
+}
+
+bool StickyKeysController::HandleScrollEvent(ui::ScrollEvent* event) {
+ return shift_sticky_key_->HandleScrollEvent(event) ||
+ alt_sticky_key_->HandleScrollEvent(event) ||
+ altgr_sticky_key_->HandleScrollEvent(event) ||
+ ctrl_sticky_key_->HandleScrollEvent(event) ||
+ mod3_sticky_key_->HandleScrollEvent(event);
+}
+
+void StickyKeysController::OnKeyEvent(ui::KeyEvent* event) {
+ // Do not consume a translated key event which is generated by an IME.
+ if (event->IsTranslated())
+ return;
+
+ if (enabled_) {
+ if (HandleKeyEvent(event))
+ event->StopPropagation();
+ UpdateOverlay();
+ }
+}
+
+void StickyKeysController::OnMouseEvent(ui::MouseEvent* event) {
+ if (enabled_) {
+ if (HandleMouseEvent(event))
+ event->StopPropagation();
+ UpdateOverlay();
+ }
+}
+
+void StickyKeysController::OnScrollEvent(ui::ScrollEvent* event) {
+ if (enabled_) {
+ if (HandleScrollEvent(event))
+ event->StopPropagation();
+ UpdateOverlay();
+ }
}
void StickyKeysController::UpdateOverlay() {
@@ -213,64 +235,66 @@ StickyKeysOverlay* StickyKeysController::GetOverlayForTest() {
///////////////////////////////////////////////////////////////////////////////
// StickyKeysHandler
-StickyKeysHandler::StickyKeysHandler(ui::EventFlags modifier_flag)
+StickyKeysHandler::StickyKeysHandler(ui::EventFlags modifier_flag,
+ StickyKeysHandlerDelegate* delegate)
: modifier_flag_(modifier_flag),
current_state_(STICKY_KEY_STATE_DISABLED),
+ event_from_myself_(false),
preparing_to_enable_(false),
- scroll_delta_(0) {
+ scroll_delta_(0),
+ delegate_(delegate) {
}
StickyKeysHandler::~StickyKeysHandler() {
}
-bool StickyKeysHandler::HandleKeyEvent(const ui::KeyEvent& event,
- ui::KeyboardCode key_code,
- int* mod_down_flags,
- bool* released) {
+StickyKeysHandler::StickyKeysHandlerDelegate::StickyKeysHandlerDelegate() {
+}
+
+StickyKeysHandler::StickyKeysHandlerDelegate::~StickyKeysHandlerDelegate() {
+}
+
+bool StickyKeysHandler::HandleKeyEvent(ui::KeyEvent* event) {
+ if (event_from_myself_)
+ return false; // Do not handle self-generated key event.
switch (current_state_) {
case STICKY_KEY_STATE_DISABLED:
- return HandleDisabledState(event, key_code);
+ return HandleDisabledState(event);
case STICKY_KEY_STATE_ENABLED:
- return HandleEnabledState(event, key_code, mod_down_flags, released);
+ return HandleEnabledState(event);
case STICKY_KEY_STATE_LOCKED:
- return HandleLockedState(event, key_code, mod_down_flags, released);
+ return HandleLockedState(event);
}
NOTREACHED();
return false;
}
-bool StickyKeysHandler::HandleMouseEvent(
- const ui::MouseEvent& event,
- int* mod_down_flags,
- bool* released) {
+bool StickyKeysHandler::HandleMouseEvent(ui::MouseEvent* event) {
if (ShouldModifyMouseEvent(event))
preparing_to_enable_ = false;
- if (current_state_ == STICKY_KEY_STATE_DISABLED ||
- !ShouldModifyMouseEvent(event)) {
+ if (event_from_myself_ || current_state_ == STICKY_KEY_STATE_DISABLED
+ || !ShouldModifyMouseEvent(event)) {
return false;
}
DCHECK(current_state_ == STICKY_KEY_STATE_ENABLED ||
current_state_ == STICKY_KEY_STATE_LOCKED);
- *mod_down_flags |= modifier_flag_;
+ AppendModifier(event);
// Only disable on the mouse released event in normal, non-locked mode.
if (current_state_ == STICKY_KEY_STATE_ENABLED &&
- event.type() != ui::ET_MOUSE_PRESSED) {
+ event->type() != ui::ET_MOUSE_PRESSED) {
current_state_ = STICKY_KEY_STATE_DISABLED;
- *released = true;
- return false;
+ DispatchEventAndReleaseModifier(event);
+ return true;
}
return false;
}
-bool StickyKeysHandler::HandleScrollEvent(
- const ui::ScrollEvent& event,
- int* mod_down_flags,
- bool* released) {
+bool StickyKeysHandler::HandleScrollEvent(ui::ScrollEvent* event) {
preparing_to_enable_ = false;
- if (current_state_ == STICKY_KEY_STATE_DISABLED)
+ if (event_from_myself_ || current_state_ == STICKY_KEY_STATE_DISABLED)
return false;
DCHECK(current_state_ == STICKY_KEY_STATE_ENABLED ||
current_state_ == STICKY_KEY_STATE_LOCKED);
@@ -279,82 +303,70 @@ bool StickyKeysHandler::HandleScrollEvent(
// and the offset of the current scroll event has the opposing sign.
bool direction_changed = false;
if (current_state_ == STICKY_KEY_STATE_ENABLED &&
- event.type() == ui::ET_SCROLL) {
- int offset = event.y_offset();
+ event->type() == ui::ET_SCROLL) {
+ int offset = event->y_offset();
if (scroll_delta_)
direction_changed = offset * scroll_delta_ <= 0;
scroll_delta_ = offset;
}
if (!direction_changed)
- *mod_down_flags |= modifier_flag_;
+ AppendModifier(event);
// We want to modify all the scroll events in the scroll sequence, which ends
// with a fling start event. We also stop when the scroll sequence changes
// direction.
if (current_state_ == STICKY_KEY_STATE_ENABLED &&
- (event.type() == ui::ET_SCROLL_FLING_START || direction_changed)) {
+ (event->type() == ui::ET_SCROLL_FLING_START || direction_changed)) {
current_state_ = STICKY_KEY_STATE_DISABLED;
scroll_delta_ = 0;
- *released = true;
- return false;
+ DispatchEventAndReleaseModifier(event);
+ return true;
}
return false;
}
-int StickyKeysHandler::GetModifierUpEvent(scoped_ptr<ui::Event>* new_event) {
- if (current_state_ != STICKY_KEY_STATE_DISABLED || !modifier_up_event_)
- return 0;
- DCHECK(new_event);
- if (*new_event)
- return 1;
- new_event->reset(modifier_up_event_.release());
- return 0;
-}
-
-StickyKeysHandler::KeyEventType StickyKeysHandler::TranslateKeyEvent(
- ui::EventType type,
- ui::KeyboardCode key_code) {
+StickyKeysHandler::KeyEventType
+ StickyKeysHandler::TranslateKeyEvent(ui::KeyEvent* event) {
bool is_target_key = false;
- if (key_code == ui::VKEY_SHIFT ||
- key_code == ui::VKEY_LSHIFT ||
- key_code == ui::VKEY_RSHIFT) {
+ if (event->key_code() == ui::VKEY_SHIFT ||
+ event->key_code() == ui::VKEY_LSHIFT ||
+ event->key_code() == ui::VKEY_RSHIFT) {
is_target_key = (modifier_flag_ == ui::EF_SHIFT_DOWN);
- } else if (key_code == ui::VKEY_CONTROL ||
- key_code == ui::VKEY_LCONTROL ||
- key_code == ui::VKEY_RCONTROL) {
+ } else if (event->key_code() == ui::VKEY_CONTROL ||
+ event->key_code() == ui::VKEY_LCONTROL ||
+ event->key_code() == ui::VKEY_RCONTROL) {
is_target_key = (modifier_flag_ == ui::EF_CONTROL_DOWN);
- } else if (key_code == ui::VKEY_MENU ||
- key_code == ui::VKEY_LMENU ||
- key_code == ui::VKEY_RMENU) {
+ } else if (event->key_code() == ui::VKEY_MENU ||
+ event->key_code() == ui::VKEY_LMENU ||
+ event->key_code() == ui::VKEY_RMENU) {
is_target_key = (modifier_flag_ == ui::EF_ALT_DOWN);
- } else if (key_code == ui::VKEY_ALTGR) {
+ } else if (event->key_code() == ui::VKEY_ALTGR) {
is_target_key = (modifier_flag_ == ui::EF_ALTGR_DOWN);
- } else if (key_code == ui::VKEY_OEM_8) {
+ } else if (event->key_code() == ui::VKEY_OEM_8) {
is_target_key = (modifier_flag_ == ui::EF_MOD3_DOWN);
} else {
- return type == ui::ET_KEY_PRESSED ?
+ return event->type() == ui::ET_KEY_PRESSED ?
NORMAL_KEY_DOWN : NORMAL_KEY_UP;
}
if (is_target_key) {
- return type == ui::ET_KEY_PRESSED ?
+ return event->type() == ui::ET_KEY_PRESSED ?
TARGET_MODIFIER_DOWN : TARGET_MODIFIER_UP;
}
- return type == ui::ET_KEY_PRESSED ?
+ return event->type() == ui::ET_KEY_PRESSED ?
OTHER_MODIFIER_DOWN : OTHER_MODIFIER_UP;
}
-bool StickyKeysHandler::HandleDisabledState(const ui::KeyEvent& event,
- ui::KeyboardCode key_code) {
- switch (TranslateKeyEvent(event.type(), key_code)) {
+bool StickyKeysHandler::HandleDisabledState(ui::KeyEvent* event) {
+ switch (TranslateKeyEvent(event)) {
case TARGET_MODIFIER_UP:
if (preparing_to_enable_) {
preparing_to_enable_ = false;
scroll_delta_ = 0;
current_state_ = STICKY_KEY_STATE_ENABLED;
- modifier_up_event_.reset(new ui::KeyEvent(event));
+ modifier_up_event_.reset(new ui::KeyEvent(*event));
return true;
}
return false;
@@ -373,23 +385,20 @@ bool StickyKeysHandler::HandleDisabledState(const ui::KeyEvent& event,
return false;
}
-bool StickyKeysHandler::HandleEnabledState(const ui::KeyEvent& event,
- ui::KeyboardCode key_code,
- int* mod_down_flags,
- bool* released) {
- switch (TranslateKeyEvent(event.type(), key_code)) {
+bool StickyKeysHandler::HandleEnabledState(ui::KeyEvent* event) {
+ switch (TranslateKeyEvent(event)) {
case NORMAL_KEY_UP:
case TARGET_MODIFIER_DOWN:
- return false;
+ return true;
case TARGET_MODIFIER_UP:
current_state_ = STICKY_KEY_STATE_LOCKED;
modifier_up_event_.reset();
return true;
case NORMAL_KEY_DOWN: {
current_state_ = STICKY_KEY_STATE_DISABLED;
- *mod_down_flags |= modifier_flag_;
- *released = true;
- return false;
+ AppendModifier(event);
+ DispatchEventAndReleaseModifier(event);
+ return true;
}
case OTHER_MODIFIER_DOWN:
case OTHER_MODIFIER_UP:
@@ -399,11 +408,8 @@ bool StickyKeysHandler::HandleEnabledState(const ui::KeyEvent& event,
return false;
}
-bool StickyKeysHandler::HandleLockedState(const ui::KeyEvent& event,
- ui::KeyboardCode key_code,
- int* mod_down_flags,
- bool* released) {
- switch (TranslateKeyEvent(event.type(), key_code)) {
+bool StickyKeysHandler::HandleLockedState(ui::KeyEvent* event) {
+ switch (TranslateKeyEvent(event)) {
case TARGET_MODIFIER_DOWN:
return true;
case TARGET_MODIFIER_UP:
@@ -411,7 +417,7 @@ bool StickyKeysHandler::HandleLockedState(const ui::KeyEvent& event,
return false;
case NORMAL_KEY_DOWN:
case NORMAL_KEY_UP:
- *mod_down_flags |= modifier_flag_;
+ AppendModifier(event);
return false;
case OTHER_MODIFIER_DOWN:
case OTHER_MODIFIER_UP:
@@ -421,4 +427,125 @@ bool StickyKeysHandler::HandleLockedState(const ui::KeyEvent& event,
return false;
}
+void StickyKeysHandler::DispatchEventAndReleaseModifier(ui::Event* event) {
+ DCHECK(event->IsKeyEvent() ||
+ event->IsMouseEvent() ||
+ event->IsScrollEvent());
+ DCHECK(modifier_up_event_.get());
+ aura::Window* target = static_cast<aura::Window*>(event->target());
+ DCHECK(target);
+ aura::Window* root_window = target->GetRootWindow();
+ DCHECK(root_window);
+
+ aura::WindowTracker window_tracker;
+ window_tracker.Add(target);
+
+ event_from_myself_ = true;
+ if (event->IsKeyEvent()) {
+ delegate_->DispatchKeyEvent(static_cast<ui::KeyEvent*>(event), target);
+ } else if (event->IsMouseEvent()) {
+ delegate_->DispatchMouseEvent(static_cast<ui::MouseEvent*>(event), target);
+ } else {
+ delegate_->DispatchScrollEvent(
+ static_cast<ui::ScrollEvent*>(event), target);
+ }
+
+ // The action triggered above may have destroyed the event target, in which
+ // case we will dispatch the modifier up event to the root window instead.
+ aura::Window* modifier_up_target =
+ window_tracker.Contains(target) ? target : root_window;
+ delegate_->DispatchKeyEvent(modifier_up_event_.get(), modifier_up_target);
+ event_from_myself_ = false;
+}
+
+void StickyKeysHandler::AppendNativeEventMask(unsigned int* state) {
+#if defined(USE_X11)
+ unsigned int& state_ref = *state;
+ switch (modifier_flag_) {
+ case ui::EF_CONTROL_DOWN:
+ state_ref |= ControlMask;
+ break;
+ case ui::EF_ALT_DOWN:
+ state_ref |= Mod1Mask;
+ break;
+ case ui::EF_ALTGR_DOWN:
+ state_ref |= Mod5Mask;
+ break;
+ case ui::EF_SHIFT_DOWN:
+ state_ref |= ShiftMask;
+ break;
+ case ui::EF_MOD3_DOWN:
+ state_ref |= Mod3Mask;
+ break;
+ default:
+ NOTREACHED();
+ }
+#endif
+}
+
+void StickyKeysHandler::AppendModifier(ui::KeyEvent* event) {
+#if defined(USE_X11)
+ XEvent* xev = event->native_event();
+ if (xev) {
+ XKeyEvent* xkey = &(xev->xkey);
+ AppendNativeEventMask(&xkey->state);
+ }
+#elif defined(USE_OZONE)
+ NOTIMPLEMENTED() << "Modifier key is not handled";
+#endif
+ event->set_flags(event->flags() | modifier_flag_);
+ event->set_character(ui::GetCharacterFromKeyCode(event->key_code(),
+ event->flags()));
+ event->NormalizeFlags();
+}
+
+void StickyKeysHandler::AppendModifier(ui::MouseEvent* event) {
+#if defined(USE_X11)
+ // The native mouse event can either be a classic X button event or an
+ // XInput2 button event.
+ XEvent* xev = event->native_event();
+ if (xev) {
+ switch (xev->type) {
+ case ButtonPress:
+ case ButtonRelease: {
+ XButtonEvent* xkey = &(xev->xbutton);
+ AppendNativeEventMask(&xkey->state);
+ break;
+ }
+ case GenericEvent: {
+ XIDeviceEvent* xievent =
+ static_cast<XIDeviceEvent*>(xev->xcookie.data);
+ CHECK(xievent->evtype == XI_ButtonPress ||
+ xievent->evtype == XI_ButtonRelease);
+ AppendNativeEventMask(
+ reinterpret_cast<unsigned int*>(&xievent->mods.effective));
+ break;
+ }
+ default:
+ NOTREACHED();
+ }
+ }
+#elif defined(USE_OZONE)
+ NOTIMPLEMENTED() << "Modifier key is not handled";
+#endif
+ event->set_flags(event->flags() | modifier_flag_);
+}
+
+void StickyKeysHandler::AppendModifier(ui::ScrollEvent* event) {
+#if defined(USE_X11)
+ XEvent* xev = event->native_event();
+ if (xev) {
+ XIDeviceEvent* xievent =
+ static_cast<XIDeviceEvent*>(xev->xcookie.data);
+ if (xievent) {
+ AppendNativeEventMask(reinterpret_cast<unsigned int*>(
+ &xievent->mods.effective));
+ }
+ }
+#elif defined(USE_OZONE)
+ NOTIMPLEMENTED() << "Modifier key is not handled";
+#endif
+ event->set_flags(event->flags() | modifier_flag_);
+}
+
} // namespace ash
diff --git a/ash/sticky_keys/sticky_keys_controller.h b/ash/sticky_keys/sticky_keys_controller.h
index fd5d389..89a196a 100644
--- a/ash/sticky_keys/sticky_keys_controller.h
+++ b/ash/sticky_keys/sticky_keys_controller.h
@@ -10,8 +10,6 @@
#include "base/memory/scoped_ptr.h"
#include "ui/events/event_constants.h"
#include "ui/events/event_handler.h"
-#include "ui/events/event_rewriter.h"
-#include "ui/events/keycodes/keyboard_codes.h"
namespace ui {
class Event;
@@ -61,7 +59,7 @@ class StickyKeysHandler;
// modifiers. Each handling or state is performed independently.
//
// StickyKeysController is disabled by default.
-class ASH_EXPORT StickyKeysController {
+class ASH_EXPORT StickyKeysController : public ui::EventHandler {
public:
StickyKeysController();
virtual ~StickyKeysController();
@@ -71,64 +69,24 @@ class ASH_EXPORT StickyKeysController {
void SetModifiersEnabled(bool mod3_enabled, bool altgr_enabled);
+ // Overridden from ui::EventHandler:
+ virtual void OnKeyEvent(ui::KeyEvent* event) OVERRIDE;
+ virtual void OnMouseEvent(ui::MouseEvent* event) OVERRIDE;
+ virtual void OnScrollEvent(ui::ScrollEvent* event) OVERRIDE;
+
// Returns the StickyKeyOverlay used by the controller. Ownership is not
// passed.
StickyKeysOverlay* GetOverlayForTest();
- // Handles keyboard event. Returns an |EventRewriteStatus|, and may
- // modify |flags|:
- // - Returns ui::EVENT_REWRITE_DISCARD, and leaves |flags| untouched,
- // if the event is consumed (i.e. a sticky modifier press or release);
- // - Returns ui::EVENT_REWRITE_REWRITTEN if the event needs to be modified
- // according to the returned |flags| (i.e. a sticky-modified key);
- // - Returns ui::EVENT_REWRITE_DISPATCH_ANOTHER if the event needs to be
- // modified according to the returned |flags|, and there are delayed
- // modifier-up events now to be retrieved using |NextDispatchEvent()|
- // (i.e. a sticky-modified key that ends a sticky state);
- // - Otherwise returns ui::EVENT_REWRITE_CONTINUE and leaves |flags|
- // unchanged.
- ui::EventRewriteStatus RewriteKeyEvent(const ui::KeyEvent& event,
- ui::KeyboardCode key_code,
- int* flags);
-
- // Handles mouse event.
- ui::EventRewriteStatus RewriteMouseEvent(const ui::MouseEvent& event,
- int* flags);
-
- // Handles scroll event.
- ui::EventRewriteStatus RewriteScrollEvent(const ui::ScrollEvent& event,
- int* flags);
-
- // Obtains a pending modifier-up event. If the immediately previous
- // call to |Rewrite...Event()| or |NextDispatchEvent()| returned
- // ui::EVENT_REWRITE_DISPATCH_ANOTHER, this sets |new_event| and returns:
- // - ui::EVENT_REWRITE_DISPATCH_ANOTHER if there is at least one more
- // pending modifier-up event;
- // - ui::EVENT_REWRITE_REWRITE if this is the last or only modifier-up event;
- // Otherwise, there is no pending modifier-up event, and this function
- // returns ui::EVENT_REWRITE_CONTINUE and sets |new_event| to NULL.
- ui::EventRewriteStatus NextDispatchEvent(scoped_ptr<ui::Event>* new_event);
-
private:
// Handles keyboard event. Returns true if Sticky key consumes keyboard event.
- // Adds to |mod_down_flags| any flag to be added to the key event.
- // Sets |released| if any modifier is to be released after the key event.
- bool HandleKeyEvent(const ui::KeyEvent& event,
- ui::KeyboardCode key_code,
- int* mod_down_flags,
- bool* released);
-
- // Handles mouse event. Returns true if Sticky key consumes keyboard event.
- // Sets |released| if any modifier is to be released after the key event.
- bool HandleMouseEvent(const ui::MouseEvent& event,
- int* mod_down_flags,
- bool* released);
-
- // Handles scroll event. Returns true if Sticky key consumes keyboard event.
- // Sets |released| if any modifier is to be released after the key event.
- bool HandleScrollEvent(const ui::ScrollEvent& event,
- int* mod_down_flags,
- bool* released);
+ bool HandleKeyEvent(ui::KeyEvent* event);
+
+ // Handles mouse event. Returns true if sticky key consumes mouse event.
+ bool HandleMouseEvent(ui::MouseEvent* event);
+
+ // Handles scroll event. Returns true if sticky key consumes scroll event.
+ bool HandleScrollEvent(ui::ScrollEvent* event);
// Updates the overlay UI with the current state of the sticky keys.
void UpdateOverlay();
@@ -185,35 +143,40 @@ class ASH_EXPORT StickyKeysController {
// is modified.
class ASH_EXPORT StickyKeysHandler {
public:
- explicit StickyKeysHandler(ui::EventFlags modifier_flag);
- ~StickyKeysHandler();
+ class StickyKeysHandlerDelegate {
+ public:
+ StickyKeysHandlerDelegate();
+ virtual ~StickyKeysHandlerDelegate();
+
+ // Dispatches keyboard event synchronously. |event| is an event that has
+ // been previously dispatched.
+ virtual void DispatchKeyEvent(ui::KeyEvent* event,
+ aura::Window* target) = 0;
+
+ // Dispatches mouse event synchronously. |event| is an event that has
+ // been previously dispatched.
+ virtual void DispatchMouseEvent(ui::MouseEvent* event,
+ aura::Window* target) = 0;
+
+ // Dispatches scroll event synchronously. |event| is an event that has
+ // been previously dispatched.
+ virtual void DispatchScrollEvent(ui::ScrollEvent* event,
+ aura::Window* target) = 0;
+ };
- // Handles keyboard event. Returns true if Sticky key consumes keyboard event.
- // Sets its own modifier flag in |mod_down_flags| if it is active and needs
- // to be added to the event, and sets |released| if releasing it.
- bool HandleKeyEvent(const ui::KeyEvent& event,
- ui::KeyboardCode key_code,
- int* mod_down_flags,
- bool* released);
+ // This class takes an ownership of |delegate|.
+ StickyKeysHandler(ui::EventFlags modifier_flag,
+ StickyKeysHandlerDelegate* delegate);
+ ~StickyKeysHandler();
- // Handles mouse event. Returns true if sticky key consumes mouse event.
- // Sets its own modifier flag in |mod_down_flags| if it is active and needs
- // to be added to the event, and sets |released| if releasing it.
- bool HandleMouseEvent(const ui::MouseEvent& event,
- int* mod_down_flags,
- bool* released);
+ // Handles key event. Returns true if key is consumed.
+ bool HandleKeyEvent(ui::KeyEvent* event);
- // Handles scroll event. Returns true if sticky key consumes scroll event.
- // Sets its own modifier flag in |mod_down_flags| if it is active and needs
- // to be added to the event, and sets |released| if releasing it.
- bool HandleScrollEvent(const ui::ScrollEvent& event,
- int* mod_down_flags,
- bool* released);
+ // Handles a mouse event. Returns true if mouse event is consumed.
+ bool HandleMouseEvent(ui::MouseEvent* event);
- // Fetches a pending modifier-up event if one exists and the return
- // parameter |new_event| is available (i.e. not set). Returns the number
- // of pending events still remaining to be returned.
- int GetModifierUpEvent(scoped_ptr<ui::Event>* new_event);
+ // Handles a scroll event. Returns true if scroll event is consumed.
+ bool HandleScrollEvent(ui::ScrollEvent* event);
// Returns current internal state.
StickyKeyState current_state() const { return current_state_; }
@@ -229,27 +192,31 @@ class ASH_EXPORT StickyKeysHandler {
OTHER_MODIFIER_UP, // The modifier key but not monitored key is up.
};
- // Translates event type and key code to sticky keys event type.
- KeyEventType TranslateKeyEvent(ui::EventType type, ui::KeyboardCode key_code);
+ // Translates |event| to sticky keys event type.
+ KeyEventType TranslateKeyEvent(ui::KeyEvent* event);
+
+ // Handles key event in DISABLED state.
+ bool HandleDisabledState(ui::KeyEvent* event);
- // Handles key event in DISABLED state. Returns true if sticky keys
- // consumes the keyboard event.
- bool HandleDisabledState(const ui::KeyEvent& event,
- ui::KeyboardCode key_code);
+ // Handles key event in ENABLED state.
+ bool HandleEnabledState(ui::KeyEvent* event);
- // Handles key event in ENABLED state. Returns true if sticky keys
- // consumes the keyboard event.
- bool HandleEnabledState(const ui::KeyEvent& event,
- ui::KeyboardCode key_code,
- int* mod_down_flags,
- bool* released);
+ // Handles key event in LOCKED state.
+ bool HandleLockedState(ui::KeyEvent* event);
- // Handles key event in LOCKED state. Returns true if sticky keys
- // consumes the keyboard event.
- bool HandleLockedState(const ui::KeyEvent& event,
- ui::KeyboardCode key_code,
- int* mod_down_flags,
- bool* released);
+ // Dispatches |event| to its target and then dispatch a key released event
+ // for the modifier key. This function is required to ensure that the events
+ // are sent in the correct order when disabling sticky key after a key/mouse
+ // button press.
+ void DispatchEventAndReleaseModifier(ui::Event* event);
+
+ // Adds |modifier_flags_| to a native X11 event state mask.
+ void AppendNativeEventMask(unsigned int* state);
+
+ // Adds |modifier_flags_| into |event|.
+ void AppendModifier(ui::KeyEvent* event);
+ void AppendModifier(ui::MouseEvent* event);
+ void AppendModifier(ui::ScrollEvent* event);
// The modifier flag to be monitored and appended to events.
const ui::EventFlags modifier_flag_;
@@ -257,6 +224,9 @@ class ASH_EXPORT StickyKeysHandler {
// The current sticky key status.
StickyKeyState current_state_;
+ // True if the received key event is sent by StickyKeyHandler.
+ bool event_from_myself_;
+
// True if we received the TARGET_MODIFIER_DOWN event while in the DISABLED
// state but before we receive the TARGET_MODIFIER_UP event. Normal
// shortcuts (eg. ctrl + t) during this time will prevent a transition to
@@ -271,6 +241,8 @@ class ASH_EXPORT StickyKeysHandler {
// The modifier up key event to be sent on non modifier key on ENABLED state.
scoped_ptr<ui::KeyEvent> modifier_up_event_;
+ scoped_ptr<StickyKeysHandlerDelegate> delegate_;
+
DISALLOW_COPY_AND_ASSIGN(StickyKeysHandler);
};
diff --git a/ash/sticky_keys/sticky_keys_overlay_unittest.cc b/ash/sticky_keys/sticky_keys_overlay_unittest.cc
index 0d6f161..678eff4 100644
--- a/ash/sticky_keys/sticky_keys_overlay_unittest.cc
+++ b/ash/sticky_keys/sticky_keys_overlay_unittest.cc
@@ -7,14 +7,47 @@
#include "ash/shell.h"
#include "ash/sticky_keys/sticky_keys_controller.h"
#include "ash/test/ash_test_base.h"
+#include "base/memory/scoped_ptr.h"
+#include "ui/aura/window_tree_host.h"
#include "ui/events/event.h"
+#include "ui/events/event_processor.h"
namespace ash {
class StickyKeysOverlayTest : public test::AshTestBase {
public:
- StickyKeysOverlayTest() {}
+ StickyKeysOverlayTest() :
+ controller_(NULL),
+ overlay_(NULL) {}
+
virtual ~StickyKeysOverlayTest() {}
+
+ virtual void SetUp() OVERRIDE {
+ test::AshTestBase::SetUp();
+
+ controller_ = Shell::GetInstance()->sticky_keys_controller();
+ controller_->Enable(true);
+ overlay_ = controller_->GetOverlayForTest();
+ ASSERT_TRUE(overlay_);
+ }
+
+ void PressAndReleaseKey(ui::KeyboardCode code) {
+ SendKeyEvent(ui::ET_KEY_PRESSED, code);
+ SendKeyEvent(ui::ET_KEY_RELEASED, code);
+ }
+
+ void SendKeyEvent(ui::EventType type, ui::KeyboardCode code) {
+ ui::KeyEvent event(type, code, 0, false);
+ ui::Event::DispatcherApi dispatcher(&event);
+ dispatcher.set_target(Shell::GetInstance()->GetPrimaryRootWindow());
+
+ ui::EventDispatchDetails details = Shell::GetPrimaryRootWindow()->
+ GetHost()->event_processor()->OnEventFromSource(&event);
+ CHECK(!details.dispatcher_destroyed);
+ }
+
+ StickyKeysController* controller_;
+ StickyKeysOverlay* overlay_;
};
TEST_F(StickyKeysOverlayTest, OverlayVisibility) {
@@ -38,7 +71,168 @@ TEST_F(StickyKeysOverlayTest, ModifierKeyState) {
overlay.GetModifierKeyState(ui::EF_CONTROL_DOWN));
}
-// Additional sticky key overlay tests that depend on chromeos::EventRewriter
-// are now in chrome/browser/chromeos/events/event_rewriter_unittest.cc .
+TEST_F(StickyKeysOverlayTest, OneModifierEnabled) {
+ EXPECT_FALSE(overlay_->is_visible());
+ EXPECT_EQ(STICKY_KEY_STATE_DISABLED,
+ overlay_->GetModifierKeyState(ui::EF_CONTROL_DOWN));
+
+ // Pressing modifier key should show overlay.
+ PressAndReleaseKey(ui::VKEY_CONTROL);
+ EXPECT_TRUE(overlay_->is_visible());
+ EXPECT_EQ(STICKY_KEY_STATE_ENABLED,
+ overlay_->GetModifierKeyState(ui::EF_CONTROL_DOWN));
+
+ // Pressing a normal key should hide overlay.
+ PressAndReleaseKey(ui::VKEY_T);
+ EXPECT_FALSE(overlay_->is_visible());
+ EXPECT_EQ(STICKY_KEY_STATE_DISABLED,
+ overlay_->GetModifierKeyState(ui::EF_CONTROL_DOWN));
+}
+
+TEST_F(StickyKeysOverlayTest, TwoModifiersEnabled) {
+ EXPECT_FALSE(overlay_->is_visible());
+ EXPECT_EQ(STICKY_KEY_STATE_DISABLED,
+ overlay_->GetModifierKeyState(ui::EF_CONTROL_DOWN));
+ EXPECT_EQ(STICKY_KEY_STATE_DISABLED,
+ overlay_->GetModifierKeyState(ui::EF_SHIFT_DOWN));
+
+ // Pressing two modifiers should show overlay.
+ PressAndReleaseKey(ui::VKEY_SHIFT);
+ PressAndReleaseKey(ui::VKEY_CONTROL);
+ EXPECT_TRUE(overlay_->is_visible());
+ EXPECT_EQ(STICKY_KEY_STATE_ENABLED,
+ overlay_->GetModifierKeyState(ui::EF_SHIFT_DOWN));
+ EXPECT_EQ(STICKY_KEY_STATE_ENABLED,
+ overlay_->GetModifierKeyState(ui::EF_CONTROL_DOWN));
+
+ // Pressing a normal key should hide overlay.
+ PressAndReleaseKey(ui::VKEY_N);
+ EXPECT_FALSE(overlay_->is_visible());
+ EXPECT_EQ(STICKY_KEY_STATE_DISABLED,
+ overlay_->GetModifierKeyState(ui::EF_CONTROL_DOWN));
+ EXPECT_EQ(STICKY_KEY_STATE_DISABLED,
+ overlay_->GetModifierKeyState(ui::EF_SHIFT_DOWN));
+}
+
+TEST_F(StickyKeysOverlayTest, LockedModifier) {
+ EXPECT_FALSE(overlay_->is_visible());
+ EXPECT_EQ(STICKY_KEY_STATE_DISABLED,
+ overlay_->GetModifierKeyState(ui::EF_ALT_DOWN));
+
+ // Pressing a modifier key twice should lock modifier and show overlay.
+ PressAndReleaseKey(ui::VKEY_LMENU);
+ PressAndReleaseKey(ui::VKEY_LMENU);
+ EXPECT_TRUE(overlay_->is_visible());
+ EXPECT_EQ(STICKY_KEY_STATE_LOCKED,
+ overlay_->GetModifierKeyState(ui::EF_ALT_DOWN));
+
+ // Pressing a normal key should not hide overlay.
+ PressAndReleaseKey(ui::VKEY_D);
+ EXPECT_TRUE(overlay_->is_visible());
+ EXPECT_EQ(STICKY_KEY_STATE_LOCKED,
+ overlay_->GetModifierKeyState(ui::EF_ALT_DOWN));
+}
+
+TEST_F(StickyKeysOverlayTest, LockedAndNormalModifier) {
+ EXPECT_FALSE(overlay_->is_visible());
+ EXPECT_EQ(STICKY_KEY_STATE_DISABLED,
+ overlay_->GetModifierKeyState(ui::EF_CONTROL_DOWN));
+ EXPECT_EQ(STICKY_KEY_STATE_DISABLED,
+ overlay_->GetModifierKeyState(ui::EF_SHIFT_DOWN));
+
+ // Pressing a modifier key twice should lock modifier and show overlay.
+ PressAndReleaseKey(ui::VKEY_CONTROL);
+ PressAndReleaseKey(ui::VKEY_CONTROL);
+ EXPECT_TRUE(overlay_->is_visible());
+ EXPECT_EQ(STICKY_KEY_STATE_LOCKED,
+ overlay_->GetModifierKeyState(ui::EF_CONTROL_DOWN));
+
+ // Pressing another modifier key should still show overlay.
+ PressAndReleaseKey(ui::VKEY_SHIFT);
+ EXPECT_TRUE(overlay_->is_visible());
+ EXPECT_EQ(STICKY_KEY_STATE_LOCKED,
+ overlay_->GetModifierKeyState(ui::EF_CONTROL_DOWN));
+ EXPECT_EQ(STICKY_KEY_STATE_ENABLED,
+ overlay_->GetModifierKeyState(ui::EF_SHIFT_DOWN));
+
+ // Pressing a normal key should not hide overlay but disable normal modifier.
+ PressAndReleaseKey(ui::VKEY_D);
+ EXPECT_TRUE(overlay_->is_visible());
+ EXPECT_EQ(STICKY_KEY_STATE_LOCKED,
+ overlay_->GetModifierKeyState(ui::EF_CONTROL_DOWN));
+ EXPECT_EQ(STICKY_KEY_STATE_DISABLED,
+ overlay_->GetModifierKeyState(ui::EF_SHIFT_DOWN));
+}
+
+TEST_F(StickyKeysOverlayTest, ModifiersDisabled) {
+ EXPECT_FALSE(overlay_->is_visible());
+ EXPECT_EQ(STICKY_KEY_STATE_DISABLED,
+ overlay_->GetModifierKeyState(ui::EF_CONTROL_DOWN));
+ EXPECT_EQ(STICKY_KEY_STATE_DISABLED,
+ overlay_->GetModifierKeyState(ui::EF_SHIFT_DOWN));
+ EXPECT_EQ(STICKY_KEY_STATE_DISABLED,
+ overlay_->GetModifierKeyState(ui::EF_ALT_DOWN));
+
+ // Enable modifiers.
+ PressAndReleaseKey(ui::VKEY_CONTROL);
+ PressAndReleaseKey(ui::VKEY_SHIFT);
+ PressAndReleaseKey(ui::VKEY_SHIFT);
+ PressAndReleaseKey(ui::VKEY_LMENU);
+
+ EXPECT_TRUE(overlay_->is_visible());
+ EXPECT_EQ(STICKY_KEY_STATE_ENABLED,
+ overlay_->GetModifierKeyState(ui::EF_CONTROL_DOWN));
+ EXPECT_EQ(STICKY_KEY_STATE_LOCKED,
+ overlay_->GetModifierKeyState(ui::EF_SHIFT_DOWN));
+ EXPECT_EQ(STICKY_KEY_STATE_ENABLED,
+ overlay_->GetModifierKeyState(ui::EF_ALT_DOWN));
+
+ // Disable modifiers and overlay should be hidden.
+ PressAndReleaseKey(ui::VKEY_CONTROL);
+ PressAndReleaseKey(ui::VKEY_CONTROL);
+ PressAndReleaseKey(ui::VKEY_SHIFT);
+ PressAndReleaseKey(ui::VKEY_LMENU);
+ PressAndReleaseKey(ui::VKEY_LMENU);
+
+ EXPECT_FALSE(overlay_->is_visible());
+ EXPECT_EQ(STICKY_KEY_STATE_DISABLED,
+ overlay_->GetModifierKeyState(ui::EF_CONTROL_DOWN));
+ EXPECT_EQ(STICKY_KEY_STATE_DISABLED,
+ overlay_->GetModifierKeyState(ui::EF_SHIFT_DOWN));
+ EXPECT_EQ(STICKY_KEY_STATE_DISABLED,
+ overlay_->GetModifierKeyState(ui::EF_ALT_DOWN));
+}
+
+TEST_F(StickyKeysOverlayTest, ModifierVisibility) {
+ // All but AltGr and Mod3 should initially be visible.
+ EXPECT_TRUE(overlay_->GetModifierVisible(ui::EF_CONTROL_DOWN));
+ EXPECT_TRUE(overlay_->GetModifierVisible(ui::EF_SHIFT_DOWN));
+ EXPECT_TRUE(overlay_->GetModifierVisible(ui::EF_ALT_DOWN));
+ EXPECT_FALSE(overlay_->GetModifierVisible(ui::EF_ALTGR_DOWN));
+ EXPECT_FALSE(overlay_->GetModifierVisible(ui::EF_MOD3_DOWN));
+
+ // Turn all modifiers on.
+ controller_->SetModifiersEnabled(true, true);
+ EXPECT_TRUE(overlay_->GetModifierVisible(ui::EF_CONTROL_DOWN));
+ EXPECT_TRUE(overlay_->GetModifierVisible(ui::EF_SHIFT_DOWN));
+ EXPECT_TRUE(overlay_->GetModifierVisible(ui::EF_ALT_DOWN));
+ EXPECT_TRUE(overlay_->GetModifierVisible(ui::EF_ALTGR_DOWN));
+ EXPECT_TRUE(overlay_->GetModifierVisible(ui::EF_MOD3_DOWN));
+
+ // Turn off Mod3.
+ controller_->SetModifiersEnabled(false, true);
+ EXPECT_TRUE(overlay_->GetModifierVisible(ui::EF_ALTGR_DOWN));
+ EXPECT_FALSE(overlay_->GetModifierVisible(ui::EF_MOD3_DOWN));
+
+ // Turn off AltGr.
+ controller_->SetModifiersEnabled(true, false);
+ EXPECT_FALSE(overlay_->GetModifierVisible(ui::EF_ALTGR_DOWN));
+ EXPECT_TRUE(overlay_->GetModifierVisible(ui::EF_MOD3_DOWN));
+
+ // Turn off AltGr and Mod3.
+ controller_->SetModifiersEnabled(false, false);
+ EXPECT_FALSE(overlay_->GetModifierVisible(ui::EF_ALTGR_DOWN));
+ EXPECT_FALSE(overlay_->GetModifierVisible(ui::EF_MOD3_DOWN));
+}
} // namespace ash
diff --git a/ash/sticky_keys/sticky_keys_unittest.cc b/ash/sticky_keys/sticky_keys_unittest.cc
index c164923..4c505e1 100644
--- a/ash/sticky_keys/sticky_keys_unittest.cc
+++ b/ash/sticky_keys/sticky_keys_unittest.cc
@@ -16,7 +16,8 @@
#include "base/memory/scoped_vector.h"
#include "ui/aura/window.h"
#include "ui/aura/window_tree_host.h"
-#include "ui/events/event_source.h"
+#include "ui/events/event_handler.h"
+#include "ui/events/event_processor.h"
#include "ui/events/test/events_test_utils_x11.h"
#include "ui/events/x/device_data_manager.h"
@@ -29,7 +30,107 @@ const unsigned int kTouchPadDeviceId = 1;
} // namespace
-class StickyKeysTest : public test::AshTestBase {
+// Keeps a buffer of handled events.
+class EventBuffer : public ui::EventHandler {
+ public:
+ EventBuffer() {}
+ virtual ~EventBuffer() {}
+
+ void PopEvents(ScopedVector<ui::Event>* events) {
+ events->clear();
+ events->swap(events_);
+ }
+
+ private:
+ // ui::EventHandler overrides:
+ virtual void OnKeyEvent(ui::KeyEvent* event) OVERRIDE {
+ events_.push_back(new ui::KeyEvent(*event));
+ }
+
+ virtual void OnMouseEvent(ui::MouseEvent* event) OVERRIDE {
+ if (event->IsMouseWheelEvent()) {
+ events_.push_back(
+ new ui::MouseWheelEvent(*static_cast<ui::MouseWheelEvent*>(event)));
+ } else {
+ events_.push_back(new ui::MouseEvent(*event));
+ }
+ }
+
+ ScopedVector<ui::Event> events_;
+
+ DISALLOW_COPY_AND_ASSIGN(EventBuffer);
+};
+
+// A testable and StickyKeysHandler.
+class MockStickyKeysHandlerDelegate :
+ public StickyKeysHandler::StickyKeysHandlerDelegate {
+ public:
+ class Delegate {
+ public:
+ virtual aura::Window* GetExpectedTarget() = 0;
+ virtual void OnShortcutPressed() = 0;
+
+ protected:
+ virtual ~Delegate() {}
+ };
+
+ MockStickyKeysHandlerDelegate(Delegate* delegate) : delegate_(delegate) {}
+
+ virtual ~MockStickyKeysHandlerDelegate() {}
+
+ // StickyKeysHandler override.
+ virtual void DispatchKeyEvent(ui::KeyEvent* event,
+ aura::Window* target) OVERRIDE {
+ ASSERT_EQ(delegate_->GetExpectedTarget(), target);
+
+ // Detect a special shortcut when it is dispatched. This shortcut will
+ // not be hit in the LOCKED state as this case does not involve the
+ // delegate.
+ if (event->type() == ui::ET_KEY_PRESSED &&
+ event->key_code() == ui::VKEY_J &&
+ event->flags() | ui::EF_CONTROL_DOWN) {
+ delegate_->OnShortcutPressed();
+ }
+
+ events_.push_back(new ui::KeyEvent(*event));
+ }
+
+ virtual void DispatchMouseEvent(ui::MouseEvent* event,
+ aura::Window* target) OVERRIDE {
+ ASSERT_EQ(delegate_->GetExpectedTarget(), target);
+ events_.push_back(
+ new ui::MouseEvent(*event, target, target->GetRootWindow()));
+ }
+
+ virtual void DispatchScrollEvent(ui::ScrollEvent* event,
+ aura::Window* target) OVERRIDE {
+ events_.push_back(new ui::ScrollEvent(event->native_event()));
+ }
+
+ // Returns the count of dispatched events.
+ size_t GetEventCount() const {
+ return events_.size();
+ }
+
+ // Returns the |index|-th dispatched event.
+ const ui::Event* GetEvent(size_t index) const {
+ return events_[index];
+ }
+
+ // Clears all previously dispatched events.
+ void ClearEvents() {
+ events_.clear();
+ }
+
+ private:
+ ScopedVector<ui::Event> events_;
+ Delegate* delegate_;
+
+ DISALLOW_COPY_AND_ASSIGN(MockStickyKeysHandlerDelegate);
+};
+
+class StickyKeysTest : public test::AshTestBase,
+ public MockStickyKeysHandlerDelegate::Delegate {
protected:
StickyKeysTest()
: target_(NULL),
@@ -50,35 +151,47 @@ class StickyKeysTest : public test::AshTestBase {
test::AshTestBase::TearDown();
}
- virtual void OnShortcutPressed() {
+ // Overridden from MockStickyKeysHandlerDelegate::Delegate:
+ virtual aura::Window* GetExpectedTarget() OVERRIDE {
+ return target_ ? target_ : root_window_;
+ }
+
+ virtual void OnShortcutPressed() OVERRIDE {
if (target_) {
delete target_;
target_ = NULL;
}
}
- ui::KeyEvent* GenerateKey(ui::EventType type, ui::KeyboardCode code) {
- scoped_xevent_.InitKeyEvent(type, code, 0);
- ui::KeyEvent* event = new ui::KeyEvent(scoped_xevent_, false);
+ ui::KeyEvent* GenerateKey(bool is_key_press, ui::KeyboardCode code) {
+ scoped_xevent_.InitKeyEvent(
+ is_key_press ? ui::ET_KEY_PRESSED : ui::ET_KEY_RELEASED,
+ code,
+ 0);
+ ui::KeyEvent* event = new ui::KeyEvent(scoped_xevent_, false);
+ ui::Event::DispatcherApi dispatcher(event);
+ dispatcher.set_target(target_);
return event;
}
// Creates a mouse event backed by a native XInput2 generic button event.
// This is the standard native event on Chromebooks.
- ui::MouseEvent* GenerateMouseEvent(ui::EventType type) {
- return GenerateMouseEventAt(type, gfx::Point());
+ ui::MouseEvent* GenerateMouseEvent(bool is_button_press) {
+ return GenerateMouseEventAt(is_button_press, gfx::Point());
}
// Creates a mouse event backed by a native XInput2 generic button event.
// The |location| should be in physical pixels.
- ui::MouseEvent* GenerateMouseEventAt(ui::EventType type,
+ ui::MouseEvent* GenerateMouseEventAt(bool is_button_press,
const gfx::Point& location) {
scoped_xevent_.InitGenericButtonEvent(
kTouchPadDeviceId,
- type,
+ is_button_press ? ui::ET_MOUSE_PRESSED : ui::ET_MOUSE_RELEASED,
location,
0);
ui::MouseEvent* event = new ui::MouseEvent(scoped_xevent_);
+ ui::Event::DispatcherApi dispatcher(event);
+ dispatcher.set_target(target_);
return event;
}
@@ -121,9 +234,14 @@ class StickyKeysTest : public test::AshTestBase {
}
// Creates a synthesized KeyEvent that is not backed by a native event.
- ui::KeyEvent* GenerateSynthesizedKeyEvent(ui::EventType type,
- ui::KeyboardCode code) {
- return new ui::KeyEvent(type, code, 0, true);
+ ui::KeyEvent* GenerateSynthesizedKeyEvent(
+ bool is_key_press, ui::KeyboardCode code) {
+ ui::KeyEvent* event = new ui::KeyEvent(
+ is_key_press ? ui::ET_KEY_PRESSED : ui::ET_MOUSE_RELEASED,
+ code, 0, true);
+ ui::Event::DispatcherApi dispatcher(event);
+ dispatcher.set_target(target_);
+ return event;
}
// Creates a synthesized MouseEvent that is not backed by a native event.
@@ -141,9 +259,11 @@ class StickyKeysTest : public test::AshTestBase {
// Creates a synthesized mouse press or release event.
ui::MouseEvent* GenerateSynthesizedMouseClickEvent(
- ui::EventType type,
+ bool is_button_press,
const gfx::Point& location) {
- return GenerateSynthesizedMouseEventAt(type, location);
+ return GenerateSynthesizedMouseEventAt(
+ is_button_press ? ui::ET_MOUSE_PRESSED : ui::ET_MOUSE_RELEASED,
+ location);
}
// Creates a synthesized ET_MOUSE_MOVED event.
@@ -164,28 +284,22 @@ class StickyKeysTest : public test::AshTestBase {
void SendActivateStickyKeyPattern(StickyKeysHandler* handler,
ui::KeyboardCode key_code) {
- bool released = false;
- int down_flags = 0;
scoped_ptr<ui::KeyEvent> ev;
- ev.reset(GenerateKey(ui::ET_KEY_PRESSED, key_code));
- handler->HandleKeyEvent(*ev.get(), key_code, &down_flags, &released);
- ev.reset(GenerateKey(ui::ET_KEY_RELEASED, key_code));
- handler->HandleKeyEvent(*ev.get(), key_code, &down_flags, &released);
- }
-
- bool HandleKeyEvent(const ui::KeyEvent& key_event,
- StickyKeysHandler* handler,
- int* down,
- bool* up) {
- return handler->HandleKeyEvent(key_event, key_event.key_code(), down, up);
+ ev.reset(GenerateKey(true, key_code));
+ handler->HandleKeyEvent(ev.get());
+ ev.reset(GenerateKey(false, key_code));
+ handler->HandleKeyEvent(ev.get());
}
- int HandleKeyEventForDownFlags(const ui::KeyEvent& key_event,
- StickyKeysHandler* handler) {
- bool released = false;
- int down = 0;
- handler->HandleKeyEvent(key_event, key_event.key_code(), &down, &released);
- return down;
+ void SendActivateStickyKeyPattern(ui::EventProcessor* dispatcher,
+ ui::KeyboardCode key_code) {
+ scoped_ptr<ui::KeyEvent> ev;
+ ev.reset(GenerateKey(true, key_code));
+ ui::EventDispatchDetails details = dispatcher->OnEventFromSource(ev.get());
+ CHECK(!details.dispatcher_destroyed);
+ ev.reset(GenerateKey(false, key_code));
+ details = dispatcher->OnEventFromSource(ev.get());
+ CHECK(!details.dispatcher_destroyed);
}
aura::Window* target() { return target_; }
@@ -204,7 +318,9 @@ class StickyKeysTest : public test::AshTestBase {
TEST_F(StickyKeysTest, BasicOneshotScenarioTest) {
scoped_ptr<ui::KeyEvent> ev;
- StickyKeysHandler sticky_key(ui::EF_SHIFT_DOWN);
+ MockStickyKeysHandlerDelegate* mock_delegate =
+ new MockStickyKeysHandlerDelegate(this);
+ StickyKeysHandler sticky_key(ui::EF_SHIFT_DOWN, mock_delegate);
EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
@@ -212,42 +328,42 @@ TEST_F(StickyKeysTest, BasicOneshotScenarioTest) {
SendActivateStickyKeyPattern(&sticky_key, ui::VKEY_SHIFT);
EXPECT_EQ(STICKY_KEY_STATE_ENABLED, sticky_key.current_state());
- ev.reset(GenerateKey(ui::ET_KEY_PRESSED, ui::VKEY_A));
- bool released = false;
- int mod_down_flags = 0;
- HandleKeyEvent(*ev.get(), &sticky_key, &mod_down_flags, &released);
+ ev.reset(GenerateKey(true, ui::VKEY_A));
+ sticky_key.HandleKeyEvent(ev.get());
+
// Next keyboard event is shift modified.
- EXPECT_TRUE(mod_down_flags & ui::EF_SHIFT_DOWN);
- // Modifier release notification happens.
- EXPECT_TRUE(released);
+ EXPECT_TRUE(ev->flags() & ui::EF_SHIFT_DOWN);
- ev.reset(GenerateKey(ui::ET_KEY_RELEASED, ui::VKEY_A));
- released = false;
- mod_down_flags = 0;
- HandleKeyEvent(*ev.get(), &sticky_key, &mod_down_flags, &released);
+ ev.reset(GenerateKey(false, ui::VKEY_A));
+ sticky_key.HandleKeyEvent(ev.get());
EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
- // Making sure Shift up keyboard event is available.
- scoped_ptr<ui::Event> up_event;
- ASSERT_EQ(0, sticky_key.GetModifierUpEvent(&up_event));
- EXPECT_TRUE(up_event.get());
- EXPECT_EQ(ui::ET_KEY_RELEASED, up_event->type());
+ // Making sure Shift up keyboard event is dispatched.
+ ASSERT_EQ(2U, mock_delegate->GetEventCount());
+ EXPECT_EQ(ui::ET_KEY_PRESSED, mock_delegate->GetEvent(0)->type());
+ EXPECT_EQ(ui::VKEY_A,
+ static_cast<const ui::KeyEvent*>(mock_delegate->GetEvent(0))
+ ->key_code());
+ EXPECT_EQ(ui::ET_KEY_RELEASED, mock_delegate->GetEvent(1)->type());
EXPECT_EQ(ui::VKEY_SHIFT,
- static_cast<const ui::KeyEvent*>(up_event.get())->key_code());
+ static_cast<const ui::KeyEvent*>(mock_delegate->GetEvent(1))
+ ->key_code());
// Enabled state is one shot, so next key event should not be shift modified.
- ev.reset(GenerateKey(ui::ET_KEY_PRESSED, ui::VKEY_A));
- mod_down_flags = HandleKeyEventForDownFlags(*ev.get(), &sticky_key);
- EXPECT_FALSE(mod_down_flags & ui::EF_SHIFT_DOWN);
+ ev.reset(GenerateKey(true, ui::VKEY_A));
+ sticky_key.HandleKeyEvent(ev.get());
+ EXPECT_FALSE(ev->flags() & ui::EF_SHIFT_DOWN);
- ev.reset(GenerateKey(ui::ET_KEY_RELEASED, ui::VKEY_A));
- mod_down_flags = HandleKeyEventForDownFlags(*ev.get(), &sticky_key);
- EXPECT_FALSE(mod_down_flags & ui::EF_SHIFT_DOWN);
+ ev.reset(GenerateKey(false, ui::VKEY_A));
+ sticky_key.HandleKeyEvent(ev.get());
+ EXPECT_FALSE(ev->flags() & ui::EF_SHIFT_DOWN);
}
TEST_F(StickyKeysTest, BasicLockedScenarioTest) {
scoped_ptr<ui::KeyEvent> ev;
- StickyKeysHandler sticky_key(ui::EF_SHIFT_DOWN);
+ MockStickyKeysHandlerDelegate* mock_delegate =
+ new MockStickyKeysHandlerDelegate(this);
+ StickyKeysHandler sticky_key(ui::EF_SHIFT_DOWN, mock_delegate);
EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
@@ -260,24 +376,24 @@ TEST_F(StickyKeysTest, BasicLockedScenarioTest) {
EXPECT_EQ(STICKY_KEY_STATE_LOCKED, sticky_key.current_state());
// All keyboard events including keyUp become shift modified.
- ev.reset(GenerateKey(ui::ET_KEY_PRESSED, ui::VKEY_A));
- int mod_down_flags = HandleKeyEventForDownFlags(*ev.get(), &sticky_key);
- EXPECT_TRUE(mod_down_flags & ui::EF_SHIFT_DOWN);
+ ev.reset(GenerateKey(true, ui::VKEY_A));
+ sticky_key.HandleKeyEvent(ev.get());
+ EXPECT_TRUE(ev->flags() & ui::EF_SHIFT_DOWN);
- ev.reset(GenerateKey(ui::ET_KEY_RELEASED, ui::VKEY_A));
- mod_down_flags = HandleKeyEventForDownFlags(*ev.get(), &sticky_key);
- EXPECT_TRUE(mod_down_flags & ui::EF_SHIFT_DOWN);
+ ev.reset(GenerateKey(false, ui::VKEY_A));
+ sticky_key.HandleKeyEvent(ev.get());
+ EXPECT_TRUE(ev->flags() & ui::EF_SHIFT_DOWN);
// Locked state keeps after normal keyboard event.
EXPECT_EQ(STICKY_KEY_STATE_LOCKED, sticky_key.current_state());
- ev.reset(GenerateKey(ui::ET_KEY_PRESSED, ui::VKEY_B));
- mod_down_flags = HandleKeyEventForDownFlags(*ev.get(), &sticky_key);
- EXPECT_TRUE(mod_down_flags & ui::EF_SHIFT_DOWN);
+ ev.reset(GenerateKey(true, ui::VKEY_B));
+ sticky_key.HandleKeyEvent(ev.get());
+ EXPECT_TRUE(ev->flags() & ui::EF_SHIFT_DOWN);
- ev.reset(GenerateKey(ui::ET_KEY_RELEASED, ui::VKEY_B));
- mod_down_flags = HandleKeyEventForDownFlags(*ev.get(), &sticky_key);
- EXPECT_TRUE(mod_down_flags & ui::EF_SHIFT_DOWN);
+ ev.reset(GenerateKey(false, ui::VKEY_B));
+ sticky_key.HandleKeyEvent(ev.get());
+ EXPECT_TRUE(ev->flags() & ui::EF_SHIFT_DOWN);
EXPECT_EQ(STICKY_KEY_STATE_LOCKED, sticky_key.current_state());
@@ -288,163 +404,146 @@ TEST_F(StickyKeysTest, BasicLockedScenarioTest) {
TEST_F(StickyKeysTest, NonTargetModifierTest) {
scoped_ptr<ui::KeyEvent> ev;
- StickyKeysHandler sticky_key(ui::EF_SHIFT_DOWN);
+ MockStickyKeysHandlerDelegate* mock_delegate =
+ new MockStickyKeysHandlerDelegate(this);
+ StickyKeysHandler sticky_key(ui::EF_SHIFT_DOWN, mock_delegate);
EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
// Non target modifier key does not affect internal state
- ev.reset(GenerateKey(ui::ET_KEY_PRESSED, ui::VKEY_MENU));
- int mod_down_flags = HandleKeyEventForDownFlags(*ev.get(), &sticky_key);
+ ev.reset(GenerateKey(true, ui::VKEY_MENU));
+ sticky_key.HandleKeyEvent(ev.get());
EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
- EXPECT_EQ(ui::EF_NONE, mod_down_flags);
- ev.reset(GenerateKey(ui::ET_KEY_RELEASED, ui::VKEY_MENU));
- mod_down_flags = HandleKeyEventForDownFlags(*ev.get(), &sticky_key);
+ ev.reset(GenerateKey(false, ui::VKEY_MENU));
+ sticky_key.HandleKeyEvent(ev.get());
EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
- EXPECT_EQ(ui::EF_NONE, mod_down_flags);
SendActivateStickyKeyPattern(&sticky_key, ui::VKEY_SHIFT);
EXPECT_EQ(STICKY_KEY_STATE_ENABLED, sticky_key.current_state());
// Non target modifier key does not affect internal state
- ev.reset(GenerateKey(ui::ET_KEY_PRESSED, ui::VKEY_MENU));
- mod_down_flags = HandleKeyEventForDownFlags(*ev.get(), &sticky_key);
+ ev.reset(GenerateKey(true, ui::VKEY_MENU));
+ sticky_key.HandleKeyEvent(ev.get());
EXPECT_EQ(STICKY_KEY_STATE_ENABLED, sticky_key.current_state());
- EXPECT_EQ(ui::EF_NONE, mod_down_flags);
- ev.reset(GenerateKey(ui::ET_KEY_RELEASED, ui::VKEY_MENU));
- mod_down_flags = HandleKeyEventForDownFlags(*ev.get(), &sticky_key);
+ ev.reset(GenerateKey(false, ui::VKEY_MENU));
+ sticky_key.HandleKeyEvent(ev.get());
EXPECT_EQ(STICKY_KEY_STATE_ENABLED, sticky_key.current_state());
- EXPECT_EQ(ui::EF_NONE, mod_down_flags);
SendActivateStickyKeyPattern(&sticky_key, ui::VKEY_SHIFT);
EXPECT_EQ(STICKY_KEY_STATE_LOCKED, sticky_key.current_state());
// Non target modifier key does not affect internal state
- ev.reset(GenerateKey(ui::ET_KEY_PRESSED, ui::VKEY_MENU));
- mod_down_flags = HandleKeyEventForDownFlags(*ev.get(), &sticky_key);
+ ev.reset(GenerateKey(true, ui::VKEY_MENU));
+ sticky_key.HandleKeyEvent(ev.get());
EXPECT_EQ(STICKY_KEY_STATE_LOCKED, sticky_key.current_state());
- EXPECT_EQ(ui::EF_NONE, mod_down_flags);
- ev.reset(GenerateKey(ui::ET_KEY_RELEASED, ui::VKEY_MENU));
- mod_down_flags = HandleKeyEventForDownFlags(*ev.get(), &sticky_key);
+ ev.reset(GenerateKey(false, ui::VKEY_MENU));
+ sticky_key.HandleKeyEvent(ev.get());
EXPECT_EQ(STICKY_KEY_STATE_LOCKED, sticky_key.current_state());
- EXPECT_EQ(ui::EF_NONE, mod_down_flags);
}
TEST_F(StickyKeysTest, NormalShortcutTest) {
// Sticky keys should not be enabled if we perform a normal shortcut.
scoped_ptr<ui::KeyEvent> ev;
- StickyKeysHandler sticky_key(ui::EF_CONTROL_DOWN);
+ MockStickyKeysHandlerDelegate* mock_delegate =
+ new MockStickyKeysHandlerDelegate(this);
+ StickyKeysHandler sticky_key(ui::EF_CONTROL_DOWN, mock_delegate);
EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
// Perform ctrl+n shortcut.
- ev.reset(GenerateKey(ui::ET_KEY_PRESSED, ui::VKEY_CONTROL));
- int mod_down_flags = HandleKeyEventForDownFlags(*ev.get(), &sticky_key);
- ev.reset(GenerateKey(ui::ET_KEY_PRESSED, ui::VKEY_N));
- mod_down_flags = HandleKeyEventForDownFlags(*ev.get(), &sticky_key);
- ev.reset(GenerateKey(ui::ET_KEY_RELEASED, ui::VKEY_N));
- mod_down_flags = HandleKeyEventForDownFlags(*ev.get(), &sticky_key);
- EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
- ev.reset(GenerateKey(ui::ET_KEY_RELEASED, ui::VKEY_CONTROL));
- mod_down_flags = HandleKeyEventForDownFlags(*ev.get(), &sticky_key);
-
- // Sticky keys should not be enabled afterwards.
- EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
- EXPECT_EQ(ui::EF_NONE, mod_down_flags);
-
- // Perform ctrl+n shortcut, releasing ctrl first.
- ev.reset(GenerateKey(ui::ET_KEY_PRESSED, ui::VKEY_CONTROL));
- mod_down_flags = HandleKeyEventForDownFlags(*ev.get(), &sticky_key);
- ev.reset(GenerateKey(ui::ET_KEY_PRESSED, ui::VKEY_N));
- mod_down_flags = HandleKeyEventForDownFlags(*ev.get(), &sticky_key);
+ ev.reset(GenerateKey(true, ui::VKEY_CONTROL));
+ sticky_key.HandleKeyEvent(ev.get());
+ ev.reset(GenerateKey(true, ui::VKEY_N));
+ sticky_key.HandleKeyEvent(ev.get());
+ ev.reset(GenerateKey(false, ui::VKEY_N));
+ sticky_key.HandleKeyEvent(ev.get());
EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
- ev.reset(GenerateKey(ui::ET_KEY_RELEASED, ui::VKEY_CONTROL));
- mod_down_flags = HandleKeyEventForDownFlags(*ev.get(), &sticky_key);
- ev.reset(GenerateKey(ui::ET_KEY_RELEASED, ui::VKEY_N));
- mod_down_flags = HandleKeyEventForDownFlags(*ev.get(), &sticky_key);
// Sticky keys should not be enabled afterwards.
+ ev.reset(GenerateKey(false, ui::VKEY_CONTROL));
+ sticky_key.HandleKeyEvent(ev.get());
EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
- EXPECT_EQ(ui::EF_NONE, mod_down_flags);
}
TEST_F(StickyKeysTest, NormalModifiedClickTest) {
scoped_ptr<ui::KeyEvent> kev;
scoped_ptr<ui::MouseEvent> mev;
- StickyKeysHandler sticky_key(ui::EF_CONTROL_DOWN);
+ MockStickyKeysHandlerDelegate* mock_delegate =
+ new MockStickyKeysHandlerDelegate(this);
+ StickyKeysHandler sticky_key(ui::EF_CONTROL_DOWN, mock_delegate);
EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
// Perform ctrl+click.
- kev.reset(GenerateKey(ui::ET_KEY_PRESSED, ui::VKEY_CONTROL));
- int mod_down_flags = HandleKeyEventForDownFlags(*kev.get(), &sticky_key);
- mev.reset(GenerateMouseEvent(ui::ET_MOUSE_PRESSED));
- bool released = false;
- sticky_key.HandleMouseEvent(*mev.get(), &mod_down_flags, &released);
- mev.reset(GenerateMouseEvent(ui::ET_MOUSE_RELEASED));
- sticky_key.HandleMouseEvent(*mev.get(), &mod_down_flags, &released);
+ kev.reset(GenerateKey(true, ui::VKEY_CONTROL));
+ sticky_key.HandleKeyEvent(kev.get());
+ mev.reset(GenerateMouseEvent(true));
+ sticky_key.HandleMouseEvent(mev.get());
+ mev.reset(GenerateMouseEvent(false));
+ sticky_key.HandleMouseEvent(mev.get());
// Sticky keys should not be enabled afterwards.
- kev.reset(GenerateKey(ui::ET_KEY_RELEASED, ui::VKEY_CONTROL));
- mod_down_flags = HandleKeyEventForDownFlags(*kev.get(), &sticky_key);
+ kev.reset(GenerateKey(false, ui::VKEY_CONTROL));
+ sticky_key.HandleKeyEvent(kev.get());
EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
- EXPECT_EQ(ui::EF_NONE, mod_down_flags);
}
TEST_F(StickyKeysTest, MouseMovedModifierTest) {
scoped_ptr<ui::KeyEvent> kev;
scoped_ptr<ui::MouseEvent> mev;
- StickyKeysHandler sticky_key(ui::EF_CONTROL_DOWN);
+ MockStickyKeysHandlerDelegate* mock_delegate =
+ new MockStickyKeysHandlerDelegate(this);
+ StickyKeysHandler sticky_key(ui::EF_CONTROL_DOWN, mock_delegate);
EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
// Press ctrl and handle mouse move events.
- kev.reset(GenerateKey(ui::ET_KEY_PRESSED, ui::VKEY_CONTROL));
- int mod_down_flags = HandleKeyEventForDownFlags(*kev.get(), &sticky_key);
+ kev.reset(GenerateKey(true, ui::VKEY_CONTROL));
+ sticky_key.HandleKeyEvent(kev.get());
mev.reset(GenerateSynthesizedMouseMoveEvent(gfx::Point(0, 0)));
- bool released = false;
- sticky_key.HandleMouseEvent(*mev.get(), &mod_down_flags, &released);
+ sticky_key.HandleMouseEvent(mev.get());
mev.reset(GenerateSynthesizedMouseMoveEvent(gfx::Point(100, 100)));
- sticky_key.HandleMouseEvent(*mev.get(), &mod_down_flags, &released);
+ sticky_key.HandleMouseEvent(mev.get());
// Sticky keys should be enabled afterwards.
- kev.reset(GenerateKey(ui::ET_KEY_RELEASED, ui::VKEY_CONTROL));
- mod_down_flags = HandleKeyEventForDownFlags(*kev.get(), &sticky_key);
+ kev.reset(GenerateKey(false, ui::VKEY_CONTROL));
+ sticky_key.HandleKeyEvent(kev.get());
EXPECT_EQ(STICKY_KEY_STATE_ENABLED, sticky_key.current_state());
- EXPECT_EQ(ui::EF_NONE, mod_down_flags);
}
TEST_F(StickyKeysTest, NormalModifiedScrollTest) {
scoped_ptr<ui::KeyEvent> kev;
scoped_ptr<ui::ScrollEvent> sev;
- StickyKeysHandler sticky_key(ui::EF_CONTROL_DOWN);
+ MockStickyKeysHandlerDelegate* mock_delegate =
+ new MockStickyKeysHandlerDelegate(this);
+ StickyKeysHandler sticky_key(ui::EF_CONTROL_DOWN, mock_delegate);
EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
// Perform ctrl+scroll.
- kev.reset(GenerateKey(ui::ET_KEY_PRESSED, ui::VKEY_CONTROL));
- int mod_down_flags = HandleKeyEventForDownFlags(*kev.get(), &sticky_key);
+ kev.reset(GenerateKey(true, ui::VKEY_CONTROL));
sev.reset(GenerateFlingScrollEvent(0, true));
- bool released = false;
- sticky_key.HandleScrollEvent(*sev.get(), &mod_down_flags, &released);
+ sticky_key.HandleScrollEvent(sev.get());
sev.reset(GenerateScrollEvent(10));
- sticky_key.HandleScrollEvent(*sev.get(), &mod_down_flags, &released);
+ sticky_key.HandleScrollEvent(sev.get());
sev.reset(GenerateFlingScrollEvent(10, false));
- sticky_key.HandleScrollEvent(*sev.get(), &mod_down_flags, &released);
+ sticky_key.HandleScrollEvent(sev.get());
// Sticky keys should not be enabled afterwards.
- kev.reset(GenerateKey(ui::ET_KEY_RELEASED, ui::VKEY_CONTROL));
- mod_down_flags = HandleKeyEventForDownFlags(*kev.get(), &sticky_key);
+ kev.reset(GenerateKey(false, ui::VKEY_CONTROL));
+ sticky_key.HandleKeyEvent(kev.get());
EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
- EXPECT_EQ(ui::EF_NONE, mod_down_flags);
}
TEST_F(StickyKeysTest, MouseEventOneshot) {
scoped_ptr<ui::MouseEvent> ev;
scoped_ptr<ui::KeyEvent> kev;
- StickyKeysHandler sticky_key(ui::EF_CONTROL_DOWN);
+ MockStickyKeysHandlerDelegate* mock_delegate =
+ new MockStickyKeysHandlerDelegate(this);
+ StickyKeysHandler sticky_key(ui::EF_CONTROL_DOWN, mock_delegate);
EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
SendActivateStickyKeyPattern(&sticky_key, ui::VKEY_CONTROL);
@@ -452,47 +551,40 @@ TEST_F(StickyKeysTest, MouseEventOneshot) {
// We should still be in the ENABLED state until we get the mouse
// release event.
- ev.reset(GenerateMouseEvent(ui::ET_MOUSE_PRESSED));
- bool released = false;
- int mod_down_flags = 0;
- sticky_key.HandleMouseEvent(*ev.get(), &mod_down_flags, &released);
- EXPECT_TRUE(mod_down_flags & ui::EF_CONTROL_DOWN);
+ ev.reset(GenerateMouseEvent(true));
+ sticky_key.HandleMouseEvent(ev.get());
+ EXPECT_TRUE(ev->flags() & ui::EF_CONTROL_DOWN);
EXPECT_EQ(STICKY_KEY_STATE_ENABLED, sticky_key.current_state());
- ev.reset(GenerateMouseEvent(ui::ET_MOUSE_RELEASED));
- released = false;
- mod_down_flags = 0;
- sticky_key.HandleMouseEvent(*ev.get(), &mod_down_flags, &released);
- EXPECT_TRUE(mod_down_flags & ui::EF_CONTROL_DOWN);
+ ev.reset(GenerateMouseEvent(false));
+ sticky_key.HandleMouseEvent(ev.get());
+ EXPECT_TRUE(ev->flags() & ui::EF_CONTROL_DOWN);
EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
// Making sure modifier key release event is dispatched in the right order.
- EXPECT_TRUE(released);
- scoped_ptr<ui::Event> up_event;
- ASSERT_EQ(0, sticky_key.GetModifierUpEvent(&up_event));
- EXPECT_TRUE(up_event.get());
- EXPECT_EQ(ui::ET_KEY_RELEASED, up_event->type());
+ ASSERT_EQ(2u, mock_delegate->GetEventCount());
+ EXPECT_EQ(ui::ET_MOUSE_RELEASED, mock_delegate->GetEvent(0)->type());
+ EXPECT_EQ(ui::ET_KEY_RELEASED, mock_delegate->GetEvent(1)->type());
EXPECT_EQ(ui::VKEY_CONTROL,
- static_cast<const ui::KeyEvent*>(up_event.get())->key_code());
+ static_cast<const ui::KeyEvent*>(mock_delegate->GetEvent(1))
+ ->key_code());
// Enabled state is one shot, so next click should not be control modified.
- ev.reset(GenerateMouseEvent(ui::ET_MOUSE_PRESSED));
- released = false;
- mod_down_flags = 0;
- sticky_key.HandleMouseEvent(*ev.get(), &mod_down_flags, &released);
- EXPECT_FALSE(mod_down_flags & ui::EF_CONTROL_DOWN);
-
- ev.reset(GenerateMouseEvent(ui::ET_MOUSE_RELEASED));
- released = false;
- mod_down_flags = 0;
- sticky_key.HandleMouseEvent(*ev.get(), &mod_down_flags, &released);
- EXPECT_FALSE(mod_down_flags & ui::EF_CONTROL_DOWN);
+ ev.reset(GenerateMouseEvent(true));
+ sticky_key.HandleMouseEvent(ev.get());
+ EXPECT_FALSE(ev->flags() & ui::EF_CONTROL_DOWN);
+
+ ev.reset(GenerateMouseEvent(false));
+ sticky_key.HandleMouseEvent(ev.get());
+ EXPECT_FALSE(ev->flags() & ui::EF_CONTROL_DOWN);
}
TEST_F(StickyKeysTest, MouseEventLocked) {
scoped_ptr<ui::MouseEvent> ev;
scoped_ptr<ui::KeyEvent> kev;
- StickyKeysHandler sticky_key(ui::EF_CONTROL_DOWN);
+ MockStickyKeysHandlerDelegate* mock_delegate =
+ new MockStickyKeysHandlerDelegate(this);
+ StickyKeysHandler sticky_key(ui::EF_CONTROL_DOWN, mock_delegate);
EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
@@ -504,44 +596,35 @@ TEST_F(StickyKeysTest, MouseEventLocked) {
// Mouse events should not disable locked mode.
for (int i = 0; i < 3; ++i) {
- bool released = false;
- int mod_down_flags = 0;
- ev.reset(GenerateMouseEvent(ui::ET_MOUSE_PRESSED));
- sticky_key.HandleMouseEvent(*ev.get(), &mod_down_flags, &released);
- EXPECT_TRUE(mod_down_flags & ui::EF_CONTROL_DOWN);
- ev.reset(GenerateMouseEvent(ui::ET_MOUSE_RELEASED));
- released = false;
- mod_down_flags = 0;
- sticky_key.HandleMouseEvent(*ev.get(), &mod_down_flags, &released);
- EXPECT_TRUE(mod_down_flags & ui::EF_CONTROL_DOWN);
+ ev.reset(GenerateMouseEvent(true));
+ sticky_key.HandleMouseEvent(ev.get());
+ EXPECT_TRUE(ev->flags() & ui::EF_CONTROL_DOWN);
+ ev.reset(GenerateMouseEvent(false));
+ sticky_key.HandleMouseEvent(ev.get());
+ EXPECT_TRUE(ev->flags() & ui::EF_CONTROL_DOWN);
EXPECT_EQ(STICKY_KEY_STATE_LOCKED, sticky_key.current_state());
}
// Test with mouse wheel.
for (int i = 0; i < 3; ++i) {
- bool released = false;
- int mod_down_flags = 0;
ev.reset(GenerateMouseWheelEvent(ui::MouseWheelEvent::kWheelDelta));
- sticky_key.HandleMouseEvent(*ev.get(), &mod_down_flags, &released);
+ sticky_key.HandleMouseEvent(ev.get());
ev.reset(GenerateMouseWheelEvent(-ui::MouseWheelEvent::kWheelDelta));
- released = false;
- mod_down_flags = 0;
- sticky_key.HandleMouseEvent(*ev.get(), &mod_down_flags, &released);
- EXPECT_TRUE(mod_down_flags & ui::EF_CONTROL_DOWN);
+ sticky_key.HandleMouseEvent(ev.get());
+ EXPECT_TRUE(ev->flags() & ui::EF_CONTROL_DOWN);
EXPECT_EQ(STICKY_KEY_STATE_LOCKED, sticky_key.current_state());
}
// Test mixed case with mouse events and key events.
ev.reset(GenerateMouseWheelEvent(ui::MouseWheelEvent::kWheelDelta));
- bool released = false;
- int mod_down_flags = 0;
- sticky_key.HandleMouseEvent(*ev.get(), &mod_down_flags, &released);
- EXPECT_TRUE(mod_down_flags & ui::EF_CONTROL_DOWN);
- kev.reset(GenerateKey(ui::ET_KEY_PRESSED, ui::VKEY_N));
- mod_down_flags = HandleKeyEventForDownFlags(*kev.get(), &sticky_key);
- EXPECT_TRUE(mod_down_flags & ui::EF_CONTROL_DOWN);
- mod_down_flags = HandleKeyEventForDownFlags(*kev.get(), &sticky_key);
- EXPECT_TRUE(mod_down_flags & ui::EF_CONTROL_DOWN);
+ sticky_key.HandleMouseEvent(ev.get());
+ EXPECT_TRUE(ev->flags() & ui::EF_CONTROL_DOWN);
+ kev.reset(GenerateKey(true, ui::VKEY_N));
+ sticky_key.HandleKeyEvent(kev.get());
+ EXPECT_TRUE(kev->flags() & ui::EF_CONTROL_DOWN);
+ kev.reset(GenerateKey(false, ui::VKEY_N));
+ sticky_key.HandleKeyEvent(kev.get());
+ EXPECT_TRUE(kev->flags() & ui::EF_CONTROL_DOWN);
EXPECT_EQ(STICKY_KEY_STATE_LOCKED, sticky_key.current_state());
}
@@ -549,10 +632,14 @@ TEST_F(StickyKeysTest, MouseEventLocked) {
TEST_F(StickyKeysTest, ScrollEventOneshot) {
scoped_ptr<ui::ScrollEvent> ev;
scoped_ptr<ui::KeyEvent> kev;
- StickyKeysHandler sticky_key(ui::EF_CONTROL_DOWN);
+ MockStickyKeysHandlerDelegate* mock_delegate =
+ new MockStickyKeysHandlerDelegate(this);
+ StickyKeysHandler sticky_key(ui::EF_CONTROL_DOWN, mock_delegate);
int scroll_deltas[] = {-10, 10};
for (int i = 0; i < 2; ++i) {
+ mock_delegate->ClearEvents();
+
// Enable sticky keys.
EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
SendActivateStickyKeyPattern(&sticky_key, ui::VKEY_CONTROL);
@@ -561,44 +648,42 @@ TEST_F(StickyKeysTest, ScrollEventOneshot) {
// Test a scroll sequence. Sticky keys should only be disabled at the end
// of the scroll sequence. Fling cancel event starts the scroll sequence.
ev.reset(GenerateFlingScrollEvent(0, true));
- bool released = false;
- int mod_down_flags = 0;
- sticky_key.HandleScrollEvent(*ev.get(), &mod_down_flags, &released);
- EXPECT_TRUE(mod_down_flags & ui::EF_CONTROL_DOWN);
+ sticky_key.HandleScrollEvent(ev.get());
+ EXPECT_TRUE(ev->flags() & ui::EF_CONTROL_DOWN);
EXPECT_EQ(STICKY_KEY_STATE_ENABLED, sticky_key.current_state());
// Scrolls should all be modified but not disable sticky keys.
for (int j = 0; j < 3; ++j) {
ev.reset(GenerateScrollEvent(scroll_deltas[i]));
- released = false;
- mod_down_flags = 0;
- sticky_key.HandleScrollEvent(*ev.get(), &mod_down_flags, &released);
- EXPECT_TRUE(mod_down_flags & ui::EF_CONTROL_DOWN);
+ sticky_key.HandleScrollEvent(ev.get());
+ EXPECT_TRUE(ev->flags() & ui::EF_CONTROL_DOWN);
EXPECT_EQ(STICKY_KEY_STATE_ENABLED, sticky_key.current_state());
}
// Fling start event ends scroll sequence.
ev.reset(GenerateFlingScrollEvent(scroll_deltas[i], false));
- released = false;
- mod_down_flags = 0;
- sticky_key.HandleScrollEvent(*ev.get(), &mod_down_flags, &released);
- EXPECT_TRUE(mod_down_flags & ui::EF_CONTROL_DOWN);
+ sticky_key.HandleScrollEvent(ev.get());
+ EXPECT_TRUE(ev->flags() & ui::EF_CONTROL_DOWN);
EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
- scoped_ptr<ui::Event> up_event;
- EXPECT_TRUE(released);
- ASSERT_EQ(0, sticky_key.GetModifierUpEvent(&up_event));
- EXPECT_TRUE(up_event.get());
- EXPECT_EQ(ui::ET_KEY_RELEASED, up_event->type());
+ ASSERT_EQ(2U, mock_delegate->GetEventCount());
+ EXPECT_EQ(ui::ET_SCROLL_FLING_START, mock_delegate->GetEvent(0)->type());
+ EXPECT_FLOAT_EQ(scroll_deltas[i],
+ static_cast<const ui::ScrollEvent*>(
+ mock_delegate->GetEvent(0))->y_offset());
+ EXPECT_EQ(ui::ET_KEY_RELEASED, mock_delegate->GetEvent(1)->type());
EXPECT_EQ(ui::VKEY_CONTROL,
- static_cast<const ui::KeyEvent*>(up_event.get())->key_code());
+ static_cast<const ui::KeyEvent*>(mock_delegate->GetEvent(1))
+ ->key_code());
}
}
TEST_F(StickyKeysTest, ScrollDirectionChanged) {
scoped_ptr<ui::ScrollEvent> ev;
scoped_ptr<ui::KeyEvent> kev;
- StickyKeysHandler sticky_key(ui::EF_CONTROL_DOWN);
+ MockStickyKeysHandlerDelegate* mock_delegate =
+ new MockStickyKeysHandlerDelegate(this);
+ StickyKeysHandler sticky_key(ui::EF_CONTROL_DOWN, mock_delegate);
// Test direction change with both boundary value and negative value.
const int direction_change_values[2] = {0, -10};
@@ -608,26 +693,21 @@ TEST_F(StickyKeysTest, ScrollDirectionChanged) {
// Fling cancel starts scroll sequence.
ev.reset(GenerateFlingScrollEvent(0, true));
- bool released = false;
- int mod_down_flags = 0;
- sticky_key.HandleScrollEvent(*ev.get(), &mod_down_flags, &released);
+ sticky_key.HandleScrollEvent(ev.get());
EXPECT_EQ(STICKY_KEY_STATE_ENABLED, sticky_key.current_state());
// Test that changing directions in a scroll sequence will
// return sticky keys to DISABLED state.
for (int j = 0; j < 3; ++j) {
ev.reset(GenerateScrollEvent(10));
- released = false;
- mod_down_flags = 0;
- sticky_key.HandleScrollEvent(*ev.get(), &mod_down_flags, &released);
- EXPECT_TRUE(mod_down_flags & ui::EF_CONTROL_DOWN);
+ sticky_key.HandleScrollEvent(ev.get());
+ EXPECT_TRUE(ev->flags() & ui::EF_CONTROL_DOWN);
EXPECT_EQ(STICKY_KEY_STATE_ENABLED, sticky_key.current_state());
}
ev.reset(GenerateScrollEvent(direction_change_values[i]));
- released = false;
- mod_down_flags = 0;
- sticky_key.HandleScrollEvent(*ev.get(), &mod_down_flags, &released);
+ sticky_key.HandleScrollEvent(ev.get());
+ EXPECT_FALSE(ev->flags() & ui::EF_CONTROL_DOWN);
EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
}
}
@@ -635,7 +715,9 @@ TEST_F(StickyKeysTest, ScrollDirectionChanged) {
TEST_F(StickyKeysTest, ScrollEventLocked) {
scoped_ptr<ui::ScrollEvent> ev;
scoped_ptr<ui::KeyEvent> kev;
- StickyKeysHandler sticky_key(ui::EF_CONTROL_DOWN);
+ MockStickyKeysHandlerDelegate* mock_delegate =
+ new MockStickyKeysHandlerDelegate(this);
+ StickyKeysHandler sticky_key(ui::EF_CONTROL_DOWN, mock_delegate);
// Lock sticky keys.
SendActivateStickyKeyPattern(&sticky_key, ui::VKEY_CONTROL);
@@ -646,45 +728,63 @@ TEST_F(StickyKeysTest, ScrollEventLocked) {
for (int i = 0; i < 5; ++i) {
// Fling cancel starts scroll sequence.
ev.reset(GenerateFlingScrollEvent(0, true));
- bool released = false;
- int mod_down_flags = 0;
- sticky_key.HandleScrollEvent(*ev.get(), &mod_down_flags, &released);
+ sticky_key.HandleScrollEvent(ev.get());
ev.reset(GenerateScrollEvent(10));
- released = false;
- mod_down_flags = 0;
- sticky_key.HandleScrollEvent(*ev.get(), &mod_down_flags, &released);
- EXPECT_TRUE(mod_down_flags & ui::EF_CONTROL_DOWN);
+ sticky_key.HandleScrollEvent(ev.get());
+ EXPECT_TRUE(ev->flags() & ui::EF_CONTROL_DOWN);
ev.reset(GenerateScrollEvent(-10));
- sticky_key.HandleScrollEvent(*ev.get(), &mod_down_flags, &released);
- EXPECT_TRUE(mod_down_flags & ui::EF_CONTROL_DOWN);
+ sticky_key.HandleScrollEvent(ev.get());
+ EXPECT_TRUE(ev->flags() & ui::EF_CONTROL_DOWN);
// Fling start ends scroll sequence.
ev.reset(GenerateFlingScrollEvent(-10, false));
- sticky_key.HandleScrollEvent(*ev.get(), &mod_down_flags, &released);
+ sticky_key.HandleScrollEvent(ev.get());
}
EXPECT_EQ(STICKY_KEY_STATE_LOCKED, sticky_key.current_state());
}
+TEST_F(StickyKeysTest, EventTargetDestroyed) {
+ scoped_ptr<ui::KeyEvent> ev;
+ MockStickyKeysHandlerDelegate* mock_delegate =
+ new MockStickyKeysHandlerDelegate(this);
+ StickyKeysHandler sticky_key(ui::EF_CONTROL_DOWN, mock_delegate);
+
+ target()->Focus();
+
+ // Go into ENABLED state.
+ EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
+ SendActivateStickyKeyPattern(&sticky_key, ui::VKEY_CONTROL);
+ EXPECT_EQ(STICKY_KEY_STATE_ENABLED, sticky_key.current_state());
+
+ // CTRL+J is a special shortcut that will destroy the event target.
+ ev.reset(GenerateKey(true, ui::VKEY_J));
+ sticky_key.HandleKeyEvent(ev.get());
+ EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
+ EXPECT_FALSE(target());
+}
+
TEST_F(StickyKeysTest, SynthesizedEvents) {
// Non-native, internally generated events should be properly handled
// by sticky keys.
- StickyKeysHandler sticky_key(ui::EF_CONTROL_DOWN);
+ MockStickyKeysHandlerDelegate* mock_delegate =
+ new MockStickyKeysHandlerDelegate(this);
+ StickyKeysHandler sticky_key(ui::EF_CONTROL_DOWN, mock_delegate);
// Test non-native key events.
scoped_ptr<ui::KeyEvent> kev;
SendActivateStickyKeyPattern(&sticky_key, ui::VKEY_CONTROL);
EXPECT_EQ(STICKY_KEY_STATE_ENABLED, sticky_key.current_state());
- kev.reset(GenerateSynthesizedKeyEvent(ui::ET_KEY_PRESSED, ui::VKEY_K));
- int mod_down_flags = HandleKeyEventForDownFlags(*kev.get(), &sticky_key);
- EXPECT_TRUE(mod_down_flags & ui::EF_CONTROL_DOWN);
+ kev.reset(GenerateSynthesizedKeyEvent(true, ui::VKEY_K));
+ sticky_key.HandleKeyEvent(kev.get());
+ EXPECT_TRUE(kev->flags() & ui::EF_CONTROL_DOWN);
EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
- kev.reset(GenerateSynthesizedKeyEvent(ui::ET_KEY_RELEASED, ui::VKEY_K));
- mod_down_flags = HandleKeyEventForDownFlags(*kev.get(), &sticky_key);
- EXPECT_FALSE(mod_down_flags & ui::EF_CONTROL_DOWN);
+ kev.reset(GenerateSynthesizedKeyEvent(false, ui::VKEY_K));
+ sticky_key.HandleKeyEvent(kev.get());
+ EXPECT_FALSE(kev->flags() & ui::EF_CONTROL_DOWN);
EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
// Test non-native mouse events.
@@ -692,21 +792,216 @@ TEST_F(StickyKeysTest, SynthesizedEvents) {
EXPECT_EQ(STICKY_KEY_STATE_ENABLED, sticky_key.current_state());
scoped_ptr<ui::MouseEvent> mev;
- mev.reset(GenerateSynthesizedMouseClickEvent(ui::ET_MOUSE_PRESSED,
- gfx::Point(0, 0)));
- bool released = false;
- sticky_key.HandleMouseEvent(*mev.get(), &mod_down_flags, &released);
- EXPECT_TRUE(mod_down_flags & ui::EF_CONTROL_DOWN);
+ mev.reset(GenerateSynthesizedMouseClickEvent(true, gfx::Point(0, 0)));
+ sticky_key.HandleMouseEvent(mev.get());
+ EXPECT_TRUE(mev->flags() & ui::EF_CONTROL_DOWN);
EXPECT_EQ(STICKY_KEY_STATE_ENABLED, sticky_key.current_state());
- mev.reset(GenerateSynthesizedMouseClickEvent(ui::ET_MOUSE_RELEASED,
- gfx::Point(0, 0)));
- released = false;
- mod_down_flags = 0;
- sticky_key.HandleMouseEvent(*mev.get(), &mod_down_flags, &released);
- EXPECT_TRUE(mod_down_flags & ui::EF_CONTROL_DOWN);
- EXPECT_TRUE(released);
+ mev.reset(GenerateSynthesizedMouseClickEvent(false, gfx::Point(0, 0)));
+ sticky_key.HandleMouseEvent(mev.get());
+ EXPECT_TRUE(mev->flags() & ui::EF_CONTROL_DOWN);
EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
}
+TEST_F(StickyKeysTest, KeyEventDispatchImpl) {
+ // Test the actual key event dispatch implementation.
+ EventBuffer buffer;
+ ScopedVector<ui::Event> events;
+ ui::EventProcessor* dispatcher =
+ Shell::GetPrimaryRootWindow()->GetHost()->event_processor();
+ Shell::GetInstance()->AddPreTargetHandler(&buffer);
+ Shell::GetInstance()->sticky_keys_controller()->Enable(true);
+
+ SendActivateStickyKeyPattern(dispatcher, ui::VKEY_CONTROL);
+ scoped_ptr<ui::KeyEvent> ev;
+ buffer.PopEvents(&events);
+
+ // Test key press event is correctly modified and modifier release
+ // event is sent.
+ ev.reset(GenerateKey(true, ui::VKEY_C));
+ ui::EventDispatchDetails details = dispatcher->OnEventFromSource(ev.get());
+ buffer.PopEvents(&events);
+ EXPECT_EQ(2u, events.size());
+ EXPECT_EQ(ui::ET_KEY_PRESSED, events[0]->type());
+ EXPECT_EQ(ui::VKEY_C, static_cast<ui::KeyEvent*>(events[0])->key_code());
+ EXPECT_TRUE(events[0]->flags() & ui::EF_CONTROL_DOWN);
+ EXPECT_EQ(ui::ET_KEY_RELEASED, events[1]->type());
+ EXPECT_EQ(ui::VKEY_CONTROL,
+ static_cast<ui::KeyEvent*>(events[1])->key_code());
+
+ // Test key release event is not modified.
+ ev.reset(GenerateKey(false, ui::VKEY_C));
+ details = dispatcher->OnEventFromSource(ev.get());
+ ASSERT_FALSE(details.dispatcher_destroyed);
+ buffer.PopEvents(&events);
+ EXPECT_EQ(1u, events.size());
+ EXPECT_EQ(ui::ET_KEY_RELEASED, events[0]->type());
+ EXPECT_EQ(ui::VKEY_C,
+ static_cast<ui::KeyEvent*>(events[0])->key_code());
+ EXPECT_FALSE(events[0]->flags() & ui::EF_CONTROL_DOWN);
+
+ // Test that synthesized key events are dispatched correctly.
+ SendActivateStickyKeyPattern(dispatcher, ui::VKEY_CONTROL);
+ buffer.PopEvents(&events);
+ scoped_ptr<ui::KeyEvent> kev;
+ kev.reset(GenerateSynthesizedKeyEvent(true, ui::VKEY_K));
+ details = dispatcher->OnEventFromSource(kev.get());
+ ASSERT_FALSE(details.dispatcher_destroyed);
+ buffer.PopEvents(&events);
+ EXPECT_EQ(2u, events.size());
+ EXPECT_EQ(ui::ET_KEY_PRESSED, events[0]->type());
+ EXPECT_EQ(ui::VKEY_K, static_cast<ui::KeyEvent*>(events[0])->key_code());
+ EXPECT_TRUE(events[0]->flags() & ui::EF_CONTROL_DOWN);
+ EXPECT_EQ(ui::ET_KEY_RELEASED, events[1]->type());
+ EXPECT_EQ(ui::VKEY_CONTROL,
+ static_cast<ui::KeyEvent*>(events[1])->key_code());
+
+ Shell::GetInstance()->RemovePreTargetHandler(&buffer);
+}
+
+class StickyKeysMouseDispatchTest
+ : public StickyKeysTest,
+ public ::testing::WithParamInterface<int> {
+};
+
+TEST_P(StickyKeysMouseDispatchTest, MouseEventDispatchImpl) {
+ int scale_factor = GetParam();
+ std::ostringstream display_specs;
+ display_specs << "1280x1024*" << scale_factor;
+ UpdateDisplay(display_specs.str());
+
+ EventBuffer buffer;
+ ScopedVector<ui::Event> events;
+ ui::EventProcessor* dispatcher =
+ Shell::GetPrimaryRootWindow()->GetHost()->event_processor();
+ Shell::GetInstance()->AddPreTargetHandler(&buffer);
+ Shell::GetInstance()->sticky_keys_controller()->Enable(true);
+
+ scoped_ptr<ui::MouseEvent> ev;
+ SendActivateStickyKeyPattern(dispatcher, ui::VKEY_CONTROL);
+ buffer.PopEvents(&events);
+
+ // Test mouse press event is correctly modified and has correct DIP location.
+ gfx::Point physical_location(400, 400);
+ gfx::Point dip_location(physical_location.x() / scale_factor,
+ physical_location.y() / scale_factor);
+ ev.reset(GenerateMouseEventAt(true, physical_location));
+ ui::EventDispatchDetails details = dispatcher->OnEventFromSource(ev.get());
+ buffer.PopEvents(&events);
+ EXPECT_EQ(1u, events.size());
+ EXPECT_EQ(ui::ET_MOUSE_PRESSED, events[0]->type());
+ EXPECT_TRUE(events[0]->flags() & ui::EF_CONTROL_DOWN);
+ EXPECT_EQ(dip_location.ToString(),
+ static_cast<ui::MouseEvent*>(events[0])->location().ToString());
+
+ // Test mouse release event is correctly modified and modifier release
+ // event is sent. The mouse event should have the correct DIP location.
+ ev.reset(GenerateMouseEventAt(false, physical_location));
+ details = dispatcher->OnEventFromSource(ev.get());
+ ASSERT_FALSE(details.dispatcher_destroyed);
+ buffer.PopEvents(&events);
+ EXPECT_EQ(2u, events.size());
+ EXPECT_EQ(ui::ET_MOUSE_RELEASED, events[0]->type());
+ EXPECT_TRUE(events[0]->flags() & ui::EF_CONTROL_DOWN);
+ EXPECT_EQ(ui::ET_KEY_RELEASED, events[1]->type());
+ EXPECT_EQ(dip_location.ToString(),
+ static_cast<ui::MouseEvent*>(events[0])->location().ToString());
+ EXPECT_EQ(ui::VKEY_CONTROL,
+ static_cast<ui::KeyEvent*>(events[1])->key_code());
+
+ // Test synthesized mouse events are dispatched correctly.
+ SendActivateStickyKeyPattern(dispatcher, ui::VKEY_CONTROL);
+ buffer.PopEvents(&events);
+ ev.reset(GenerateSynthesizedMouseClickEvent(false, physical_location));
+ details = dispatcher->OnEventFromSource(ev.get());
+ ASSERT_FALSE(details.dispatcher_destroyed);
+ buffer.PopEvents(&events);
+ EXPECT_EQ(2u, events.size());
+ EXPECT_EQ(ui::ET_MOUSE_RELEASED, events[0]->type());
+ EXPECT_TRUE(events[0]->flags() & ui::EF_CONTROL_DOWN);
+ EXPECT_EQ(dip_location.ToString(),
+ static_cast<ui::MouseEvent*>(events[0])->location().ToString());
+ EXPECT_EQ(ui::ET_KEY_RELEASED, events[1]->type());
+ EXPECT_EQ(ui::VKEY_CONTROL,
+ static_cast<ui::KeyEvent*>(events[1])->key_code());
+
+ Shell::GetInstance()->RemovePreTargetHandler(&buffer);
+}
+
+TEST_P(StickyKeysMouseDispatchTest, MouseWheelEventDispatchImpl) {
+ int scale_factor = GetParam();
+ std::ostringstream display_specs;
+ display_specs << "1280x1024*" << scale_factor;
+ UpdateDisplay(display_specs.str());
+
+ // Test the actual mouse wheel event dispatch implementation.
+ EventBuffer buffer;
+ ScopedVector<ui::Event> events;
+ ui::EventProcessor* dispatcher =
+ Shell::GetPrimaryRootWindow()->GetHost()->event_processor();
+ Shell::GetInstance()->AddPreTargetHandler(&buffer);
+ Shell::GetInstance()->sticky_keys_controller()->Enable(true);
+
+ scoped_ptr<ui::MouseWheelEvent> ev;
+ SendActivateStickyKeyPattern(dispatcher, ui::VKEY_CONTROL);
+ buffer.PopEvents(&events);
+
+ // Test positive mouse wheel event is correctly modified and modifier release
+ // event is sent.
+ ev.reset(GenerateMouseWheelEvent(ui::MouseWheelEvent::kWheelDelta));
+ ui::EventDispatchDetails details = dispatcher->OnEventFromSource(ev.get());
+ ASSERT_FALSE(details.dispatcher_destroyed);
+ buffer.PopEvents(&events);
+ EXPECT_EQ(2u, events.size());
+ EXPECT_TRUE(events[0]->IsMouseWheelEvent());
+ EXPECT_EQ(ui::MouseWheelEvent::kWheelDelta / scale_factor,
+ static_cast<ui::MouseWheelEvent*>(events[0])->y_offset());
+ EXPECT_TRUE(events[0]->flags() & ui::EF_CONTROL_DOWN);
+ EXPECT_EQ(ui::ET_KEY_RELEASED, events[1]->type());
+ EXPECT_EQ(ui::VKEY_CONTROL,
+ static_cast<ui::KeyEvent*>(events[1])->key_code());
+
+ // Test negative mouse wheel event is correctly modified and modifier release
+ // event is sent.
+ SendActivateStickyKeyPattern(dispatcher, ui::VKEY_CONTROL);
+ buffer.PopEvents(&events);
+
+ ev.reset(GenerateMouseWheelEvent(-ui::MouseWheelEvent::kWheelDelta));
+ details = dispatcher->OnEventFromSource(ev.get());
+ ASSERT_FALSE(details.dispatcher_destroyed);
+ buffer.PopEvents(&events);
+ EXPECT_EQ(2u, events.size());
+ EXPECT_TRUE(events[0]->IsMouseWheelEvent());
+ EXPECT_EQ(-ui::MouseWheelEvent::kWheelDelta / scale_factor,
+ static_cast<ui::MouseWheelEvent*>(events[0])->y_offset());
+ EXPECT_TRUE(events[0]->flags() & ui::EF_CONTROL_DOWN);
+ EXPECT_EQ(ui::ET_KEY_RELEASED, events[1]->type());
+ EXPECT_EQ(ui::VKEY_CONTROL,
+ static_cast<ui::KeyEvent*>(events[1])->key_code());
+
+ // Test synthesized mouse wheel events are dispatched correctly.
+ SendActivateStickyKeyPattern(dispatcher, ui::VKEY_CONTROL);
+ buffer.PopEvents(&events);
+ ev.reset(
+ GenerateSynthesizedMouseWheelEvent(ui::MouseWheelEvent::kWheelDelta));
+ details = dispatcher->OnEventFromSource(ev.get());
+ ASSERT_FALSE(details.dispatcher_destroyed);
+ buffer.PopEvents(&events);
+ EXPECT_EQ(2u, events.size());
+ EXPECT_TRUE(events[0]->IsMouseWheelEvent());
+ EXPECT_EQ(ui::MouseWheelEvent::kWheelDelta / scale_factor,
+ static_cast<ui::MouseWheelEvent*>(events[0])->y_offset());
+ EXPECT_TRUE(events[0]->flags() & ui::EF_CONTROL_DOWN);
+ EXPECT_TRUE(events[0]->flags() & ui::EF_CONTROL_DOWN);
+ EXPECT_EQ(ui::ET_KEY_RELEASED, events[1]->type());
+ EXPECT_EQ(ui::VKEY_CONTROL,
+ static_cast<ui::KeyEvent*>(events[1])->key_code());
+
+ Shell::GetInstance()->RemovePreTargetHandler(&buffer);
+}
+
+INSTANTIATE_TEST_CASE_P(DPIScaleFactors,
+ StickyKeysMouseDispatchTest,
+ ::testing::Values(1, 2));
+
} // namespace ash