Index: chrome/browser/ui/ash/event_rewriter.cc |
diff --git a/chrome/browser/ui/ash/event_rewriter.cc b/chrome/browser/ui/ash/event_rewriter.cc |
index 5912b1ee76bb4ab13ed4e5db0d88af7d467ff803..8087d1f7fb1b798ac8fb1c20ad365cbe7c955475 100644 |
--- a/chrome/browser/ui/ash/event_rewriter.cc |
+++ b/chrome/browser/ui/ash/event_rewriter.cc |
@@ -1,3 +1,4 @@ |
+ |
// Copyright (c) 2012 The Chromium Authors. All rights reserved. |
// Use of this source code is governed by a BSD-style license that can be |
// found in the LICENSE file. |
@@ -25,6 +26,7 @@ |
// Get rid of a macro from Xlib.h that conflicts with OwnershipService class. |
#undef Status |
+#include "ash/magnifier/magnification_controller.h" |
#include "ash/wm/window_state.h" |
#include "base/command_line.h" |
#include "base/sys_info.h" |
@@ -140,12 +142,142 @@ bool IsMod3UsedByCurrentInputMethod() { |
} // namespace |
+#if defined(OS_CHROMEOS) |
+ |
+// This class converts the arrow+shift keys to NUMPAD keys to activate |
+// magnifier accelerators. This also suppress the first arrow key press |
+// event and sends the arrow key press even upon release. This is to |
+// prevent sending an arrow key event for click-and-hold operation. |
+class EventRewriter::AccessibilityEventRewriter { |
+ public: |
+ explicit AccessibilityEventRewriter(EventRewriter* rewriter) |
+ : state_(INITIAL), |
+ event_rewriter_(rewriter) {} |
+ ~AccessibilityEventRewriter() {} |
+ |
+ bool RewriteAccessibilityKeys( |
+ ui::KeyEvent* event, |
+ ash::EventRewriterDelegate::Action* action) { |
+ if (!ash::MagnificationController::IsMagnifierAcceleratorsEnabled() || |
+ !ash::Shell::GetInstance()->magnification_controller()->IsEnabled()) { |
+ return false; |
+ } |
+ |
+ if (event->key_code() != ui::VKEY_UP && |
+ event->key_code() != ui::VKEY_DOWN && |
+ event->key_code() != ui::VKEY_LEFT && |
+ event->key_code() != ui::VKEY_RIGHT) { |
+ return false; |
+ } |
+ |
+ if (event->type() == ui::ET_KEY_PRESSED && |
+ event->flags() & ui::EF_SHIFT_DOWN) { |
+ switch (state_) { |
+ case INITIAL: |
+ state_ = PRESSED; |
+ // Don't send ET_KEY_PRESSED event yet. The ET_KEY_PRESSED |
+ // event will be sent upon ET_KEY_RELEASEED event below. |
+ *action = EventRewriterDelegate::ACTION_DROP_EVENT; |
+ break; |
+ case PRESSED: |
+ state_ = HOLD; |
+ // pass through |
+ case HOLD: |
+ ConvertArrowToScrollAccelerator(event); |
+ *action = ash::EventRewriterDelegate::ACTION_REWRITE_EVENT; |
+ break; |
+ } |
+ } else if (event->type() == ui::ET_KEY_RELEASED) { |
+ switch (state_) { |
+ case INITIAL: |
+ break; |
+ case PRESSED: { |
+ // Modify RELEASED event to PRESSED event. |
+ XKeyEvent* xkey = &(event->native_event()->xkey); |
+ xkey->type = KeyPress; |
+ xkey->state |= ShiftMask; |
+ event->set_type(ui::ET_KEY_PRESSED); |
+ event->set_flags(event->flags() | ui::EF_SHIFT_DOWN); |
+ event->NormalizeFlags(); |
+ *action = ash::EventRewriterDelegate::ACTION_REWRITE_EVENT; |
+ break; |
+ } |
+ case HOLD: |
+ ConvertArrowToScrollAccelerator(event); |
+ *action = ash::EventRewriterDelegate::ACTION_REWRITE_EVENT; |
+ break; |
+ } |
+ state_ = INITIAL; |
+ } |
+ return true; |
+ } |
+ |
+ private: |
+ // A state to keep track of one click and click and hold operation. |
+ // |
+ // One click: |
+ // INITIAL --(first press)--> PRESSED --(release)--> INITIAL[SEND PRESS] |
+ // |
+ // Click and hold: |
+ // INITIAL --(first press)--> PRESSED --(press)--> |
+ // HOLD[send accelerator keys] --(press)--> |
+ // HOLD[send accelerator keys] --(release)--> |
+ // INITIAL[send accelerator keys] |
+ enum State { |
+ INITIAL, |
+ PRESSED, |
+ HOLD |
+ }; |
+ |
+ void ConvertArrowToScrollAccelerator(ui::KeyEvent* event) { |
+ ui::KeyboardCode original_keyboard_code = event->key_code(); |
+ ui::KeyboardCode new_keyboard_code; |
+ switch (original_keyboard_code) { |
+ case ui::VKEY_UP: |
+ new_keyboard_code = ui::VKEY_NUMPAD6; |
+ break; |
+ case ui::VKEY_DOWN: |
+ new_keyboard_code = ui::VKEY_NUMPAD7; |
+ break; |
+ case ui::VKEY_LEFT: |
+ new_keyboard_code = ui::VKEY_NUMPAD8; |
+ break; |
+ case ui::VKEY_RIGHT: |
+ new_keyboard_code = ui::VKEY_NUMPAD9; |
+ break; |
+ default: |
+ NOTREACHED() << "Unknown keyboard_code:" << original_keyboard_code; |
+ return; |
+ } |
+ |
+ KeySym new_key_sym = ui::XKeysymForWindowsKeyCode(new_keyboard_code, false); |
+ unsigned int new_native_keycode = |
+ event_rewriter_->NativeKeySymToNativeKeycode(new_key_sym); |
+ |
+ XKeyEvent* xkey = &(event->native_event()->xkey); |
+ OverwriteEvent(event, |
+ new_native_keycode, |
+ xkey->state, |
+ new_keyboard_code, |
+ event->flags()); |
+ } |
+ |
+ State state_; |
+ EventRewriter* event_rewriter_; |
+ |
+ DISALLOW_COPY_AND_ASSIGN(AccessibilityEventRewriter); |
+}; |
+ |
+#endif // OS_CHROMEOS |
+ |
EventRewriter::EventRewriter() |
: last_device_id_(kBadDeviceId), |
#if defined(OS_CHROMEOS) |
xkeyboard_for_testing_(NULL), |
keyboard_driven_event_rewriter_( |
new chromeos::KeyboardDrivenEventRewriter), |
+ accessibility_event_rewriter_( |
+ new AccessibilityEventRewriter(this)), |
#endif |
pref_service_for_testing_(NULL) { |
// The ash shell isn't instantiated for our unit tests. |
@@ -210,7 +342,7 @@ void EventRewriter::RewriteForTesting(ui::KeyEvent* event) { |
ash::EventRewriterDelegate::Action EventRewriter::RewriteOrFilterKeyEvent( |
ui::KeyEvent* event) { |
if (event->HasNativeEvent()) |
- Rewrite(event); |
+ return Rewrite(event); |
return ash::EventRewriterDelegate::ACTION_REWRITE_EVENT; |
} |
@@ -372,24 +504,30 @@ const PrefService* EventRewriter::GetPrefService() const { |
return profile ? profile->GetPrefs() : NULL; |
} |
-void EventRewriter::Rewrite(ui::KeyEvent* event) { |
+ash::EventRewriterDelegate::Action EventRewriter::Rewrite(ui::KeyEvent* event) { |
+ ash::EventRewriterDelegate::Action action = |
+ EventRewriterDelegate::ACTION_REWRITE_EVENT; |
#if defined(OS_CHROMEOS) |
// Do not rewrite an event sent by ui_controls::SendKeyPress(). See |
// crbug.com/136465. |
if (event->native_event()->xkey.send_event) |
- return; |
+ return action; |
// Keyboard driven rewriting happen first. Skip further processing if event is |
// changed. |
if (keyboard_driven_event_rewriter_->RewriteIfKeyboardDrivenOnLoginScreen( |
event)) { |
- return; |
+ return action; |
} |
+ |
+ if (RewriteAccessibilityKeys(event, &action)) |
+ return action; |
#endif |
RewriteModifiers(event); |
RewriteNumPadKeys(event); |
RewriteExtendedKeys(event); |
RewriteFunctionKeys(event); |
+ return action; |
} |
bool EventRewriter::IsAppleKeyboard() const { |
@@ -1029,6 +1167,27 @@ void EventRewriter::RewriteLocatedEvent(ui::LocatedEvent* event) { |
#endif |
} |
+bool EventRewriter::RewriteAccessibilityKeys( |
+ ui::KeyEvent* event, |
+ ash::EventRewriterDelegate::Action* action) { |
+ return accessibility_event_rewriter_->RewriteAccessibilityKeys(event, action); |
+} |
+ |
+EventRewriter::DeviceType EventRewriter::DeviceAddedInternal( |
+ int device_id, |
+ const std::string& device_name) { |
+ const DeviceType type = EventRewriter::GetDeviceType(device_name); |
+ if (type == kDeviceAppleKeyboard) { |
+ VLOG(1) << "Apple keyboard '" << device_name << "' connected: " |
+ << "id=" << device_id; |
+ } |
+ // Always overwrite the existing device_id since the X server may reuse a |
+ // device id for an unattached device. |
+ device_id_to_type_[device_id] = type; |
+ return type; |
+} |
+ |
+// static |
void EventRewriter::OverwriteEvent(ui::KeyEvent* event, |
unsigned int new_native_keycode, |
unsigned int new_native_state, |
@@ -1048,17 +1207,3 @@ void EventRewriter::OverwriteEvent(ui::KeyEvent* event, |
// TODO(yusukes): Support Ash on other platforms if needed. |
#endif |
} |
- |
-EventRewriter::DeviceType EventRewriter::DeviceAddedInternal( |
- int device_id, |
- const std::string& device_name) { |
- const DeviceType type = EventRewriter::GetDeviceType(device_name); |
- if (type == kDeviceAppleKeyboard) { |
- VLOG(1) << "Apple keyboard '" << device_name << "' connected: " |
- << "id=" << device_id; |
- } |
- // Always overwrite the existing device_id since the X server may reuse a |
- // device id for an unattached device. |
- device_id_to_type_[device_id] = type; |
- return type; |
-} |