summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-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
-rw-r--r--chrome/browser/chromeos/chrome_browser_main_chromeos.cc13
-rw-r--r--chrome/browser/chromeos/events/event_rewriter.cc138
-rw-r--r--chrome/browser/chromeos/events/event_rewriter.h18
-rw-r--r--chrome/browser/chromeos/events/event_rewriter_unittest.cc486
9 files changed, 1125 insertions, 1239 deletions
diff --git a/ash/shell.cc b/ash/shell.cc
index c8b3279..2c39306 100644
--- a/ash/shell.cc
+++ b/ash/shell.cc
@@ -889,13 +889,6 @@ 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);
@@ -930,6 +923,10 @@ 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 53be1fc..6237004 100644
--- a/ash/sticky_keys/sticky_keys_controller.cc
+++ b/ash/sticky_keys/sticky_keys_controller.cc
@@ -4,12 +4,6 @@
#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"
@@ -25,79 +19,26 @@ namespace ash {
namespace {
// Returns true if the type of mouse event should be modified by sticky keys.
-bool ShouldModifyMouseEvent(ui::MouseEvent* event) {
- ui::EventType type = event->type();
+bool ShouldModifyMouseEvent(const ui::MouseEvent& event) {
+ ui::EventType type = event.type();
return type == ui::ET_MOUSE_PRESSED || type == ui::ET_MOUSE_RELEASED ||
type == ui::ET_MOUSEWHEEL;
}
-// 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;
+// 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;
}
} // namespace
@@ -120,21 +61,11 @@ 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,
- 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()));
+ 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));
overlay_.reset(new StickyKeysOverlay());
overlay_->SetModifierVisible(ui::EF_ALTGR_DOWN, altgr_enabled_);
@@ -155,56 +86,103 @@ void StickyKeysController::SetModifiersEnabled(bool mod3_enabled,
}
}
-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();
- }
+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;
}
void StickyKeysController::UpdateOverlay() {
@@ -235,66 +213,64 @@ StickyKeysOverlay* StickyKeysController::GetOverlayForTest() {
///////////////////////////////////////////////////////////////////////////////
// StickyKeysHandler
-StickyKeysHandler::StickyKeysHandler(ui::EventFlags modifier_flag,
- StickyKeysHandlerDelegate* delegate)
+StickyKeysHandler::StickyKeysHandler(ui::EventFlags modifier_flag)
: modifier_flag_(modifier_flag),
current_state_(STICKY_KEY_STATE_DISABLED),
- event_from_myself_(false),
preparing_to_enable_(false),
- scroll_delta_(0),
- delegate_(delegate) {
+ scroll_delta_(0) {
}
StickyKeysHandler::~StickyKeysHandler() {
}
-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.
+bool StickyKeysHandler::HandleKeyEvent(const ui::KeyEvent& event,
+ ui::KeyboardCode key_code,
+ int* mod_down_flags,
+ bool* released) {
switch (current_state_) {
case STICKY_KEY_STATE_DISABLED:
- return HandleDisabledState(event);
+ return HandleDisabledState(event, key_code);
case STICKY_KEY_STATE_ENABLED:
- return HandleEnabledState(event);
+ return HandleEnabledState(event, key_code, mod_down_flags, released);
case STICKY_KEY_STATE_LOCKED:
- return HandleLockedState(event);
+ return HandleLockedState(event, key_code, mod_down_flags, released);
}
NOTREACHED();
return false;
}
-bool StickyKeysHandler::HandleMouseEvent(ui::MouseEvent* event) {
+bool StickyKeysHandler::HandleMouseEvent(
+ const ui::MouseEvent& event,
+ int* mod_down_flags,
+ bool* released) {
if (ShouldModifyMouseEvent(event))
preparing_to_enable_ = false;
- if (event_from_myself_ || current_state_ == STICKY_KEY_STATE_DISABLED
- || !ShouldModifyMouseEvent(event)) {
+ if (current_state_ == STICKY_KEY_STATE_DISABLED ||
+ !ShouldModifyMouseEvent(event)) {
return false;
}
DCHECK(current_state_ == STICKY_KEY_STATE_ENABLED ||
current_state_ == STICKY_KEY_STATE_LOCKED);
- AppendModifier(event);
+ *mod_down_flags |= modifier_flag_;
// 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;
- DispatchEventAndReleaseModifier(event);
- return true;
+ *released = true;
+ return false;
}
return false;
}
-bool StickyKeysHandler::HandleScrollEvent(ui::ScrollEvent* event) {
+bool StickyKeysHandler::HandleScrollEvent(
+ const ui::ScrollEvent& event,
+ int* mod_down_flags,
+ bool* released) {
preparing_to_enable_ = false;
- if (event_from_myself_ || current_state_ == STICKY_KEY_STATE_DISABLED)
+ if (current_state_ == STICKY_KEY_STATE_DISABLED)
return false;
DCHECK(current_state_ == STICKY_KEY_STATE_ENABLED ||
current_state_ == STICKY_KEY_STATE_LOCKED);
@@ -303,70 +279,82 @@ bool StickyKeysHandler::HandleScrollEvent(ui::ScrollEvent* event) {
// 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)
- AppendModifier(event);
+ *mod_down_flags |= modifier_flag_;
// 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;
- DispatchEventAndReleaseModifier(event);
- return true;
+ *released = true;
+ return false;
}
return false;
}
-StickyKeysHandler::KeyEventType
- StickyKeysHandler::TranslateKeyEvent(ui::KeyEvent* event) {
+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) {
bool is_target_key = false;
- if (event->key_code() == ui::VKEY_SHIFT ||
- event->key_code() == ui::VKEY_LSHIFT ||
- event->key_code() == ui::VKEY_RSHIFT) {
+ if (key_code == ui::VKEY_SHIFT ||
+ key_code == ui::VKEY_LSHIFT ||
+ key_code == ui::VKEY_RSHIFT) {
is_target_key = (modifier_flag_ == ui::EF_SHIFT_DOWN);
- } else if (event->key_code() == ui::VKEY_CONTROL ||
- event->key_code() == ui::VKEY_LCONTROL ||
- event->key_code() == ui::VKEY_RCONTROL) {
+ } else if (key_code == ui::VKEY_CONTROL ||
+ key_code == ui::VKEY_LCONTROL ||
+ key_code == ui::VKEY_RCONTROL) {
is_target_key = (modifier_flag_ == ui::EF_CONTROL_DOWN);
- } else if (event->key_code() == ui::VKEY_MENU ||
- event->key_code() == ui::VKEY_LMENU ||
- event->key_code() == ui::VKEY_RMENU) {
+ } else if (key_code == ui::VKEY_MENU ||
+ key_code == ui::VKEY_LMENU ||
+ key_code == ui::VKEY_RMENU) {
is_target_key = (modifier_flag_ == ui::EF_ALT_DOWN);
- } else if (event->key_code() == ui::VKEY_ALTGR) {
+ } else if (key_code == ui::VKEY_ALTGR) {
is_target_key = (modifier_flag_ == ui::EF_ALTGR_DOWN);
- } else if (event->key_code() == ui::VKEY_OEM_8) {
+ } else if (key_code == ui::VKEY_OEM_8) {
is_target_key = (modifier_flag_ == ui::EF_MOD3_DOWN);
} else {
- return event->type() == ui::ET_KEY_PRESSED ?
+ return type == ui::ET_KEY_PRESSED ?
NORMAL_KEY_DOWN : NORMAL_KEY_UP;
}
if (is_target_key) {
- return event->type() == ui::ET_KEY_PRESSED ?
+ return type == ui::ET_KEY_PRESSED ?
TARGET_MODIFIER_DOWN : TARGET_MODIFIER_UP;
}
- return event->type() == ui::ET_KEY_PRESSED ?
+ return type == ui::ET_KEY_PRESSED ?
OTHER_MODIFIER_DOWN : OTHER_MODIFIER_UP;
}
-bool StickyKeysHandler::HandleDisabledState(ui::KeyEvent* event) {
- switch (TranslateKeyEvent(event)) {
+bool StickyKeysHandler::HandleDisabledState(const ui::KeyEvent& event,
+ ui::KeyboardCode key_code) {
+ switch (TranslateKeyEvent(event.type(), key_code)) {
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;
@@ -385,20 +373,23 @@ bool StickyKeysHandler::HandleDisabledState(ui::KeyEvent* event) {
return false;
}
-bool StickyKeysHandler::HandleEnabledState(ui::KeyEvent* event) {
- switch (TranslateKeyEvent(event)) {
+bool StickyKeysHandler::HandleEnabledState(const ui::KeyEvent& event,
+ ui::KeyboardCode key_code,
+ int* mod_down_flags,
+ bool* released) {
+ switch (TranslateKeyEvent(event.type(), key_code)) {
case NORMAL_KEY_UP:
case TARGET_MODIFIER_DOWN:
- return true;
+ return false;
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;
- AppendModifier(event);
- DispatchEventAndReleaseModifier(event);
- return true;
+ *mod_down_flags |= modifier_flag_;
+ *released = true;
+ return false;
}
case OTHER_MODIFIER_DOWN:
case OTHER_MODIFIER_UP:
@@ -408,8 +399,11 @@ bool StickyKeysHandler::HandleEnabledState(ui::KeyEvent* event) {
return false;
}
-bool StickyKeysHandler::HandleLockedState(ui::KeyEvent* event) {
- switch (TranslateKeyEvent(event)) {
+bool StickyKeysHandler::HandleLockedState(const ui::KeyEvent& event,
+ ui::KeyboardCode key_code,
+ int* mod_down_flags,
+ bool* released) {
+ switch (TranslateKeyEvent(event.type(), key_code)) {
case TARGET_MODIFIER_DOWN:
return true;
case TARGET_MODIFIER_UP:
@@ -417,7 +411,7 @@ bool StickyKeysHandler::HandleLockedState(ui::KeyEvent* event) {
return false;
case NORMAL_KEY_DOWN:
case NORMAL_KEY_UP:
- AppendModifier(event);
+ *mod_down_flags |= modifier_flag_;
return false;
case OTHER_MODIFIER_DOWN:
case OTHER_MODIFIER_UP:
@@ -427,125 +421,4 @@ bool StickyKeysHandler::HandleLockedState(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 89a196a..fd5d389 100644
--- a/ash/sticky_keys/sticky_keys_controller.h
+++ b/ash/sticky_keys/sticky_keys_controller.h
@@ -10,6 +10,8 @@
#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;
@@ -59,7 +61,7 @@ class StickyKeysHandler;
// modifiers. Each handling or state is performed independently.
//
// StickyKeysController is disabled by default.
-class ASH_EXPORT StickyKeysController : public ui::EventHandler {
+class ASH_EXPORT StickyKeysController {
public:
StickyKeysController();
virtual ~StickyKeysController();
@@ -69,24 +71,64 @@ class ASH_EXPORT StickyKeysController : public ui::EventHandler {
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.
- 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);
+ // 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);
// Updates the overlay UI with the current state of the sticky keys.
void UpdateOverlay();
@@ -143,40 +185,35 @@ class ASH_EXPORT StickyKeysController : public ui::EventHandler {
// is modified.
class ASH_EXPORT StickyKeysHandler {
public:
- 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;
- };
-
- // This class takes an ownership of |delegate|.
- StickyKeysHandler(ui::EventFlags modifier_flag,
- StickyKeysHandlerDelegate* delegate);
+ explicit StickyKeysHandler(ui::EventFlags modifier_flag);
~StickyKeysHandler();
- // Handles key event. Returns true if key is consumed.
- bool HandleKeyEvent(ui::KeyEvent* event);
+ // 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);
- // Handles a mouse event. Returns true if mouse event is consumed.
- bool HandleMouseEvent(ui::MouseEvent* event);
+ // 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 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 scroll event. Returns true if scroll event is consumed.
- bool HandleScrollEvent(ui::ScrollEvent* 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);
// Returns current internal state.
StickyKeyState current_state() const { return current_state_; }
@@ -192,31 +229,27 @@ class ASH_EXPORT StickyKeysHandler {
OTHER_MODIFIER_UP, // The modifier key but not monitored key is up.
};
- // Translates |event| to sticky keys event type.
- KeyEventType TranslateKeyEvent(ui::KeyEvent* event);
-
- // Handles key event in DISABLED state.
- bool HandleDisabledState(ui::KeyEvent* event);
+ // Translates event type and key code to sticky keys event type.
+ KeyEventType TranslateKeyEvent(ui::EventType type, ui::KeyboardCode key_code);
- // Handles key event in ENABLED state.
- bool HandleEnabledState(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 LOCKED state.
- bool HandleLockedState(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);
- // 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);
+ // 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);
// The modifier flag to be monitored and appended to events.
const ui::EventFlags modifier_flag_;
@@ -224,9 +257,6 @@ 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
@@ -241,8 +271,6 @@ 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 678eff4..0d6f161 100644
--- a/ash/sticky_keys/sticky_keys_overlay_unittest.cc
+++ b/ash/sticky_keys/sticky_keys_overlay_unittest.cc
@@ -7,47 +7,14 @@
#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() :
- controller_(NULL),
- overlay_(NULL) {}
-
+ StickyKeysOverlayTest() {}
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) {
@@ -71,168 +38,7 @@ TEST_F(StickyKeysOverlayTest, ModifierKeyState) {
overlay.GetModifierKeyState(ui::EF_CONTROL_DOWN));
}
-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));
-}
+// Additional sticky key overlay tests that depend on chromeos::EventRewriter
+// are now in chrome/browser/chromeos/events/event_rewriter_unittest.cc .
} // namespace ash
diff --git a/ash/sticky_keys/sticky_keys_unittest.cc b/ash/sticky_keys/sticky_keys_unittest.cc
index 4c505e1..c164923 100644
--- a/ash/sticky_keys/sticky_keys_unittest.cc
+++ b/ash/sticky_keys/sticky_keys_unittest.cc
@@ -16,8 +16,7 @@
#include "base/memory/scoped_vector.h"
#include "ui/aura/window.h"
#include "ui/aura/window_tree_host.h"
-#include "ui/events/event_handler.h"
-#include "ui/events/event_processor.h"
+#include "ui/events/event_source.h"
#include "ui/events/test/events_test_utils_x11.h"
#include "ui/events/x/device_data_manager.h"
@@ -30,107 +29,7 @@ const unsigned int kTouchPadDeviceId = 1;
} // namespace
-// 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 {
+class StickyKeysTest : public test::AshTestBase {
protected:
StickyKeysTest()
: target_(NULL),
@@ -151,47 +50,35 @@ class StickyKeysTest : public test::AshTestBase,
test::AshTestBase::TearDown();
}
- // Overridden from MockStickyKeysHandlerDelegate::Delegate:
- virtual aura::Window* GetExpectedTarget() OVERRIDE {
- return target_ ? target_ : root_window_;
- }
-
- virtual void OnShortcutPressed() OVERRIDE {
+ virtual void OnShortcutPressed() {
if (target_) {
delete target_;
target_ = NULL;
}
}
- 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_);
+ ui::KeyEvent* GenerateKey(ui::EventType type, ui::KeyboardCode code) {
+ scoped_xevent_.InitKeyEvent(type, code, 0);
+ ui::KeyEvent* event = new ui::KeyEvent(scoped_xevent_, false);
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(bool is_button_press) {
- return GenerateMouseEventAt(is_button_press, gfx::Point());
+ ui::MouseEvent* GenerateMouseEvent(ui::EventType type) {
+ return GenerateMouseEventAt(type, gfx::Point());
}
// Creates a mouse event backed by a native XInput2 generic button event.
// The |location| should be in physical pixels.
- ui::MouseEvent* GenerateMouseEventAt(bool is_button_press,
+ ui::MouseEvent* GenerateMouseEventAt(ui::EventType type,
const gfx::Point& location) {
scoped_xevent_.InitGenericButtonEvent(
kTouchPadDeviceId,
- is_button_press ? ui::ET_MOUSE_PRESSED : ui::ET_MOUSE_RELEASED,
+ type,
location,
0);
ui::MouseEvent* event = new ui::MouseEvent(scoped_xevent_);
- ui::Event::DispatcherApi dispatcher(event);
- dispatcher.set_target(target_);
return event;
}
@@ -234,14 +121,9 @@ class StickyKeysTest : public test::AshTestBase,
}
// Creates a synthesized KeyEvent that is not backed by a native event.
- 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;
+ ui::KeyEvent* GenerateSynthesizedKeyEvent(ui::EventType type,
+ ui::KeyboardCode code) {
+ return new ui::KeyEvent(type, code, 0, true);
}
// Creates a synthesized MouseEvent that is not backed by a native event.
@@ -259,11 +141,9 @@ class StickyKeysTest : public test::AshTestBase,
// Creates a synthesized mouse press or release event.
ui::MouseEvent* GenerateSynthesizedMouseClickEvent(
- bool is_button_press,
+ ui::EventType type,
const gfx::Point& location) {
- return GenerateSynthesizedMouseEventAt(
- is_button_press ? ui::ET_MOUSE_PRESSED : ui::ET_MOUSE_RELEASED,
- location);
+ return GenerateSynthesizedMouseEventAt(type, location);
}
// Creates a synthesized ET_MOUSE_MOVED event.
@@ -284,22 +164,28 @@ 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(true, key_code));
- handler->HandleKeyEvent(ev.get());
- ev.reset(GenerateKey(false, key_code));
- handler->HandleKeyEvent(ev.get());
+ 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);
}
- 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);
+ bool HandleKeyEvent(const ui::KeyEvent& key_event,
+ StickyKeysHandler* handler,
+ int* down,
+ bool* up) {
+ return handler->HandleKeyEvent(key_event, key_event.key_code(), down, up);
+ }
+
+ 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;
}
aura::Window* target() { return target_; }
@@ -318,9 +204,7 @@ class StickyKeysTest : public test::AshTestBase,
TEST_F(StickyKeysTest, BasicOneshotScenarioTest) {
scoped_ptr<ui::KeyEvent> ev;
- MockStickyKeysHandlerDelegate* mock_delegate =
- new MockStickyKeysHandlerDelegate(this);
- StickyKeysHandler sticky_key(ui::EF_SHIFT_DOWN, mock_delegate);
+ StickyKeysHandler sticky_key(ui::EF_SHIFT_DOWN);
EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
@@ -328,42 +212,42 @@ TEST_F(StickyKeysTest, BasicOneshotScenarioTest) {
SendActivateStickyKeyPattern(&sticky_key, ui::VKEY_SHIFT);
EXPECT_EQ(STICKY_KEY_STATE_ENABLED, sticky_key.current_state());
- ev.reset(GenerateKey(true, ui::VKEY_A));
- sticky_key.HandleKeyEvent(ev.get());
-
+ 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);
// Next keyboard event is shift modified.
- EXPECT_TRUE(ev->flags() & ui::EF_SHIFT_DOWN);
+ EXPECT_TRUE(mod_down_flags & ui::EF_SHIFT_DOWN);
+ // Modifier release notification happens.
+ EXPECT_TRUE(released);
- ev.reset(GenerateKey(false, ui::VKEY_A));
- sticky_key.HandleKeyEvent(ev.get());
+ 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);
EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
- // 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());
+ // 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());
EXPECT_EQ(ui::VKEY_SHIFT,
- static_cast<const ui::KeyEvent*>(mock_delegate->GetEvent(1))
- ->key_code());
+ static_cast<const ui::KeyEvent*>(up_event.get())->key_code());
// Enabled state is one shot, so next key event should not be shift modified.
- 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_PRESSED, 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);
+ 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);
}
TEST_F(StickyKeysTest, BasicLockedScenarioTest) {
scoped_ptr<ui::KeyEvent> ev;
- MockStickyKeysHandlerDelegate* mock_delegate =
- new MockStickyKeysHandlerDelegate(this);
- StickyKeysHandler sticky_key(ui::EF_SHIFT_DOWN, mock_delegate);
+ StickyKeysHandler sticky_key(ui::EF_SHIFT_DOWN);
EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
@@ -376,24 +260,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(true, ui::VKEY_A));
- sticky_key.HandleKeyEvent(ev.get());
- EXPECT_TRUE(ev->flags() & ui::EF_SHIFT_DOWN);
+ 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(false, 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);
// Locked state keeps after normal keyboard event.
EXPECT_EQ(STICKY_KEY_STATE_LOCKED, sticky_key.current_state());
- 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_PRESSED, 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);
+ 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);
EXPECT_EQ(STICKY_KEY_STATE_LOCKED, sticky_key.current_state());
@@ -404,146 +288,163 @@ TEST_F(StickyKeysTest, BasicLockedScenarioTest) {
TEST_F(StickyKeysTest, NonTargetModifierTest) {
scoped_ptr<ui::KeyEvent> ev;
- MockStickyKeysHandlerDelegate* mock_delegate =
- new MockStickyKeysHandlerDelegate(this);
- StickyKeysHandler sticky_key(ui::EF_SHIFT_DOWN, mock_delegate);
+ StickyKeysHandler sticky_key(ui::EF_SHIFT_DOWN);
EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
// Non target modifier key does not affect internal state
- ev.reset(GenerateKey(true, ui::VKEY_MENU));
- sticky_key.HandleKeyEvent(ev.get());
+ ev.reset(GenerateKey(ui::ET_KEY_PRESSED, ui::VKEY_MENU));
+ int mod_down_flags = HandleKeyEventForDownFlags(*ev.get(), &sticky_key);
EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
+ EXPECT_EQ(ui::EF_NONE, mod_down_flags);
- ev.reset(GenerateKey(false, ui::VKEY_MENU));
- sticky_key.HandleKeyEvent(ev.get());
+ ev.reset(GenerateKey(ui::ET_KEY_RELEASED, ui::VKEY_MENU));
+ mod_down_flags = HandleKeyEventForDownFlags(*ev.get(), &sticky_key);
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(true, ui::VKEY_MENU));
- sticky_key.HandleKeyEvent(ev.get());
+ ev.reset(GenerateKey(ui::ET_KEY_PRESSED, ui::VKEY_MENU));
+ mod_down_flags = HandleKeyEventForDownFlags(*ev.get(), &sticky_key);
EXPECT_EQ(STICKY_KEY_STATE_ENABLED, sticky_key.current_state());
+ EXPECT_EQ(ui::EF_NONE, mod_down_flags);
- ev.reset(GenerateKey(false, ui::VKEY_MENU));
- sticky_key.HandleKeyEvent(ev.get());
+ ev.reset(GenerateKey(ui::ET_KEY_RELEASED, ui::VKEY_MENU));
+ mod_down_flags = HandleKeyEventForDownFlags(*ev.get(), &sticky_key);
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(true, ui::VKEY_MENU));
- sticky_key.HandleKeyEvent(ev.get());
+ ev.reset(GenerateKey(ui::ET_KEY_PRESSED, ui::VKEY_MENU));
+ mod_down_flags = HandleKeyEventForDownFlags(*ev.get(), &sticky_key);
EXPECT_EQ(STICKY_KEY_STATE_LOCKED, sticky_key.current_state());
+ EXPECT_EQ(ui::EF_NONE, mod_down_flags);
- ev.reset(GenerateKey(false, ui::VKEY_MENU));
- sticky_key.HandleKeyEvent(ev.get());
+ ev.reset(GenerateKey(ui::ET_KEY_RELEASED, ui::VKEY_MENU));
+ mod_down_flags = HandleKeyEventForDownFlags(*ev.get(), &sticky_key);
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;
- MockStickyKeysHandlerDelegate* mock_delegate =
- new MockStickyKeysHandlerDelegate(this);
- StickyKeysHandler sticky_key(ui::EF_CONTROL_DOWN, mock_delegate);
+ StickyKeysHandler sticky_key(ui::EF_CONTROL_DOWN);
EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
// Perform ctrl+n shortcut.
- 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());
+ 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);
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;
- MockStickyKeysHandlerDelegate* mock_delegate =
- new MockStickyKeysHandlerDelegate(this);
- StickyKeysHandler sticky_key(ui::EF_CONTROL_DOWN, mock_delegate);
+ StickyKeysHandler sticky_key(ui::EF_CONTROL_DOWN);
EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
// Perform ctrl+click.
- 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());
+ 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);
// Sticky keys should not be enabled afterwards.
- kev.reset(GenerateKey(false, ui::VKEY_CONTROL));
- sticky_key.HandleKeyEvent(kev.get());
+ kev.reset(GenerateKey(ui::ET_KEY_RELEASED, ui::VKEY_CONTROL));
+ mod_down_flags = HandleKeyEventForDownFlags(*kev.get(), &sticky_key);
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;
- MockStickyKeysHandlerDelegate* mock_delegate =
- new MockStickyKeysHandlerDelegate(this);
- StickyKeysHandler sticky_key(ui::EF_CONTROL_DOWN, mock_delegate);
+ StickyKeysHandler sticky_key(ui::EF_CONTROL_DOWN);
EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
// Press ctrl and handle mouse move events.
- kev.reset(GenerateKey(true, ui::VKEY_CONTROL));
- sticky_key.HandleKeyEvent(kev.get());
+ kev.reset(GenerateKey(ui::ET_KEY_PRESSED, ui::VKEY_CONTROL));
+ int mod_down_flags = HandleKeyEventForDownFlags(*kev.get(), &sticky_key);
mev.reset(GenerateSynthesizedMouseMoveEvent(gfx::Point(0, 0)));
- sticky_key.HandleMouseEvent(mev.get());
+ bool released = false;
+ sticky_key.HandleMouseEvent(*mev.get(), &mod_down_flags, &released);
mev.reset(GenerateSynthesizedMouseMoveEvent(gfx::Point(100, 100)));
- sticky_key.HandleMouseEvent(mev.get());
+ sticky_key.HandleMouseEvent(*mev.get(), &mod_down_flags, &released);
// Sticky keys should be enabled afterwards.
- kev.reset(GenerateKey(false, ui::VKEY_CONTROL));
- sticky_key.HandleKeyEvent(kev.get());
+ kev.reset(GenerateKey(ui::ET_KEY_RELEASED, ui::VKEY_CONTROL));
+ mod_down_flags = HandleKeyEventForDownFlags(*kev.get(), &sticky_key);
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;
- MockStickyKeysHandlerDelegate* mock_delegate =
- new MockStickyKeysHandlerDelegate(this);
- StickyKeysHandler sticky_key(ui::EF_CONTROL_DOWN, mock_delegate);
+ StickyKeysHandler sticky_key(ui::EF_CONTROL_DOWN);
EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
// Perform ctrl+scroll.
- kev.reset(GenerateKey(true, ui::VKEY_CONTROL));
+ kev.reset(GenerateKey(ui::ET_KEY_PRESSED, ui::VKEY_CONTROL));
+ int mod_down_flags = HandleKeyEventForDownFlags(*kev.get(), &sticky_key);
sev.reset(GenerateFlingScrollEvent(0, true));
- sticky_key.HandleScrollEvent(sev.get());
+ bool released = false;
+ sticky_key.HandleScrollEvent(*sev.get(), &mod_down_flags, &released);
sev.reset(GenerateScrollEvent(10));
- sticky_key.HandleScrollEvent(sev.get());
+ sticky_key.HandleScrollEvent(*sev.get(), &mod_down_flags, &released);
sev.reset(GenerateFlingScrollEvent(10, false));
- sticky_key.HandleScrollEvent(sev.get());
+ sticky_key.HandleScrollEvent(*sev.get(), &mod_down_flags, &released);
// Sticky keys should not be enabled afterwards.
- kev.reset(GenerateKey(false, ui::VKEY_CONTROL));
- sticky_key.HandleKeyEvent(kev.get());
+ kev.reset(GenerateKey(ui::ET_KEY_RELEASED, ui::VKEY_CONTROL));
+ mod_down_flags = HandleKeyEventForDownFlags(*kev.get(), &sticky_key);
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;
- MockStickyKeysHandlerDelegate* mock_delegate =
- new MockStickyKeysHandlerDelegate(this);
- StickyKeysHandler sticky_key(ui::EF_CONTROL_DOWN, mock_delegate);
+ StickyKeysHandler sticky_key(ui::EF_CONTROL_DOWN);
EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
SendActivateStickyKeyPattern(&sticky_key, ui::VKEY_CONTROL);
@@ -551,40 +452,47 @@ TEST_F(StickyKeysTest, MouseEventOneshot) {
// We should still be in the ENABLED state until we get the mouse
// release event.
- ev.reset(GenerateMouseEvent(true));
- sticky_key.HandleMouseEvent(ev.get());
- EXPECT_TRUE(ev->flags() & ui::EF_CONTROL_DOWN);
+ 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);
EXPECT_EQ(STICKY_KEY_STATE_ENABLED, sticky_key.current_state());
- ev.reset(GenerateMouseEvent(false));
- sticky_key.HandleMouseEvent(ev.get());
- EXPECT_TRUE(ev->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);
EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
// Making sure modifier key release event is dispatched in the right order.
- 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_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());
EXPECT_EQ(ui::VKEY_CONTROL,
- static_cast<const ui::KeyEvent*>(mock_delegate->GetEvent(1))
- ->key_code());
+ static_cast<const ui::KeyEvent*>(up_event.get())->key_code());
// Enabled state is one shot, so next click should not be control modified.
- 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);
+ 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);
}
TEST_F(StickyKeysTest, MouseEventLocked) {
scoped_ptr<ui::MouseEvent> ev;
scoped_ptr<ui::KeyEvent> kev;
- MockStickyKeysHandlerDelegate* mock_delegate =
- new MockStickyKeysHandlerDelegate(this);
- StickyKeysHandler sticky_key(ui::EF_CONTROL_DOWN, mock_delegate);
+ StickyKeysHandler sticky_key(ui::EF_CONTROL_DOWN);
EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
@@ -596,35 +504,44 @@ TEST_F(StickyKeysTest, MouseEventLocked) {
// Mouse events should not disable locked mode.
for (int i = 0; i < 3; ++i) {
- 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);
+ 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);
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());
+ sticky_key.HandleMouseEvent(*ev.get(), &mod_down_flags, &released);
ev.reset(GenerateMouseWheelEvent(-ui::MouseWheelEvent::kWheelDelta));
- sticky_key.HandleMouseEvent(ev.get());
- EXPECT_TRUE(ev->flags() & ui::EF_CONTROL_DOWN);
+ released = false;
+ mod_down_flags = 0;
+ sticky_key.HandleMouseEvent(*ev.get(), &mod_down_flags, &released);
+ EXPECT_TRUE(mod_down_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));
- 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);
+ 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);
EXPECT_EQ(STICKY_KEY_STATE_LOCKED, sticky_key.current_state());
}
@@ -632,14 +549,10 @@ TEST_F(StickyKeysTest, MouseEventLocked) {
TEST_F(StickyKeysTest, ScrollEventOneshot) {
scoped_ptr<ui::ScrollEvent> ev;
scoped_ptr<ui::KeyEvent> kev;
- MockStickyKeysHandlerDelegate* mock_delegate =
- new MockStickyKeysHandlerDelegate(this);
- StickyKeysHandler sticky_key(ui::EF_CONTROL_DOWN, mock_delegate);
+ StickyKeysHandler sticky_key(ui::EF_CONTROL_DOWN);
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);
@@ -648,42 +561,44 @@ 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));
- sticky_key.HandleScrollEvent(ev.get());
- EXPECT_TRUE(ev->flags() & ui::EF_CONTROL_DOWN);
+ 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);
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]));
- sticky_key.HandleScrollEvent(ev.get());
- EXPECT_TRUE(ev->flags() & ui::EF_CONTROL_DOWN);
+ released = false;
+ mod_down_flags = 0;
+ sticky_key.HandleScrollEvent(*ev.get(), &mod_down_flags, &released);
+ EXPECT_TRUE(mod_down_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));
- sticky_key.HandleScrollEvent(ev.get());
- EXPECT_TRUE(ev->flags() & ui::EF_CONTROL_DOWN);
+ released = false;
+ mod_down_flags = 0;
+ sticky_key.HandleScrollEvent(*ev.get(), &mod_down_flags, &released);
+ EXPECT_TRUE(mod_down_flags & ui::EF_CONTROL_DOWN);
EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
- 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());
+ 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());
EXPECT_EQ(ui::VKEY_CONTROL,
- static_cast<const ui::KeyEvent*>(mock_delegate->GetEvent(1))
- ->key_code());
+ static_cast<const ui::KeyEvent*>(up_event.get())->key_code());
}
}
TEST_F(StickyKeysTest, ScrollDirectionChanged) {
scoped_ptr<ui::ScrollEvent> ev;
scoped_ptr<ui::KeyEvent> kev;
- MockStickyKeysHandlerDelegate* mock_delegate =
- new MockStickyKeysHandlerDelegate(this);
- StickyKeysHandler sticky_key(ui::EF_CONTROL_DOWN, mock_delegate);
+ StickyKeysHandler sticky_key(ui::EF_CONTROL_DOWN);
// Test direction change with both boundary value and negative value.
const int direction_change_values[2] = {0, -10};
@@ -693,21 +608,26 @@ TEST_F(StickyKeysTest, ScrollDirectionChanged) {
// Fling cancel starts scroll sequence.
ev.reset(GenerateFlingScrollEvent(0, true));
- sticky_key.HandleScrollEvent(ev.get());
+ bool released = false;
+ int mod_down_flags = 0;
+ sticky_key.HandleScrollEvent(*ev.get(), &mod_down_flags, &released);
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));
- sticky_key.HandleScrollEvent(ev.get());
- EXPECT_TRUE(ev->flags() & ui::EF_CONTROL_DOWN);
+ released = false;
+ mod_down_flags = 0;
+ sticky_key.HandleScrollEvent(*ev.get(), &mod_down_flags, &released);
+ EXPECT_TRUE(mod_down_flags & ui::EF_CONTROL_DOWN);
EXPECT_EQ(STICKY_KEY_STATE_ENABLED, sticky_key.current_state());
}
ev.reset(GenerateScrollEvent(direction_change_values[i]));
- sticky_key.HandleScrollEvent(ev.get());
- EXPECT_FALSE(ev->flags() & ui::EF_CONTROL_DOWN);
+ released = false;
+ mod_down_flags = 0;
+ sticky_key.HandleScrollEvent(*ev.get(), &mod_down_flags, &released);
EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
}
}
@@ -715,9 +635,7 @@ TEST_F(StickyKeysTest, ScrollDirectionChanged) {
TEST_F(StickyKeysTest, ScrollEventLocked) {
scoped_ptr<ui::ScrollEvent> ev;
scoped_ptr<ui::KeyEvent> kev;
- MockStickyKeysHandlerDelegate* mock_delegate =
- new MockStickyKeysHandlerDelegate(this);
- StickyKeysHandler sticky_key(ui::EF_CONTROL_DOWN, mock_delegate);
+ StickyKeysHandler sticky_key(ui::EF_CONTROL_DOWN);
// Lock sticky keys.
SendActivateStickyKeyPattern(&sticky_key, ui::VKEY_CONTROL);
@@ -728,63 +646,45 @@ TEST_F(StickyKeysTest, ScrollEventLocked) {
for (int i = 0; i < 5; ++i) {
// Fling cancel starts scroll sequence.
ev.reset(GenerateFlingScrollEvent(0, true));
- sticky_key.HandleScrollEvent(ev.get());
+ bool released = false;
+ int mod_down_flags = 0;
+ sticky_key.HandleScrollEvent(*ev.get(), &mod_down_flags, &released);
ev.reset(GenerateScrollEvent(10));
- sticky_key.HandleScrollEvent(ev.get());
- EXPECT_TRUE(ev->flags() & ui::EF_CONTROL_DOWN);
+ released = false;
+ mod_down_flags = 0;
+ sticky_key.HandleScrollEvent(*ev.get(), &mod_down_flags, &released);
+ EXPECT_TRUE(mod_down_flags & ui::EF_CONTROL_DOWN);
ev.reset(GenerateScrollEvent(-10));
- sticky_key.HandleScrollEvent(ev.get());
- EXPECT_TRUE(ev->flags() & ui::EF_CONTROL_DOWN);
+ sticky_key.HandleScrollEvent(*ev.get(), &mod_down_flags, &released);
+ EXPECT_TRUE(mod_down_flags & ui::EF_CONTROL_DOWN);
// Fling start ends scroll sequence.
ev.reset(GenerateFlingScrollEvent(-10, false));
- sticky_key.HandleScrollEvent(ev.get());
+ sticky_key.HandleScrollEvent(*ev.get(), &mod_down_flags, &released);
}
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.
- MockStickyKeysHandlerDelegate* mock_delegate =
- new MockStickyKeysHandlerDelegate(this);
- StickyKeysHandler sticky_key(ui::EF_CONTROL_DOWN, mock_delegate);
+ StickyKeysHandler sticky_key(ui::EF_CONTROL_DOWN);
// 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(true, ui::VKEY_K));
- sticky_key.HandleKeyEvent(kev.get());
- EXPECT_TRUE(kev->flags() & ui::EF_CONTROL_DOWN);
+ 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);
EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
- kev.reset(GenerateSynthesizedKeyEvent(false, ui::VKEY_K));
- sticky_key.HandleKeyEvent(kev.get());
- EXPECT_FALSE(kev->flags() & ui::EF_CONTROL_DOWN);
+ 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);
EXPECT_EQ(STICKY_KEY_STATE_DISABLED, sticky_key.current_state());
// Test non-native mouse events.
@@ -792,216 +692,21 @@ TEST_F(StickyKeysTest, SynthesizedEvents) {
EXPECT_EQ(STICKY_KEY_STATE_ENABLED, sticky_key.current_state());
scoped_ptr<ui::MouseEvent> mev;
- mev.reset(GenerateSynthesizedMouseClickEvent(true, gfx::Point(0, 0)));
- sticky_key.HandleMouseEvent(mev.get());
- EXPECT_TRUE(mev->flags() & ui::EF_CONTROL_DOWN);
+ 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);
EXPECT_EQ(STICKY_KEY_STATE_ENABLED, sticky_key.current_state());
- mev.reset(GenerateSynthesizedMouseClickEvent(false, gfx::Point(0, 0)));
- sticky_key.HandleMouseEvent(mev.get());
- EXPECT_TRUE(mev->flags() & ui::EF_CONTROL_DOWN);
+ 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);
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
diff --git a/chrome/browser/chromeos/chrome_browser_main_chromeos.cc b/chrome/browser/chromeos/chrome_browser_main_chromeos.cc
index fa32096..03c8571 100644
--- a/chrome/browser/chromeos/chrome_browser_main_chromeos.cc
+++ b/chrome/browser/chromeos/chrome_browser_main_chromeos.cc
@@ -730,11 +730,6 @@ void ChromeBrowserMainPartsChromeos::PreBrowserStart() {
// Start the CrOS input device UMA watcher
DeviceUMA::GetInstance();
#endif
- keyboard_event_rewriters_.reset(new EventRewriterController());
- keyboard_event_rewriters_->AddEventRewriter(
- scoped_ptr<ui::EventRewriter>(new KeyboardDrivenEventRewriter()));
- keyboard_event_rewriters_->AddEventRewriter(
- scoped_ptr<ui::EventRewriter>(new EventRewriter()));
// -- This used to be in ChromeBrowserMainParts::PreMainMessageLoopRun()
// -- immediately after ChildProcess::WaitForDebugger().
@@ -757,7 +752,13 @@ void ChromeBrowserMainPartsChromeos::PostBrowserStart() {
// These are dependent on the ash::Shell singleton already having been
// initialized.
power_button_observer_.reset(new PowerButtonObserver);
- data_promo_notification_.reset(new DataPromoNotification()),
+ data_promo_notification_.reset(new DataPromoNotification());
+
+ keyboard_event_rewriters_.reset(new EventRewriterController());
+ keyboard_event_rewriters_->AddEventRewriter(
+ scoped_ptr<ui::EventRewriter>(new KeyboardDrivenEventRewriter()));
+ keyboard_event_rewriters_->AddEventRewriter(scoped_ptr<ui::EventRewriter>(
+ new EventRewriter(ash::Shell::GetInstance()->sticky_keys_controller())));
keyboard_event_rewriters_->Init();
ChromeBrowserMainPartsLinux::PostBrowserStart();
diff --git a/chrome/browser/chromeos/events/event_rewriter.cc b/chrome/browser/chromeos/events/event_rewriter.cc
index eee24f7..d7e0bcb 100644
--- a/chrome/browser/chromeos/events/event_rewriter.cc
+++ b/chrome/browser/chromeos/events/event_rewriter.cc
@@ -6,10 +6,12 @@
#include <vector>
+#include "ash/sticky_keys/sticky_keys_controller.h"
#include "ash/wm/window_state.h"
#include "ash/wm/window_util.h"
#include "base/command_line.h"
#include "base/logging.h"
+#include "base/macros.h"
#include "base/prefs/pref_service.h"
#include "base/strings/string_util.h"
#include "base/sys_info.h"
@@ -153,12 +155,24 @@ void UpdateX11EventMask(int ui_flags, unsigned int* x_flags) {
}
#endif
+bool IsSendEvent(const ui::Event& event) {
+#if defined(USE_X11)
+ // Do not rewrite an event sent by ui_controls::SendKeyPress(). See
+ // crbug.com/136465.
+ XEvent* xev = event.native_event();
+ if (xev && xev->xany.send_event)
+ return true;
+#endif
+ return false;
+}
+
} // namespace
-EventRewriter::EventRewriter()
+EventRewriter::EventRewriter(ash::StickyKeysController* sticky_keys_controller)
: last_device_id_(kBadDeviceId),
ime_keyboard_for_testing_(NULL),
- pref_service_for_testing_(NULL) {
+ pref_service_for_testing_(NULL),
+ sticky_keys_controller_(sticky_keys_controller) {
#if defined(USE_X11)
ui::PlatformEventSource::GetInstance()->AddPlatformEventObserver(this);
if (base::SysInfo::IsRunningOnChromeOS()) {
@@ -190,35 +204,38 @@ void EventRewriter::RewriteLocatedEventForTesting(const ui::Event& event,
ui::EventRewriteStatus EventRewriter::RewriteEvent(
const ui::Event& event,
scoped_ptr<ui::Event>* rewritten_event) {
-#if defined(USE_X11)
- // Do not rewrite an event sent by ui_controls::SendKeyPress(). See
- // crbug.com/136465.
- XEvent* xev = event.native_event();
- if (xev && xev->xany.send_event)
- return ui::EVENT_REWRITE_CONTINUE;
-#endif
- switch (event.type()) {
- case ui::ET_KEY_PRESSED:
- case ui::ET_KEY_RELEASED:
- return RewriteKeyEvent(static_cast<const ui::KeyEvent&>(event),
+ if ((event.type() == ui::ET_KEY_PRESSED) ||
+ (event.type() == ui::ET_KEY_RELEASED)) {
+ return RewriteKeyEvent(static_cast<const ui::KeyEvent&>(event),
+ rewritten_event);
+ }
+ if (event.IsMouseEvent()) {
+ return RewriteMouseEvent(static_cast<const ui::MouseEvent&>(event),
rewritten_event);
- case ui::ET_MOUSE_PRESSED:
- case ui::ET_MOUSE_RELEASED:
- return RewriteMouseEvent(static_cast<const ui::MouseEvent&>(event),
- rewritten_event);
- case ui::ET_TOUCH_PRESSED:
- case ui::ET_TOUCH_RELEASED:
- return RewriteTouchEvent(static_cast<const ui::TouchEvent&>(event),
- rewritten_event);
- default:
- return ui::EVENT_REWRITE_CONTINUE;
}
- NOTREACHED();
+ if ((event.type() == ui::ET_TOUCH_PRESSED) ||
+ (event.type() == ui::ET_TOUCH_RELEASED)) {
+ return RewriteTouchEvent(static_cast<const ui::TouchEvent&>(event),
+ rewritten_event);
+ }
+ if (event.IsScrollEvent()) {
+ return RewriteScrollEvent(static_cast<const ui::ScrollEvent&>(event),
+ rewritten_event);
+ }
+ return ui::EVENT_REWRITE_CONTINUE;
}
ui::EventRewriteStatus EventRewriter::NextDispatchEvent(
const ui::Event& last_event,
scoped_ptr<ui::Event>* new_event) {
+ if (sticky_keys_controller_) {
+ // In the case of sticky keys, we know what the events obtained here are:
+ // modifier key releases that match the ones previously discarded. So, we
+ // know that they don't have to be passed through the post-sticky key
+ // rewriting phases, |RewriteExtendedKeys()| and |RewriteFunctionKeys()|,
+ // because those phases do nothing with modifier key releases.
+ return sticky_keys_controller_->NextDispatchEvent(new_event);
+ }
NOTREACHED();
return ui::EVENT_REWRITE_CONTINUE;
}
@@ -333,14 +350,33 @@ ui::EventRewriteStatus EventRewriter::RewriteKeyEvent(
const ui::KeyEvent& key_event,
scoped_ptr<ui::Event>* rewritten_event) {
MutableKeyState state = {key_event.flags(), key_event.key_code()};
- RewriteModifierKeys(key_event, &state);
- RewriteNumPadKeys(key_event, &state);
- RewriteExtendedKeys(key_event, &state);
- RewriteFunctionKeys(key_event, &state);
+ bool is_send_event = IsSendEvent(key_event);
+ if (!is_send_event) {
+ RewriteModifierKeys(key_event, &state);
+ RewriteNumPadKeys(key_event, &state);
+ }
+ ui::EventRewriteStatus status = ui::EVENT_REWRITE_CONTINUE;
+ if (sticky_keys_controller_) {
+ status = sticky_keys_controller_->RewriteKeyEvent(
+ key_event, state.key_code, &state.flags);
+ if (status == ui::EVENT_REWRITE_DISCARD)
+ return ui::EVENT_REWRITE_DISCARD;
+ }
+ if (!is_send_event) {
+ RewriteExtendedKeys(key_event, &state);
+ RewriteFunctionKeys(key_event, &state);
+ }
if ((key_event.flags() == state.flags) &&
- (key_event.key_code() == state.key_code)) {
+ (key_event.key_code() == state.key_code) &&
+ (status == ui::EVENT_REWRITE_CONTINUE)) {
return ui::EVENT_REWRITE_CONTINUE;
}
+ // Sticky keys may have returned a result other than |EVENT_REWRITE_CONTINUE|,
+ // in which case we need to preserve that return status. Alternatively, we
+ // might be here because key_event changed, in which case we need to return
+ // |EVENT_REWRITE_REWRITTEN|.
+ if (status == ui::EVENT_REWRITE_CONTINUE)
+ status = ui::EVENT_REWRITE_REWRITTEN;
ui::KeyEvent* rewritten_key_event = new ui::KeyEvent(key_event);
rewritten_event->reset(rewritten_key_event);
rewritten_key_event->set_flags(state.flags);
@@ -360,16 +396,26 @@ ui::EventRewriteStatus EventRewriter::RewriteKeyEvent(
state.key_code, state.flags & ui::EF_SHIFT_DOWN));
}
#endif
- return ui::EVENT_REWRITE_REWRITTEN;
+ return status;
}
ui::EventRewriteStatus EventRewriter::RewriteMouseEvent(
const ui::MouseEvent& mouse_event,
scoped_ptr<ui::Event>* rewritten_event) {
int flags = mouse_event.flags();
- RewriteLocatedEvent(mouse_event, &flags);
- if (mouse_event.flags() == flags)
+ if ((mouse_event.type() == ui::ET_MOUSE_PRESSED) ||
+ (mouse_event.type() == ui::ET_MOUSE_RELEASED)) {
+ RewriteLocatedEvent(mouse_event, &flags);
+ }
+ ui::EventRewriteStatus status = ui::EVENT_REWRITE_CONTINUE;
+ if (sticky_keys_controller_)
+ status = sticky_keys_controller_->RewriteMouseEvent(mouse_event, &flags);
+ if ((mouse_event.flags() == flags) &&
+ (status == ui::EVENT_REWRITE_CONTINUE)) {
return ui::EVENT_REWRITE_CONTINUE;
+ }
+ if (status == ui::EVENT_REWRITE_CONTINUE)
+ status = ui::EVENT_REWRITE_REWRITTEN;
ui::MouseEvent* rewritten_mouse_event = new ui::MouseEvent(mouse_event);
rewritten_event->reset(rewritten_mouse_event);
rewritten_mouse_event->set_flags(flags);
@@ -397,7 +443,7 @@ ui::EventRewriteStatus EventRewriter::RewriteMouseEvent(
}
}
#endif
- return ui::EVENT_REWRITE_REWRITTEN;
+ return status;
}
ui::EventRewriteStatus EventRewriter::RewriteTouchEvent(
@@ -424,6 +470,32 @@ ui::EventRewriteStatus EventRewriter::RewriteTouchEvent(
return ui::EVENT_REWRITE_REWRITTEN;
}
+ui::EventRewriteStatus EventRewriter::RewriteScrollEvent(
+ const ui::ScrollEvent& scroll_event,
+ scoped_ptr<ui::Event>* rewritten_event) {
+ int flags = scroll_event.flags();
+ ui::EventRewriteStatus status = ui::EVENT_REWRITE_CONTINUE;
+ if (sticky_keys_controller_)
+ status = sticky_keys_controller_->RewriteScrollEvent(scroll_event, &flags);
+ if (status == ui::EVENT_REWRITE_CONTINUE)
+ return status;
+ ui::ScrollEvent* rewritten_scroll_event = new ui::ScrollEvent(scroll_event);
+ rewritten_event->reset(rewritten_scroll_event);
+ rewritten_scroll_event->set_flags(flags);
+#if defined(USE_X11)
+ XEvent* xev = rewritten_scroll_event->native_event();
+ if (xev) {
+ XIDeviceEvent* xievent = static_cast<XIDeviceEvent*>(xev->xcookie.data);
+ if (xievent) {
+ UpdateX11EventMask(
+ rewritten_scroll_event->flags(),
+ reinterpret_cast<unsigned int*>(&xievent->mods.effective));
+ }
+ }
+#endif
+ return status;
+}
+
void EventRewriter::RewriteModifierKeys(const ui::KeyEvent& key_event,
MutableKeyState* state) {
DCHECK(key_event.type() == ui::ET_KEY_PRESSED ||
diff --git a/chrome/browser/chromeos/events/event_rewriter.h b/chrome/browser/chromeos/events/event_rewriter.h
index 3763a89..1c946c9 100644
--- a/chrome/browser/chromeos/events/event_rewriter.h
+++ b/chrome/browser/chromeos/events/event_rewriter.h
@@ -23,6 +23,10 @@ typedef union _XEvent XEvent;
class PrefService;
+namespace ash {
+class StickyKeysController;
+}
+
namespace chromeos {
namespace input_method {
class ImeKeyboard;
@@ -51,7 +55,10 @@ class EventRewriter
kDeviceAppleKeyboard,
};
- EventRewriter();
+ // Does not take ownership of the |sticky_keys_controller|, which may also
+ // be NULL (for testing without ash), in which case sticky key operations
+ // don't happen.
+ explicit EventRewriter(ash::StickyKeysController* sticky_keys_controller);
virtual ~EventRewriter();
// Calls DeviceAddedInternal.
@@ -98,7 +105,7 @@ class EventRewriter
#endif
private:
- // Things that internal rewriter phases can change about an Event.
+ // Things that keyboard-related rewriter phases can change about an Event.
struct MutableKeyState {
int flags;
ui::KeyboardCode key_code;
@@ -157,6 +164,9 @@ class EventRewriter
ui::EventRewriteStatus RewriteTouchEvent(
const ui::TouchEvent& touch_event,
scoped_ptr<ui::Event>* rewritten_event);
+ ui::EventRewriteStatus RewriteScrollEvent(
+ const ui::ScrollEvent& scroll_event,
+ scoped_ptr<ui::Event>* rewritten_event);
// Rewriter phases. These can inspect the original |event|, but operate using
// the current |state|, which may have been modified by previous phases.
@@ -175,6 +185,10 @@ class EventRewriter
chromeos::input_method::ImeKeyboard* ime_keyboard_for_testing_;
const PrefService* pref_service_for_testing_;
+ // The sticky keys controller is not owned here;
+ // at time of writing it is a singleton in ash::Shell>
+ ash::StickyKeysController* sticky_keys_controller_;
+
DISALLOW_COPY_AND_ASSIGN(EventRewriter);
};
diff --git a/chrome/browser/chromeos/events/event_rewriter_unittest.cc b/chrome/browser/chromeos/events/event_rewriter_unittest.cc
index 6b350ee..4b3a244 100644
--- a/chrome/browser/chromeos/events/event_rewriter_unittest.cc
+++ b/chrome/browser/chromeos/events/event_rewriter_unittest.cc
@@ -4,15 +4,11 @@
#include "chrome/browser/chromeos/events/event_rewriter.h"
-#include <X11/keysym.h>
-#include <X11/XF86keysym.h>
-#include <X11/Xlib.h>
-#undef Bool
-#undef None
-#undef RootWindow
-
#include <vector>
+#include "ash/shell.h"
+#include "ash/sticky_keys/sticky_keys_controller.h"
+#include "ash/sticky_keys/sticky_keys_overlay.h"
#include "ash/test/ash_test_base.h"
#include "ash/wm/window_state.h"
#include "base/basictypes.h"
@@ -30,14 +26,24 @@
#include "chromeos/ime/fake_ime_keyboard.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/aura/window.h"
+#include "ui/aura/window_tree_host.h"
#include "ui/events/event.h"
#include "ui/events/event_rewriter.h"
+#include "ui/events/test/test_event_processor.h"
+
+#if defined(USE_X11)
+#include <X11/keysym.h>
+
#include "ui/events/test/events_test_utils_x11.h"
#include "ui/events/x/touch_factory_x11.h"
#include "ui/gfx/x/x11_types.h"
+#endif
namespace {
+// The device id of the test touchpad device.
+const unsigned int kTouchPadDeviceId = 1;
+
std::string GetExpectedResultAsString(ui::KeyboardCode ui_keycode,
int ui_flags,
ui::EventType ui_type) {
@@ -192,8 +198,7 @@ namespace chromeos {
class EventRewriterTest : public ash::test::AshTestBase {
public:
EventRewriterTest()
- : display_(gfx::GetXDisplay()),
- mock_user_manager_(new chromeos::MockUserManager),
+ : mock_user_manager_(new chromeos::MockUserManager),
user_manager_enabler_(mock_user_manager_),
input_method_manager_mock_(NULL) {}
virtual ~EventRewriterTest() {}
@@ -227,7 +232,6 @@ class EventRewriterTest : public ash::test::AshTestBase {
return flags;
}
- Display* display_;
chromeos::MockUserManager* mock_user_manager_; // Not owned.
chromeos::ScopedUserManagerEnabler user_manager_enabler_;
chromeos::input_method::MockInputMethodManager* input_method_manager_mock_;
@@ -236,7 +240,7 @@ class EventRewriterTest : public ash::test::AshTestBase {
TEST_F(EventRewriterTest, TestRewriteCommandToControl) {
// First, test with a PC keyboard.
TestingPrefServiceSyncable prefs;
- EventRewriter rewriter;
+ EventRewriter rewriter(NULL);
rewriter.DeviceAddedForTesting(0, "PC Keyboard");
rewriter.set_last_device_id_for_testing(0);
rewriter.set_pref_service_for_testing(&prefs);
@@ -317,7 +321,7 @@ TEST_F(EventRewriterTest, TestRewriteCommandToControlWithControlRemapped) {
control.Init(prefs::kLanguageRemapControlKeyTo, &prefs);
control.SetValue(chromeos::input_method::kAltKey);
- EventRewriter rewriter;
+ EventRewriter rewriter(NULL);
rewriter.set_pref_service_for_testing(&prefs);
rewriter.DeviceAddedForTesting(0, "PC Keyboard");
rewriter.set_last_device_id_for_testing(0);
@@ -357,7 +361,7 @@ TEST_F(EventRewriterTest, TestRewriteCommandToControlWithControlRemapped) {
void EventRewriterTest::TestRewriteNumPadKeys() {
TestingPrefServiceSyncable prefs;
- EventRewriter rewriter;
+ EventRewriter rewriter(NULL);
rewriter.set_pref_service_for_testing(&prefs);
KeyTestCase tests[] = {
@@ -499,7 +503,7 @@ TEST_F(EventRewriterTest, TestRewriteNumPadKeysWithDiamondKeyFlag) {
// Tests if the rewriter can handle a Command + Num Pad event.
void EventRewriterTest::TestRewriteNumPadKeysOnAppleKeyboard() {
TestingPrefServiceSyncable prefs;
- EventRewriter rewriter;
+ EventRewriter rewriter(NULL);
rewriter.DeviceAddedForTesting(0, "Apple Keyboard");
rewriter.set_last_device_id_for_testing(0);
rewriter.set_pref_service_for_testing(&prefs);
@@ -541,7 +545,7 @@ TEST_F(EventRewriterTest,
TEST_F(EventRewriterTest, TestRewriteModifiersNoRemap) {
TestingPrefServiceSyncable prefs;
- EventRewriter rewriter;
+ EventRewriter rewriter(NULL);
rewriter.set_pref_service_for_testing(&prefs);
KeyTestCase tests[] = {
@@ -584,7 +588,7 @@ TEST_F(EventRewriterTest, TestRewriteModifiersNoRemap) {
TEST_F(EventRewriterTest, TestRewriteModifiersNoRemapMultipleKeys) {
TestingPrefServiceSyncable prefs;
- EventRewriter rewriter;
+ EventRewriter rewriter(NULL);
rewriter.set_pref_service_for_testing(&prefs);
KeyTestCase tests[] = {
@@ -627,7 +631,7 @@ TEST_F(EventRewriterTest, TestRewriteModifiersDisableSome) {
control.Init(prefs::kLanguageRemapControlKeyTo, &prefs);
control.SetValue(chromeos::input_method::kVoidKey);
- EventRewriter rewriter;
+ EventRewriter rewriter(NULL);
rewriter.set_pref_service_for_testing(&prefs);
KeyTestCase disabled_modifier_tests[] = {
@@ -702,7 +706,7 @@ TEST_F(EventRewriterTest, TestRewriteModifiersRemapToControl) {
search.Init(prefs::kLanguageRemapSearchKeyTo, &prefs);
search.SetValue(chromeos::input_method::kControlKey);
- EventRewriter rewriter;
+ EventRewriter rewriter(NULL);
rewriter.set_pref_service_for_testing(&prefs);
KeyTestCase s_tests[] = {
@@ -766,7 +770,7 @@ TEST_F(EventRewriterTest, TestRewriteModifiersRemapToEscape) {
search.Init(prefs::kLanguageRemapSearchKeyTo, &prefs);
search.SetValue(chromeos::input_method::kEscapeKey);
- EventRewriter rewriter;
+ EventRewriter rewriter(NULL);
rewriter.set_pref_service_for_testing(&prefs);
KeyTestCase tests[] = {// Press Search. Confirm the event is now VKEY_ESCAPE.
@@ -788,7 +792,7 @@ TEST_F(EventRewriterTest, TestRewriteModifiersRemapMany) {
search.Init(prefs::kLanguageRemapSearchKeyTo, &prefs);
search.SetValue(chromeos::input_method::kAltKey);
- EventRewriter rewriter;
+ EventRewriter rewriter(NULL);
rewriter.set_pref_service_for_testing(&prefs);
KeyTestCase s2a_tests[] = {
@@ -865,7 +869,7 @@ TEST_F(EventRewriterTest, TestRewriteModifiersRemapToCapsLock) {
search.SetValue(chromeos::input_method::kCapsLockKey);
chromeos::input_method::FakeImeKeyboard ime_keyboard;
- EventRewriter rewriter;
+ EventRewriter rewriter(NULL);
rewriter.set_pref_service_for_testing(&prefs);
rewriter.set_ime_keyboard_for_testing(&ime_keyboard);
EXPECT_FALSE(ime_keyboard.caps_lock_is_enabled_);
@@ -935,7 +939,7 @@ TEST_F(EventRewriterTest, TestRewriteCapsLock) {
chromeos::Preferences::RegisterProfilePrefs(prefs.registry());
chromeos::input_method::FakeImeKeyboard ime_keyboard;
- EventRewriter rewriter;
+ EventRewriter rewriter(NULL);
rewriter.set_pref_service_for_testing(&prefs);
rewriter.set_ime_keyboard_for_testing(&ime_keyboard);
EXPECT_FALSE(ime_keyboard.caps_lock_is_enabled_);
@@ -954,7 +958,7 @@ TEST_F(EventRewriterTest, TestRewriteDiamondKey) {
chromeos::Preferences::RegisterProfilePrefs(prefs.registry());
chromeos::input_method::FakeImeKeyboard ime_keyboard;
- EventRewriter rewriter;
+ EventRewriter rewriter(NULL);
rewriter.set_pref_service_for_testing(&prefs);
rewriter.set_ime_keyboard_for_testing(&ime_keyboard);
@@ -987,7 +991,7 @@ TEST_F(EventRewriterTest, TestRewriteDiamondKeyWithFlag) {
chromeos::Preferences::RegisterProfilePrefs(prefs.registry());
chromeos::input_method::FakeImeKeyboard ime_keyboard;
- EventRewriter rewriter;
+ EventRewriter rewriter(NULL);
rewriter.set_pref_service_for_testing(&prefs);
rewriter.set_ime_keyboard_for_testing(&ime_keyboard);
@@ -1039,7 +1043,7 @@ TEST_F(EventRewriterTest, TestRewriteCapsLockToControl) {
control.Init(prefs::kLanguageRemapCapsLockKeyTo, &prefs);
control.SetValue(chromeos::input_method::kControlKey);
- EventRewriter rewriter;
+ EventRewriter rewriter(NULL);
rewriter.set_pref_service_for_testing(&prefs);
KeyTestCase tests[] = {
@@ -1075,7 +1079,7 @@ TEST_F(EventRewriterTest, TestRewriteCapsLockMod3InUse) {
control.Init(prefs::kLanguageRemapCapsLockKeyTo, &prefs);
control.SetValue(chromeos::input_method::kControlKey);
- EventRewriter rewriter;
+ EventRewriter rewriter(NULL);
rewriter.set_pref_service_for_testing(&prefs);
input_method_manager_mock_->set_mod3_used(true);
@@ -1092,7 +1096,7 @@ TEST_F(EventRewriterTest, TestRewriteCapsLockMod3InUse) {
TEST_F(EventRewriterTest, TestRewriteExtendedKeys) {
TestingPrefServiceSyncable prefs;
chromeos::Preferences::RegisterProfilePrefs(prefs.registry());
- EventRewriter rewriter;
+ EventRewriter rewriter(NULL);
rewriter.DeviceAddedForTesting(0, "PC Keyboard");
rewriter.set_last_device_id_for_testing(0);
rewriter.set_pref_service_for_testing(&prefs);
@@ -1201,7 +1205,7 @@ TEST_F(EventRewriterTest, TestRewriteExtendedKeys) {
TEST_F(EventRewriterTest, TestRewriteFunctionKeys) {
TestingPrefServiceSyncable prefs;
chromeos::Preferences::RegisterProfilePrefs(prefs.registry());
- EventRewriter rewriter;
+ EventRewriter rewriter(NULL);
rewriter.set_pref_service_for_testing(&prefs);
FunctionKeyTestCase tests[] = {
@@ -1529,7 +1533,7 @@ TEST_F(EventRewriterTest, TestRewriteExtendedKeysWithSearchRemapped) {
search.Init(prefs::kLanguageRemapSearchKeyTo, &prefs);
search.SetValue(chromeos::input_method::kControlKey);
- EventRewriter rewriter;
+ EventRewriter rewriter(NULL);
rewriter.set_pref_service_for_testing(&prefs);
CommandLine::ForCurrentProcess()->AppendSwitchASCII(
@@ -1556,6 +1560,8 @@ TEST_F(EventRewriterTest, TestRewriteExtendedKeysWithSearchRemapped) {
}
TEST_F(EventRewriterTest, TestRewriteKeyEventSentByXSendEvent) {
+#if defined(USE_X11)
+ // TODO(kpschoedel): pending alternative to xevent.xany.send_event
// Remap Control to Alt.
TestingPrefServiceSyncable prefs;
chromeos::Preferences::RegisterProfilePrefs(prefs.registry());
@@ -1563,7 +1569,7 @@ TEST_F(EventRewriterTest, TestRewriteKeyEventSentByXSendEvent) {
control.Init(prefs::kLanguageRemapControlKeyTo, &prefs);
control.SetValue(chromeos::input_method::kAltKey);
- EventRewriter rewriter;
+ EventRewriter rewriter(NULL);
rewriter.set_pref_service_for_testing(&prefs);
// Send left control press.
@@ -1582,6 +1588,7 @@ TEST_F(EventRewriterTest, TestRewriteKeyEventSentByXSendEvent) {
rewriter.RewriteEvent(keyevent, &new_event));
EXPECT_FALSE(new_event);
}
+#endif
}
TEST_F(EventRewriterTest, TestRewriteNonNativeEvent) {
@@ -1592,7 +1599,7 @@ TEST_F(EventRewriterTest, TestRewriteNonNativeEvent) {
control.Init(prefs::kLanguageRemapControlKeyTo, &prefs);
control.SetValue(chromeos::input_method::kAltKey);
- EventRewriter rewriter;
+ EventRewriter rewriter(NULL);
rewriter.set_pref_service_for_testing(&prefs);
const int kTouchId = 2;
@@ -1609,11 +1616,60 @@ TEST_F(EventRewriterTest, TestRewriteNonNativeEvent) {
new_event->flags() & (ui::EF_CONTROL_DOWN | ui::EF_ALT_DOWN));
}
+// Keeps a buffer of handled events.
+class EventBuffer : public ui::test::TestEventProcessor {
+ public:
+ EventBuffer() {}
+ virtual ~EventBuffer() {}
+
+ void PopEvents(ScopedVector<ui::Event>* events) {
+ events->clear();
+ events->swap(events_);
+ }
+
+ private:
+ // ui::EventProcessor overrides:
+ virtual ui::EventDispatchDetails OnEventFromSource(
+ ui::Event* event) OVERRIDE {
+ if (event->IsKeyEvent()) {
+ events_.push_back(new ui::KeyEvent(*static_cast<ui::KeyEvent*>(event)));
+ } else if (event->IsMouseWheelEvent()) {
+ events_.push_back(
+ new ui::MouseWheelEvent(*static_cast<ui::MouseWheelEvent*>(event)));
+ } else if (event->IsMouseEvent()) {
+ events_.push_back(
+ new ui::MouseEvent(*static_cast<ui::MouseEvent*>(event)));
+ }
+ return ui::EventDispatchDetails();
+ }
+
+ ScopedVector<ui::Event> events_;
+
+ DISALLOW_COPY_AND_ASSIGN(EventBuffer);
+};
+
+// Trivial EventSource that does nothing but send events.
+class TestEventSource : public ui::EventSource {
+ public:
+ explicit TestEventSource(ui::EventProcessor* processor)
+ : processor_(processor) {}
+ virtual ui::EventProcessor* GetEventProcessor() OVERRIDE {
+ return processor_;
+ }
+ ui::EventDispatchDetails Send(ui::Event* event) {
+ return SendEventToProcessor(event);
+ }
+
+ private:
+ ui::EventProcessor* processor_;
+};
+
// Tests of event rewriting that depend on the Ash window manager.
class EventRewriterAshTest : public ash::test::AshTestBase {
public:
EventRewriterAshTest()
- : mock_user_manager_(new chromeos::MockUserManager),
+ : source_(&buffer_),
+ mock_user_manager_(new chromeos::MockUserManager),
user_manager_enabler_(mock_user_manager_) {}
virtual ~EventRewriterAshTest() {}
@@ -1622,12 +1678,40 @@ class EventRewriterAshTest : public ash::test::AshTestBase {
return rewriter_->RewriteEvent(event, rewritten_event);
}
+ ui::EventDispatchDetails Send(ui::Event* event) {
+ return source_.Send(event);
+ }
+
+ void SendKeyEvent(ui::EventType type, ui::KeyboardCode key_code) {
+ ui::KeyEvent press(type, key_code, ui::EF_NONE, false);
+ ui::EventDispatchDetails details = Send(&press);
+ CHECK(!details.dispatcher_destroyed);
+ }
+
+ void SendActivateStickyKeyPattern(ui::KeyboardCode key_code) {
+ SendKeyEvent(ui::ET_KEY_PRESSED, key_code);
+ SendKeyEvent(ui::ET_KEY_RELEASED, key_code);
+ }
+
protected:
+ TestingPrefServiceSyncable* prefs() { return &prefs_; }
+
+ void PopEvents(ScopedVector<ui::Event>* events) {
+ buffer_.PopEvents(events);
+ }
+
virtual void SetUp() OVERRIDE {
AshTestBase::SetUp();
- rewriter_.reset(new EventRewriter());
+ sticky_keys_controller_ =
+ ash::Shell::GetInstance()->sticky_keys_controller();
+ rewriter_.reset(new EventRewriter(sticky_keys_controller_));
chromeos::Preferences::RegisterProfilePrefs(prefs_.registry());
rewriter_->set_pref_service_for_testing(&prefs_);
+#if defined(USE_X11)
+ ui::SetUpTouchPadForTest(kTouchPadDeviceId);
+#endif
+ source_.AddEventRewriter(rewriter_.get());
+ sticky_keys_controller_->Enable(true);
}
virtual void TearDown() OVERRIDE {
@@ -1635,13 +1719,18 @@ class EventRewriterAshTest : public ash::test::AshTestBase {
AshTestBase::TearDown();
}
- TestingPrefServiceSyncable prefs_;
+ protected:
+ ash::StickyKeysController* sticky_keys_controller_;
private:
scoped_ptr<EventRewriter> rewriter_;
+ EventBuffer buffer_;
+ TestEventSource source_;
+
chromeos::MockUserManager* mock_user_manager_; // Not owned.
chromeos::ScopedUserManagerEnabler user_manager_enabler_;
+ TestingPrefServiceSyncable prefs_;
DISALLOW_COPY_AND_ASSIGN(EventRewriterAshTest);
};
@@ -1650,6 +1739,7 @@ TEST_F(EventRewriterAshTest, TopRowKeysAreFunctionKeys) {
scoped_ptr<aura::Window> window(CreateTestWindowInShellWithId(1));
ash::wm::WindowState* window_state = ash::wm::GetWindowState(window.get());
window_state->Activate();
+ ScopedVector<ui::Event> events;
// Create a simulated keypress of F1 targetted at the window.
ui::KeyEvent press_f1(ui::ET_KEY_PRESSED, ui::VKEY_F1, 0, false);
@@ -1657,34 +1747,38 @@ TEST_F(EventRewriterAshTest, TopRowKeysAreFunctionKeys) {
// Simulate an apps v2 window that has requested top row keys as function
// keys. The event should not be rewritten.
window_state->set_top_row_keys_are_function_keys(true);
- scoped_ptr<ui::Event> rewritten_event;
- ASSERT_FALSE(RewriteFunctionKeys(press_f1, &rewritten_event));
- ASSERT_FALSE(rewritten_event);
+ ui::EventDispatchDetails details = Send(&press_f1);
+ ASSERT_FALSE(details.dispatcher_destroyed);
+ PopEvents(&events);
+ EXPECT_EQ(1u, events.size());
EXPECT_EQ(
GetExpectedResultAsString(ui::VKEY_F1, ui::EF_NONE, ui::ET_KEY_PRESSED),
- GetKeyEventAsString(press_f1));
+ GetKeyEventAsString(*static_cast<ui::KeyEvent*>(events[0])));
// The event should also not be rewritten if the send-function-keys pref is
// additionally set, for both apps v2 and regular windows.
BooleanPrefMember send_function_keys_pref;
- send_function_keys_pref.Init(prefs::kLanguageSendFunctionKeys, &prefs_);
+ send_function_keys_pref.Init(prefs::kLanguageSendFunctionKeys, prefs());
send_function_keys_pref.SetValue(true);
window_state->set_top_row_keys_are_function_keys(false);
- ASSERT_FALSE(RewriteFunctionKeys(press_f1, &rewritten_event));
- ASSERT_FALSE(rewritten_event);
+ details = Send(&press_f1);
+ ASSERT_FALSE(details.dispatcher_destroyed);
+ PopEvents(&events);
+ EXPECT_EQ(1u, events.size());
EXPECT_EQ(
GetExpectedResultAsString(ui::VKEY_F1, ui::EF_NONE, ui::ET_KEY_PRESSED),
- GetKeyEventAsString(press_f1));
+ GetKeyEventAsString(*static_cast<ui::KeyEvent*>(events[0])));
// If the pref isn't set when an event is sent to a regular window, F1 is
// rewritten to the back key.
send_function_keys_pref.SetValue(false);
- ASSERT_TRUE(RewriteFunctionKeys(press_f1, &rewritten_event));
- ASSERT_TRUE(rewritten_event);
+ details = Send(&press_f1);
+ ASSERT_FALSE(details.dispatcher_destroyed);
+ PopEvents(&events);
+ EXPECT_EQ(1u, events.size());
EXPECT_EQ(GetExpectedResultAsString(
ui::VKEY_BROWSER_BACK, ui::EF_NONE, ui::ET_KEY_PRESSED),
- GetKeyEventAsString(
- *static_cast<const ui::KeyEvent*>(rewritten_event.get())));
+ GetKeyEventAsString(*static_cast<ui::KeyEvent*>(events[0])));
}
TEST_F(EventRewriterTest, TestRewrittenModifierClick) {
@@ -1699,7 +1793,7 @@ TEST_F(EventRewriterTest, TestRewrittenModifierClick) {
control.Init(prefs::kLanguageRemapControlKeyTo, &prefs);
control.SetValue(chromeos::input_method::kAltKey);
- EventRewriter rewriter;
+ EventRewriter rewriter(NULL);
rewriter.set_pref_service_for_testing(&prefs);
// Check that Control + Left Button is converted (via Alt + Left Button)
@@ -1721,12 +1815,15 @@ TEST_F(EventRewriterTest, TestRewrittenModifierClick) {
TEST_F(EventRewriterTest, DontRewriteIfNotRewritten) {
+#if defined(USE_X11)
+ // TODO(kpschoedel): pending changes for crbug.com/360377
+ // to |chromeos::EventRewriter::RewriteLocatedEvent()
std::vector<unsigned int> device_list;
device_list.push_back(10);
device_list.push_back(11);
ui::TouchFactory::GetInstance()->SetPointerDeviceForTest(device_list);
TestingPrefServiceSyncable prefs;
- EventRewriter rewriter;
+ EventRewriter rewriter(NULL);
rewriter.set_pref_service_for_testing(&prefs);
const int kLeftAndAltFlag = ui::EF_LEFT_MOUSE_BUTTON | ui::EF_ALT_DOWN;
{
@@ -1792,6 +1889,299 @@ TEST_F(EventRewriterTest, DontRewriteIfNotRewritten) {
int flags = RewriteMouseEvent(&rewriter, release);
EXPECT_TRUE(ui::EF_RIGHT_MOUSE_BUTTON & flags);
}
+#endif
+}
+
+TEST_F(EventRewriterAshTest, StickyKeyEventDispatchImpl) {
+ // Test the actual key event dispatch implementation.
+ ScopedVector<ui::Event> events;
+
+ SendActivateStickyKeyPattern(ui::VKEY_CONTROL);
+ PopEvents(&events);
+ EXPECT_EQ(1u, events.size());
+ EXPECT_EQ(ui::ET_KEY_PRESSED, events[0]->type());
+ EXPECT_EQ(ui::VKEY_CONTROL,
+ static_cast<ui::KeyEvent*>(events[0])->key_code());
+
+ // Test key press event is correctly modified and modifier release
+ // event is sent.
+ ui::KeyEvent press(ui::ET_KEY_PRESSED, ui::VKEY_C, ui::EF_NONE, false);
+ ui::EventDispatchDetails details = Send(&press);
+ 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.
+ ui::KeyEvent release(ui::ET_KEY_RELEASED, ui::VKEY_C, ui::EF_NONE, false);
+ details = Send(&release);
+ ASSERT_FALSE(details.dispatcher_destroyed);
+ 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_F(EventRewriterAshTest, MouseEventDispatchImpl) {
+ ScopedVector<ui::Event> events;
+
+ SendActivateStickyKeyPattern(ui::VKEY_CONTROL);
+ PopEvents(&events);
+
+ // Test mouse press event is correctly modified.
+ gfx::Point location(0, 0);
+ ui::MouseEvent press(ui::ET_MOUSE_PRESSED,
+ location,
+ location,
+ ui::EF_LEFT_MOUSE_BUTTON,
+ ui::EF_LEFT_MOUSE_BUTTON);
+ ui::EventDispatchDetails details = Send(&press);
+ ASSERT_FALSE(details.dispatcher_destroyed);
+ 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);
+
+ // Test mouse release event is correctly modified and modifier release
+ // event is sent. The mouse event should have the correct DIP location.
+ ui::MouseEvent release(ui::ET_MOUSE_RELEASED,
+ location,
+ location,
+ ui::EF_LEFT_MOUSE_BUTTON,
+ ui::EF_LEFT_MOUSE_BUTTON);
+ details = Send(&release);
+ ASSERT_FALSE(details.dispatcher_destroyed);
+ 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(ui::VKEY_CONTROL,
+ static_cast<ui::KeyEvent*>(events[1])->key_code());
+}
+
+TEST_F(EventRewriterAshTest, MouseWheelEventDispatchImpl) {
+ ScopedVector<ui::Event> events;
+
+ // Test positive mouse wheel event is correctly modified and modifier release
+ // event is sent.
+ SendActivateStickyKeyPattern(ui::VKEY_CONTROL);
+ PopEvents(&events);
+ gfx::Point location(0, 0);
+ ui::MouseEvent mev(ui::ET_MOUSEWHEEL,
+ location,
+ location,
+ ui::EF_LEFT_MOUSE_BUTTON,
+ ui::EF_LEFT_MOUSE_BUTTON);
+ ui::MouseWheelEvent positive(mev, 0, ui::MouseWheelEvent::kWheelDelta);
+ ui::EventDispatchDetails details = Send(&positive);
+ ASSERT_FALSE(details.dispatcher_destroyed);
+ PopEvents(&events);
+ EXPECT_EQ(2u, events.size());
+ EXPECT_TRUE(events[0]->IsMouseWheelEvent());
+ 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(ui::VKEY_CONTROL);
+ PopEvents(&events);
+ ui::MouseWheelEvent negative(mev, 0, -ui::MouseWheelEvent::kWheelDelta);
+ details = Send(&negative);
+ ASSERT_FALSE(details.dispatcher_destroyed);
+ PopEvents(&events);
+ EXPECT_EQ(2u, events.size());
+ EXPECT_TRUE(events[0]->IsMouseWheelEvent());
+ 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());
+}
+
+class StickyKeysOverlayTest : public EventRewriterAshTest {
+ public:
+ StickyKeysOverlayTest() : overlay_(NULL) {}
+
+ virtual ~StickyKeysOverlayTest() {}
+
+ virtual void SetUp() OVERRIDE {
+ EventRewriterAshTest::SetUp();
+ overlay_ = sticky_keys_controller_->GetOverlayForTest();
+ ASSERT_TRUE(overlay_);
+ }
+
+ ash::StickyKeysOverlay* overlay_;
+};
+
+TEST_F(StickyKeysOverlayTest, OneModifierEnabled) {
+ EXPECT_FALSE(overlay_->is_visible());
+ EXPECT_EQ(ash::STICKY_KEY_STATE_DISABLED,
+ overlay_->GetModifierKeyState(ui::EF_CONTROL_DOWN));
+
+ // Pressing modifier key should show overlay.
+ SendActivateStickyKeyPattern(ui::VKEY_CONTROL);
+ EXPECT_TRUE(overlay_->is_visible());
+ EXPECT_EQ(ash::STICKY_KEY_STATE_ENABLED,
+ overlay_->GetModifierKeyState(ui::EF_CONTROL_DOWN));
+
+ // Pressing a normal key should hide overlay.
+ SendActivateStickyKeyPattern(ui::VKEY_T);
+ EXPECT_FALSE(overlay_->is_visible());
+ EXPECT_EQ(ash::STICKY_KEY_STATE_DISABLED,
+ overlay_->GetModifierKeyState(ui::EF_CONTROL_DOWN));
+}
+
+TEST_F(StickyKeysOverlayTest, TwoModifiersEnabled) {
+ EXPECT_FALSE(overlay_->is_visible());
+ EXPECT_EQ(ash::STICKY_KEY_STATE_DISABLED,
+ overlay_->GetModifierKeyState(ui::EF_CONTROL_DOWN));
+ EXPECT_EQ(ash::STICKY_KEY_STATE_DISABLED,
+ overlay_->GetModifierKeyState(ui::EF_SHIFT_DOWN));
+
+ // Pressing two modifiers should show overlay.
+ SendActivateStickyKeyPattern(ui::VKEY_SHIFT);
+ SendActivateStickyKeyPattern(ui::VKEY_CONTROL);
+ EXPECT_TRUE(overlay_->is_visible());
+ EXPECT_EQ(ash::STICKY_KEY_STATE_ENABLED,
+ overlay_->GetModifierKeyState(ui::EF_SHIFT_DOWN));
+ EXPECT_EQ(ash::STICKY_KEY_STATE_ENABLED,
+ overlay_->GetModifierKeyState(ui::EF_CONTROL_DOWN));
+
+ // Pressing a normal key should hide overlay.
+ SendActivateStickyKeyPattern(ui::VKEY_N);
+ EXPECT_FALSE(overlay_->is_visible());
+ EXPECT_EQ(ash::STICKY_KEY_STATE_DISABLED,
+ overlay_->GetModifierKeyState(ui::EF_CONTROL_DOWN));
+ EXPECT_EQ(ash::STICKY_KEY_STATE_DISABLED,
+ overlay_->GetModifierKeyState(ui::EF_SHIFT_DOWN));
+}
+
+TEST_F(StickyKeysOverlayTest, LockedModifier) {
+ EXPECT_FALSE(overlay_->is_visible());
+ EXPECT_EQ(ash::STICKY_KEY_STATE_DISABLED,
+ overlay_->GetModifierKeyState(ui::EF_ALT_DOWN));
+
+ // Pressing a modifier key twice should lock modifier and show overlay.
+ SendActivateStickyKeyPattern(ui::VKEY_LMENU);
+ SendActivateStickyKeyPattern(ui::VKEY_LMENU);
+ EXPECT_TRUE(overlay_->is_visible());
+ EXPECT_EQ(ash::STICKY_KEY_STATE_LOCKED,
+ overlay_->GetModifierKeyState(ui::EF_ALT_DOWN));
+
+ // Pressing a normal key should not hide overlay.
+ SendActivateStickyKeyPattern(ui::VKEY_D);
+ EXPECT_TRUE(overlay_->is_visible());
+ EXPECT_EQ(ash::STICKY_KEY_STATE_LOCKED,
+ overlay_->GetModifierKeyState(ui::EF_ALT_DOWN));
+}
+
+TEST_F(StickyKeysOverlayTest, LockedAndNormalModifier) {
+ EXPECT_FALSE(overlay_->is_visible());
+ EXPECT_EQ(ash::STICKY_KEY_STATE_DISABLED,
+ overlay_->GetModifierKeyState(ui::EF_CONTROL_DOWN));
+ EXPECT_EQ(ash::STICKY_KEY_STATE_DISABLED,
+ overlay_->GetModifierKeyState(ui::EF_SHIFT_DOWN));
+
+ // Pressing a modifier key twice should lock modifier and show overlay.
+ SendActivateStickyKeyPattern(ui::VKEY_CONTROL);
+ SendActivateStickyKeyPattern(ui::VKEY_CONTROL);
+ EXPECT_TRUE(overlay_->is_visible());
+ EXPECT_EQ(ash::STICKY_KEY_STATE_LOCKED,
+ overlay_->GetModifierKeyState(ui::EF_CONTROL_DOWN));
+
+ // Pressing another modifier key should still show overlay.
+ SendActivateStickyKeyPattern(ui::VKEY_SHIFT);
+ EXPECT_TRUE(overlay_->is_visible());
+ EXPECT_EQ(ash::STICKY_KEY_STATE_LOCKED,
+ overlay_->GetModifierKeyState(ui::EF_CONTROL_DOWN));
+ EXPECT_EQ(ash::STICKY_KEY_STATE_ENABLED,
+ overlay_->GetModifierKeyState(ui::EF_SHIFT_DOWN));
+
+ // Pressing a normal key should not hide overlay but disable normal modifier.
+ SendActivateStickyKeyPattern(ui::VKEY_D);
+ EXPECT_TRUE(overlay_->is_visible());
+ EXPECT_EQ(ash::STICKY_KEY_STATE_LOCKED,
+ overlay_->GetModifierKeyState(ui::EF_CONTROL_DOWN));
+ EXPECT_EQ(ash::STICKY_KEY_STATE_DISABLED,
+ overlay_->GetModifierKeyState(ui::EF_SHIFT_DOWN));
+}
+
+TEST_F(StickyKeysOverlayTest, ModifiersDisabled) {
+ EXPECT_FALSE(overlay_->is_visible());
+ EXPECT_EQ(ash::STICKY_KEY_STATE_DISABLED,
+ overlay_->GetModifierKeyState(ui::EF_CONTROL_DOWN));
+ EXPECT_EQ(ash::STICKY_KEY_STATE_DISABLED,
+ overlay_->GetModifierKeyState(ui::EF_SHIFT_DOWN));
+ EXPECT_EQ(ash::STICKY_KEY_STATE_DISABLED,
+ overlay_->GetModifierKeyState(ui::EF_ALT_DOWN));
+
+ // Enable modifiers.
+ SendActivateStickyKeyPattern(ui::VKEY_CONTROL);
+ SendActivateStickyKeyPattern(ui::VKEY_SHIFT);
+ SendActivateStickyKeyPattern(ui::VKEY_SHIFT);
+ SendActivateStickyKeyPattern(ui::VKEY_LMENU);
+
+ EXPECT_TRUE(overlay_->is_visible());
+ EXPECT_EQ(ash::STICKY_KEY_STATE_ENABLED,
+ overlay_->GetModifierKeyState(ui::EF_CONTROL_DOWN));
+ EXPECT_EQ(ash::STICKY_KEY_STATE_LOCKED,
+ overlay_->GetModifierKeyState(ui::EF_SHIFT_DOWN));
+ EXPECT_EQ(ash::STICKY_KEY_STATE_ENABLED,
+ overlay_->GetModifierKeyState(ui::EF_ALT_DOWN));
+
+ // Disable modifiers and overlay should be hidden.
+ SendActivateStickyKeyPattern(ui::VKEY_CONTROL);
+ SendActivateStickyKeyPattern(ui::VKEY_CONTROL);
+ SendActivateStickyKeyPattern(ui::VKEY_SHIFT);
+ SendActivateStickyKeyPattern(ui::VKEY_LMENU);
+ SendActivateStickyKeyPattern(ui::VKEY_LMENU);
+
+ EXPECT_FALSE(overlay_->is_visible());
+ EXPECT_EQ(ash::STICKY_KEY_STATE_DISABLED,
+ overlay_->GetModifierKeyState(ui::EF_CONTROL_DOWN));
+ EXPECT_EQ(ash::STICKY_KEY_STATE_DISABLED,
+ overlay_->GetModifierKeyState(ui::EF_SHIFT_DOWN));
+ EXPECT_EQ(ash::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.
+ sticky_keys_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.
+ sticky_keys_controller_->SetModifiersEnabled(false, true);
+ EXPECT_TRUE(overlay_->GetModifierVisible(ui::EF_ALTGR_DOWN));
+ EXPECT_FALSE(overlay_->GetModifierVisible(ui::EF_MOD3_DOWN));
+
+ // Turn off AltGr.
+ sticky_keys_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.
+ sticky_keys_controller_->SetModifiersEnabled(false, false);
+ EXPECT_FALSE(overlay_->GetModifierVisible(ui::EF_ALTGR_DOWN));
+ EXPECT_FALSE(overlay_->GetModifierVisible(ui::EF_MOD3_DOWN));
}
} // namespace chromeos