| 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;
|
| -}
|
|
|