Home | History | Annotate | Download | only in events
      1 // Copyright 2014 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "chrome/browser/chromeos/events/event_rewriter.h"
      6 
      7 #include <vector>
      8 
      9 #include "ash/wm/window_state.h"
     10 #include "ash/wm/window_util.h"
     11 #include "base/command_line.h"
     12 #include "base/logging.h"
     13 #include "base/prefs/pref_service.h"
     14 #include "base/strings/string_util.h"
     15 #include "base/sys_info.h"
     16 #include "chrome/browser/chromeos/login/ui/login_display_host_impl.h"
     17 #include "chrome/browser/chromeos/login/users/user_manager.h"
     18 #include "chrome/browser/profiles/profile_manager.h"
     19 #include "chrome/common/pref_names.h"
     20 #include "chromeos/chromeos_switches.h"
     21 #include "chromeos/ime/ime_keyboard.h"
     22 #include "chromeos/ime/input_method_manager.h"
     23 #include "ui/events/event.h"
     24 #include "ui/events/event_utils.h"
     25 #include "ui/events/keycodes/keyboard_code_conversion.h"
     26 #include "ui/events/platform/platform_event_source.h"
     27 #include "ui/wm/core/window_util.h"
     28 
     29 #if defined(USE_X11)
     30 #include <X11/extensions/XInput2.h>
     31 #include <X11/Xlib.h>
     32 // Get rid of macros from Xlib.h that conflicts with other parts of the code.
     33 #undef RootWindow
     34 #undef Status
     35 
     36 #include "chrome/browser/chromeos/events/xinput_hierarchy_changed_event_listener.h"
     37 #include "ui/base/x/x11_util.h"
     38 #include "ui/events/keycodes/keyboard_code_conversion_x.h"
     39 #endif
     40 
     41 namespace chromeos {
     42 
     43 namespace {
     44 
     45 const int kBadDeviceId = -1;
     46 
     47 // Table of key properties of remappable keys and/or remapping targets.
     48 // This is searched in two distinct ways:
     49 //  - |remap_to| is an |input_method::ModifierKey|, which is the form
     50 //    held in user preferences. |GetRemappedKey()| maps this to the
     51 //    corresponding |key_code| and characterstic event |flag|.
     52 //  - |flag| is a |ui::EventFlags|. |GetRemappedModifierMasks()| maps this
     53 //    to the corresponding user preference |pref_name| for that flag's
     54 //    key, so that it can then be remapped as above.
     55 // In addition |kModifierRemappingCtrl| is a direct reference to the
     56 // Control key entry in the table, used in handling Chromebook Diamond
     57 // and Apple Command keys.
     58 const struct ModifierRemapping {
     59   int remap_to;
     60   int flag;
     61   ui::KeyboardCode key_code;
     62   const char* pref_name;
     63 } kModifierRemappings[] = {
     64       {input_method::kSearchKey, ui::EF_COMMAND_DOWN, ui::VKEY_LWIN,
     65        prefs::kLanguageRemapSearchKeyTo},
     66       {input_method::kControlKey, ui::EF_CONTROL_DOWN, ui::VKEY_CONTROL,
     67        prefs::kLanguageRemapControlKeyTo},
     68       {input_method::kAltKey, ui::EF_ALT_DOWN, ui::VKEY_MENU,
     69        prefs::kLanguageRemapAltKeyTo},
     70       {input_method::kVoidKey, 0, ui::VKEY_UNKNOWN, NULL},
     71       {input_method::kCapsLockKey, ui::EF_MOD3_DOWN, ui::VKEY_CAPITAL,
     72        prefs::kLanguageRemapCapsLockKeyTo},
     73       {input_method::kEscapeKey, 0, ui::VKEY_ESCAPE, NULL},
     74       {0, 0, ui::VKEY_F15, prefs::kLanguageRemapDiamondKeyTo},
     75 };
     76 
     77 const ModifierRemapping* kModifierRemappingCtrl = &kModifierRemappings[1];
     78 
     79 // Gets a remapped key for |pref_name| key. For example, to find out which
     80 // key Search is currently remapped to, call the function with
     81 // prefs::kLanguageRemapSearchKeyTo.
     82 const ModifierRemapping* GetRemappedKey(const std::string& pref_name,
     83                                         const PrefService& pref_service) {
     84   if (!pref_service.FindPreference(pref_name.c_str()))
     85     return NULL;  // The |pref_name| hasn't been registered. On login screen?
     86   const int value = pref_service.GetInteger(pref_name.c_str());
     87   for (size_t i = 0; i < arraysize(kModifierRemappings); ++i) {
     88     if (value == kModifierRemappings[i].remap_to)
     89       return &kModifierRemappings[i];
     90   }
     91   return NULL;
     92 }
     93 
     94 bool HasDiamondKey() {
     95   return CommandLine::ForCurrentProcess()->HasSwitch(
     96       chromeos::switches::kHasChromeOSDiamondKey);
     97 }
     98 
     99 bool IsISOLevel5ShiftUsedByCurrentInputMethod() {
    100   // Since both German Neo2 XKB layout and Caps Lock depend on Mod3Mask,
    101   // it's not possible to make both features work. For now, we don't remap
    102   // Mod3Mask when Neo2 is in use.
    103   // TODO(yusukes): Remove the restriction.
    104   input_method::InputMethodManager* manager =
    105       input_method::InputMethodManager::Get();
    106   return manager->IsISOLevel5ShiftUsedByCurrentInputMethod();
    107 }
    108 
    109 EventRewriter::DeviceType GetDeviceType(const std::string& device_name) {
    110   std::vector<std::string> tokens;
    111   Tokenize(device_name, " .", &tokens);
    112 
    113   // If the |device_name| contains the two words, "apple" and "keyboard", treat
    114   // it as an Apple keyboard.
    115   bool found_apple = false;
    116   bool found_keyboard = false;
    117   for (size_t i = 0; i < tokens.size(); ++i) {
    118     if (!found_apple && LowerCaseEqualsASCII(tokens[i], "apple"))
    119       found_apple = true;
    120     if (!found_keyboard && LowerCaseEqualsASCII(tokens[i], "keyboard"))
    121       found_keyboard = true;
    122     if (found_apple && found_keyboard)
    123       return EventRewriter::kDeviceAppleKeyboard;
    124   }
    125 
    126   return EventRewriter::kDeviceUnknown;
    127 }
    128 
    129 #if defined(USE_X11)
    130 void UpdateX11EventMask(int ui_flags, unsigned int* x_flags) {
    131   static struct {
    132     int ui;
    133     int x;
    134   } flags[] = {
    135     {ui::EF_CONTROL_DOWN, ControlMask},
    136     {ui::EF_SHIFT_DOWN, ShiftMask},
    137     {ui::EF_ALT_DOWN, Mod1Mask},
    138     {ui::EF_CAPS_LOCK_DOWN, LockMask},
    139     {ui::EF_ALTGR_DOWN, Mod5Mask},
    140     {ui::EF_COMMAND_DOWN, Mod4Mask},
    141     {ui::EF_MOD3_DOWN, Mod3Mask},
    142     {ui::EF_NUMPAD_KEY, Mod2Mask},
    143     {ui::EF_LEFT_MOUSE_BUTTON, Button1Mask},
    144     {ui::EF_MIDDLE_MOUSE_BUTTON, Button2Mask},
    145     {ui::EF_RIGHT_MOUSE_BUTTON, Button3Mask},
    146   };
    147   for (size_t i = 0; i < ARRAYSIZE_UNSAFE(flags); ++i) {
    148     if (ui_flags & flags[i].ui)
    149       *x_flags |= flags[i].x;
    150     else
    151       *x_flags &= ~flags[i].x;
    152   }
    153 }
    154 #endif
    155 
    156 }  // namespace
    157 
    158 EventRewriter::EventRewriter()
    159     : last_device_id_(kBadDeviceId),
    160       ime_keyboard_for_testing_(NULL),
    161       pref_service_for_testing_(NULL) {
    162 #if defined(USE_X11)
    163   ui::PlatformEventSource::GetInstance()->AddPlatformEventObserver(this);
    164   if (base::SysInfo::IsRunningOnChromeOS()) {
    165     XInputHierarchyChangedEventListener::GetInstance()->AddObserver(this);
    166   }
    167 #endif
    168 }
    169 
    170 EventRewriter::~EventRewriter() {
    171 #if defined(USE_X11)
    172   ui::PlatformEventSource::GetInstance()->RemovePlatformEventObserver(this);
    173   if (base::SysInfo::IsRunningOnChromeOS()) {
    174     XInputHierarchyChangedEventListener::GetInstance()->RemoveObserver(this);
    175   }
    176 #endif
    177 }
    178 
    179 EventRewriter::DeviceType EventRewriter::DeviceAddedForTesting(
    180     int device_id,
    181     const std::string& device_name) {
    182   return DeviceAddedInternal(device_id, device_name);
    183 }
    184 
    185 void EventRewriter::RewriteLocatedEventForTesting(const ui::Event& event,
    186                                                   int* flags) {
    187   RewriteLocatedEvent(event, flags);
    188 }
    189 
    190 ui::EventRewriteStatus EventRewriter::RewriteEvent(
    191     const ui::Event& event,
    192     scoped_ptr<ui::Event>* rewritten_event) {
    193 #if defined(USE_X11)
    194   // Do not rewrite an event sent by ui_controls::SendKeyPress(). See
    195   // crbug.com/136465.
    196   XEvent* xev = event.native_event();
    197   if (xev && xev->xany.send_event)
    198     return ui::EVENT_REWRITE_CONTINUE;
    199 #endif
    200   switch (event.type()) {
    201     case ui::ET_KEY_PRESSED:
    202     case ui::ET_KEY_RELEASED:
    203       return RewriteKeyEvent(static_cast<const ui::KeyEvent&>(event),
    204                              rewritten_event);
    205     case ui::ET_MOUSE_PRESSED:
    206     case ui::ET_MOUSE_RELEASED:
    207       return RewriteMouseEvent(static_cast<const ui::MouseEvent&>(event),
    208                                rewritten_event);
    209     case ui::ET_TOUCH_PRESSED:
    210     case ui::ET_TOUCH_RELEASED:
    211       return RewriteTouchEvent(static_cast<const ui::TouchEvent&>(event),
    212                                rewritten_event);
    213     default:
    214       return ui::EVENT_REWRITE_CONTINUE;
    215   }
    216   NOTREACHED();
    217 }
    218 
    219 ui::EventRewriteStatus EventRewriter::NextDispatchEvent(
    220     const ui::Event& last_event,
    221     scoped_ptr<ui::Event>* new_event) {
    222   NOTREACHED();
    223   return ui::EVENT_REWRITE_CONTINUE;
    224 }
    225 
    226 #if defined(USE_X11)
    227 void EventRewriter::DeviceKeyPressedOrReleased(int device_id) {
    228   if (!device_id_to_type_.count(device_id)) {
    229     // |device_id| is unknown. This means the device was connected before
    230     // booting the OS. Query the name of the device and add it to the map.
    231     DeviceAdded(device_id);
    232   }
    233   last_device_id_ = device_id;
    234 }
    235 #endif
    236 
    237 const PrefService* EventRewriter::GetPrefService() const {
    238   if (pref_service_for_testing_)
    239     return pref_service_for_testing_;
    240   Profile* profile = ProfileManager::GetActiveUserProfile();
    241   return profile ? profile->GetPrefs() : NULL;
    242 }
    243 
    244 bool EventRewriter::IsAppleKeyboard() const {
    245   if (last_device_id_ == kBadDeviceId)
    246     return false;
    247 
    248   // Check which device generated |event|.
    249   std::map<int, DeviceType>::const_iterator iter =
    250       device_id_to_type_.find(last_device_id_);
    251   if (iter == device_id_to_type_.end()) {
    252     LOG(ERROR) << "Device ID " << last_device_id_ << " is unknown.";
    253     return false;
    254   }
    255 
    256   const DeviceType type = iter->second;
    257   return type == kDeviceAppleKeyboard;
    258 }
    259 
    260 bool EventRewriter::TopRowKeysAreFunctionKeys(const ui::KeyEvent& event) const {
    261   const PrefService* prefs = GetPrefService();
    262   if (prefs && prefs->FindPreference(prefs::kLanguageSendFunctionKeys) &&
    263       prefs->GetBoolean(prefs::kLanguageSendFunctionKeys))
    264     return true;
    265 
    266   ash::wm::WindowState* state = ash::wm::GetActiveWindowState();
    267   return state ? state->top_row_keys_are_function_keys() : false;
    268 }
    269 
    270 int EventRewriter::GetRemappedModifierMasks(const PrefService& pref_service,
    271                                             const ui::Event& event,
    272                                             int original_flags) const {
    273   int unmodified_flags = original_flags;
    274   int rewritten_flags = 0;
    275   for (size_t i = 0; unmodified_flags && (i < arraysize(kModifierRemappings));
    276        ++i) {
    277     const ModifierRemapping* remapped_key = 0;
    278     if (!(unmodified_flags & kModifierRemappings[i].flag))
    279       continue;
    280     switch (kModifierRemappings[i].flag) {
    281       case ui::EF_COMMAND_DOWN:
    282         // Rewrite Command key presses on an Apple keyboard to Control.
    283         if (IsAppleKeyboard()) {
    284           DCHECK_EQ(ui::EF_CONTROL_DOWN, kModifierRemappingCtrl->flag);
    285           remapped_key = kModifierRemappingCtrl;
    286         }
    287         break;
    288       case ui::EF_MOD3_DOWN:
    289         // If EF_MOD3_DOWN is used by the current input method, leave it alone;
    290         // it is not remappable.
    291         if (IsISOLevel5ShiftUsedByCurrentInputMethod())
    292           continue;
    293         // Otherwise, Mod3Mask is set on X events when the Caps Lock key
    294         // is down, but, if Caps Lock is remapped, CapsLock is NOT set,
    295         // because pressing the key does not invoke caps lock. So, the
    296         // kModifierRemappings[] table uses EF_MOD3_DOWN for the Caps
    297         // Lock remapping.
    298         break;
    299       default:
    300         break;
    301     }
    302     if (!remapped_key && kModifierRemappings[i].pref_name) {
    303       remapped_key =
    304           GetRemappedKey(kModifierRemappings[i].pref_name, pref_service);
    305     }
    306     if (remapped_key) {
    307       unmodified_flags &= ~kModifierRemappings[i].flag;
    308       rewritten_flags |= remapped_key->flag;
    309     }
    310   }
    311   return rewritten_flags | unmodified_flags;
    312 }
    313 
    314 bool EventRewriter::RewriteWithKeyboardRemappingsByKeyCode(
    315     const KeyboardRemapping* remappings,
    316     size_t num_remappings,
    317     const MutableKeyState& input,
    318     MutableKeyState* remapped_state) {
    319   for (size_t i = 0; i < num_remappings; ++i) {
    320     const KeyboardRemapping& map = remappings[i];
    321     if (input.key_code != map.input_key_code)
    322       continue;
    323     if ((input.flags & map.input_flags) != map.input_flags)
    324       continue;
    325     remapped_state->key_code = map.output_key_code;
    326     remapped_state->flags = (input.flags & ~map.input_flags) | map.output_flags;
    327     return true;
    328   }
    329   return false;
    330 }
    331 
    332 ui::EventRewriteStatus EventRewriter::RewriteKeyEvent(
    333     const ui::KeyEvent& key_event,
    334     scoped_ptr<ui::Event>* rewritten_event) {
    335   MutableKeyState state = {key_event.flags(), key_event.key_code()};
    336   RewriteModifierKeys(key_event, &state);
    337   RewriteNumPadKeys(key_event, &state);
    338   RewriteExtendedKeys(key_event, &state);
    339   RewriteFunctionKeys(key_event, &state);
    340   if ((key_event.flags() == state.flags) &&
    341       (key_event.key_code() == state.key_code)) {
    342     return ui::EVENT_REWRITE_CONTINUE;
    343   }
    344   ui::KeyEvent* rewritten_key_event = new ui::KeyEvent(key_event);
    345   rewritten_event->reset(rewritten_key_event);
    346   rewritten_key_event->set_flags(state.flags);
    347   rewritten_key_event->set_key_code(state.key_code);
    348   rewritten_key_event->set_character(
    349       ui::GetCharacterFromKeyCode(state.key_code, state.flags));
    350   rewritten_key_event->NormalizeFlags();
    351 #if defined(USE_X11)
    352   XEvent* xev = rewritten_key_event->native_event();
    353   if (xev) {
    354     CHECK(xev->type == KeyPress || xev->type == KeyRelease);
    355     XKeyEvent* xkey = &(xev->xkey);
    356     UpdateX11EventMask(rewritten_key_event->flags(), &xkey->state);
    357     xkey->keycode =
    358         XKeysymToKeycode(gfx::GetXDisplay(),
    359                          ui::XKeysymForWindowsKeyCode(
    360                              state.key_code, state.flags & ui::EF_SHIFT_DOWN));
    361   }
    362 #endif
    363   return ui::EVENT_REWRITE_REWRITTEN;
    364 }
    365 
    366 ui::EventRewriteStatus EventRewriter::RewriteMouseEvent(
    367     const ui::MouseEvent& mouse_event,
    368     scoped_ptr<ui::Event>* rewritten_event) {
    369   int flags = mouse_event.flags();
    370   RewriteLocatedEvent(mouse_event, &flags);
    371   if (mouse_event.flags() == flags)
    372     return ui::EVENT_REWRITE_CONTINUE;
    373   ui::MouseEvent* rewritten_mouse_event = new ui::MouseEvent(mouse_event);
    374   rewritten_event->reset(rewritten_mouse_event);
    375   rewritten_mouse_event->set_flags(flags);
    376 #if defined(USE_X11)
    377   XEvent* xev = rewritten_mouse_event->native_event();
    378   if (xev) {
    379     switch (xev->type) {
    380       case ButtonPress:
    381       case ButtonRelease: {
    382         XButtonEvent* xbutton = &(xev->xbutton);
    383         UpdateX11EventMask(rewritten_mouse_event->flags(), &xbutton->state);
    384         break;
    385       }
    386       case GenericEvent: {
    387         XIDeviceEvent* xievent = static_cast<XIDeviceEvent*>(xev->xcookie.data);
    388         CHECK(xievent->evtype == XI_ButtonPress ||
    389               xievent->evtype == XI_ButtonRelease);
    390         UpdateX11EventMask(
    391             rewritten_mouse_event->flags(),
    392             reinterpret_cast<unsigned int*>(&xievent->mods.effective));
    393         break;
    394       }
    395       default:
    396         NOTREACHED();
    397     }
    398   }
    399 #endif
    400   return ui::EVENT_REWRITE_REWRITTEN;
    401 }
    402 
    403 ui::EventRewriteStatus EventRewriter::RewriteTouchEvent(
    404     const ui::TouchEvent& touch_event,
    405     scoped_ptr<ui::Event>* rewritten_event) {
    406   int flags = touch_event.flags();
    407   RewriteLocatedEvent(touch_event, &flags);
    408   if (touch_event.flags() == flags)
    409     return ui::EVENT_REWRITE_CONTINUE;
    410   ui::TouchEvent* rewritten_touch_event = new ui::TouchEvent(touch_event);
    411   rewritten_event->reset(rewritten_touch_event);
    412   rewritten_touch_event->set_flags(flags);
    413 #if defined(USE_X11)
    414   XEvent* xev = rewritten_touch_event->native_event();
    415   if (xev) {
    416     XIDeviceEvent* xievent = static_cast<XIDeviceEvent*>(xev->xcookie.data);
    417     if (xievent) {
    418       UpdateX11EventMask(
    419           rewritten_touch_event->flags(),
    420           reinterpret_cast<unsigned int*>(&xievent->mods.effective));
    421     }
    422   }
    423 #endif
    424   return ui::EVENT_REWRITE_REWRITTEN;
    425 }
    426 
    427 void EventRewriter::RewriteModifierKeys(const ui::KeyEvent& key_event,
    428                                         MutableKeyState* state) {
    429   DCHECK(key_event.type() == ui::ET_KEY_PRESSED ||
    430          key_event.type() == ui::ET_KEY_RELEASED);
    431 
    432   // Do nothing if we have just logged in as guest but have not restarted chrome
    433   // process yet (so we are still on the login screen). In this situations we
    434   // have no user profile so can not do anything useful.
    435   // Note that currently, unlike other accounts, when user logs in as guest, we
    436   // restart chrome process. In future this is to be changed.
    437   // TODO(glotov): remove the following condition when we do not restart chrome
    438   // when user logs in as guest.
    439   // TODO(kpschoedel): check whether this is still necessary.
    440   if (UserManager::Get()->IsLoggedInAsGuest() &&
    441       LoginDisplayHostImpl::default_host())
    442     return;
    443 
    444   const PrefService* pref_service = GetPrefService();
    445   if (!pref_service)
    446     return;
    447 
    448   MutableKeyState incoming = *state;
    449   state->flags = ui::EF_NONE;
    450   int characteristic_flag = ui::EF_NONE;
    451 
    452   // First, remap the key code.
    453   const ModifierRemapping* remapped_key = NULL;
    454   switch (incoming.key_code) {
    455     // On Chrome OS, F15 (XF86XK_Launch6) with NumLock (Mod2Mask) is sent
    456     // when Diamond key is pressed.
    457     case ui::VKEY_F15:
    458       // When diamond key is not available, the configuration UI for Diamond
    459       // key is not shown. Therefore, ignore the kLanguageRemapDiamondKeyTo
    460       // syncable pref.
    461       if (HasDiamondKey())
    462         remapped_key =
    463             GetRemappedKey(prefs::kLanguageRemapDiamondKeyTo, *pref_service);
    464       // Default behavior is Ctrl key.
    465       if (!remapped_key) {
    466         DCHECK_EQ(ui::VKEY_CONTROL, kModifierRemappingCtrl->key_code);
    467         remapped_key = kModifierRemappingCtrl;
    468         characteristic_flag = ui::EF_CONTROL_DOWN;
    469       }
    470       break;
    471     // On Chrome OS, XF86XK_Launch7 (F16) with Mod3Mask is sent when Caps Lock
    472     // is pressed (with one exception: when
    473     // IsISOLevel5ShiftUsedByCurrentInputMethod() is true, the key generates
    474     // XK_ISO_Level3_Shift with Mod3Mask, not XF86XK_Launch7).
    475     case ui::VKEY_F16:
    476       characteristic_flag = ui::EF_CAPS_LOCK_DOWN;
    477       remapped_key =
    478           GetRemappedKey(prefs::kLanguageRemapCapsLockKeyTo, *pref_service);
    479       break;
    480     case ui::VKEY_LWIN:
    481     case ui::VKEY_RWIN:
    482       characteristic_flag = ui::EF_COMMAND_DOWN;
    483       // Rewrite Command-L/R key presses on an Apple keyboard to Control.
    484       if (IsAppleKeyboard()) {
    485         DCHECK_EQ(ui::VKEY_CONTROL, kModifierRemappingCtrl->key_code);
    486         remapped_key = kModifierRemappingCtrl;
    487       } else {
    488         remapped_key =
    489             GetRemappedKey(prefs::kLanguageRemapSearchKeyTo, *pref_service);
    490       }
    491       // Default behavior is Super key, hence don't remap the event if the pref
    492       // is unavailable.
    493       break;
    494     case ui::VKEY_CONTROL:
    495       characteristic_flag = ui::EF_CONTROL_DOWN;
    496       remapped_key =
    497           GetRemappedKey(prefs::kLanguageRemapControlKeyTo, *pref_service);
    498       break;
    499     case ui::VKEY_MENU:
    500       // ALT key
    501       characteristic_flag = ui::EF_ALT_DOWN;
    502       remapped_key =
    503           GetRemappedKey(prefs::kLanguageRemapAltKeyTo, *pref_service);
    504       break;
    505     default:
    506       break;
    507   }
    508 
    509   if (remapped_key) {
    510     state->key_code = remapped_key->key_code;
    511     incoming.flags |= characteristic_flag;
    512     characteristic_flag = remapped_key->flag;
    513   }
    514 
    515   // Next, remap modifier bits.
    516   state->flags |=
    517       GetRemappedModifierMasks(*pref_service, key_event, incoming.flags);
    518   if (key_event.type() == ui::ET_KEY_PRESSED)
    519     state->flags |= characteristic_flag;
    520   else
    521     state->flags &= ~characteristic_flag;
    522 
    523   // Toggle Caps Lock if the remapped key is ui::VKEY_CAPITAL, but do nothing if
    524   // the original key is ui::VKEY_CAPITAL (i.e. a Caps Lock key on an external
    525   // keyboard is pressed) since X can handle that case.
    526   if (key_event.type() == ui::ET_KEY_PRESSED &&
    527       incoming.key_code != ui::VKEY_CAPITAL &&
    528       state->key_code == ui::VKEY_CAPITAL) {
    529     chromeos::input_method::ImeKeyboard* ime_keyboard =
    530         ime_keyboard_for_testing_
    531             ? ime_keyboard_for_testing_
    532             : chromeos::input_method::InputMethodManager::Get()
    533                   ->GetImeKeyboard();
    534     ime_keyboard->SetCapsLockEnabled(!ime_keyboard->CapsLockIsEnabled());
    535   }
    536 }
    537 
    538 void EventRewriter::RewriteNumPadKeys(const ui::KeyEvent& key_event,
    539                                       MutableKeyState* state) {
    540   DCHECK(key_event.type() == ui::ET_KEY_PRESSED ||
    541          key_event.type() == ui::ET_KEY_RELEASED);
    542   if (!(state->flags & ui::EF_NUMPAD_KEY))
    543     return;
    544   MutableKeyState incoming = *state;
    545 
    546   static const KeyboardRemapping kNumPadRemappings[] = {
    547       {ui::VKEY_INSERT, ui::EF_NUMPAD_KEY, ui::VKEY_NUMPAD0, ui::EF_NUMPAD_KEY},
    548       {ui::VKEY_DELETE, ui::EF_NUMPAD_KEY, ui::VKEY_DECIMAL, ui::EF_NUMPAD_KEY},
    549       {ui::VKEY_END, ui::EF_NUMPAD_KEY, ui::VKEY_NUMPAD1, ui::EF_NUMPAD_KEY},
    550       {ui::VKEY_DOWN, ui::EF_NUMPAD_KEY, ui::VKEY_NUMPAD2, ui::EF_NUMPAD_KEY},
    551       {ui::VKEY_NEXT, ui::EF_NUMPAD_KEY, ui::VKEY_NUMPAD3, ui::EF_NUMPAD_KEY},
    552       {ui::VKEY_LEFT, ui::EF_NUMPAD_KEY, ui::VKEY_NUMPAD4, ui::EF_NUMPAD_KEY},
    553       {ui::VKEY_CLEAR, ui::EF_NUMPAD_KEY, ui::VKEY_NUMPAD5, ui::EF_NUMPAD_KEY},
    554       {ui::VKEY_RIGHT, ui::EF_NUMPAD_KEY, ui::VKEY_NUMPAD6, ui::EF_NUMPAD_KEY},
    555       {ui::VKEY_HOME, ui::EF_NUMPAD_KEY, ui::VKEY_NUMPAD7, ui::EF_NUMPAD_KEY},
    556       {ui::VKEY_UP, ui::EF_NUMPAD_KEY, ui::VKEY_NUMPAD8, ui::EF_NUMPAD_KEY},
    557       {ui::VKEY_PRIOR, ui::EF_NUMPAD_KEY, ui::VKEY_NUMPAD9, ui::EF_NUMPAD_KEY},
    558   };
    559 
    560   RewriteWithKeyboardRemappingsByKeyCode(
    561       kNumPadRemappings, arraysize(kNumPadRemappings), incoming, state);
    562 }
    563 
    564 void EventRewriter::RewriteExtendedKeys(const ui::KeyEvent& key_event,
    565                                         MutableKeyState* state) {
    566   DCHECK(key_event.type() == ui::ET_KEY_PRESSED ||
    567          key_event.type() == ui::ET_KEY_RELEASED);
    568 
    569   MutableKeyState incoming = *state;
    570   bool rewritten = false;
    571 
    572   if ((incoming.flags & (ui::EF_COMMAND_DOWN | ui::EF_ALT_DOWN)) ==
    573       (ui::EF_COMMAND_DOWN | ui::EF_ALT_DOWN)) {
    574     // Allow Search to avoid rewriting extended keys.
    575     static const KeyboardRemapping kAvoidRemappings[] = {
    576         {  // Alt+Backspace
    577          ui::VKEY_BACK, ui::EF_ALT_DOWN | ui::EF_COMMAND_DOWN, ui::VKEY_BACK,
    578          ui::EF_ALT_DOWN,
    579         },
    580         {  // Control+Alt+Up
    581          ui::VKEY_UP,
    582          ui::EF_ALT_DOWN | ui::EF_CONTROL_DOWN | ui::EF_COMMAND_DOWN,
    583          ui::VKEY_UP, ui::EF_ALT_DOWN | ui::EF_CONTROL_DOWN,
    584         },
    585         {  // Alt+Up
    586          ui::VKEY_UP, ui::EF_ALT_DOWN | ui::EF_COMMAND_DOWN, ui::VKEY_UP,
    587          ui::EF_ALT_DOWN,
    588         },
    589         {  // Control+Alt+Down
    590          ui::VKEY_DOWN,
    591          ui::EF_ALT_DOWN | ui::EF_CONTROL_DOWN | ui::EF_COMMAND_DOWN,
    592          ui::VKEY_DOWN, ui::EF_ALT_DOWN | ui::EF_CONTROL_DOWN,
    593         },
    594         {  // Alt+Down
    595          ui::VKEY_DOWN, ui::EF_ALT_DOWN | ui::EF_COMMAND_DOWN, ui::VKEY_DOWN,
    596          ui::EF_ALT_DOWN,
    597         }};
    598 
    599     rewritten = RewriteWithKeyboardRemappingsByKeyCode(
    600         kAvoidRemappings, arraysize(kAvoidRemappings), incoming, state);
    601   }
    602 
    603   if (!rewritten && (incoming.flags & ui::EF_COMMAND_DOWN)) {
    604     static const KeyboardRemapping kSearchRemappings[] = {
    605         {  // Search+BackSpace -> Delete
    606          ui::VKEY_BACK, ui::EF_COMMAND_DOWN, ui::VKEY_DELETE, 0},
    607         {  // Search+Left -> Home
    608          ui::VKEY_LEFT, ui::EF_COMMAND_DOWN, ui::VKEY_HOME, 0},
    609         {  // Search+Up -> Prior (aka PageUp)
    610          ui::VKEY_UP, ui::EF_COMMAND_DOWN, ui::VKEY_PRIOR, 0},
    611         {  // Search+Right -> End
    612          ui::VKEY_RIGHT, ui::EF_COMMAND_DOWN, ui::VKEY_END, 0},
    613         {  // Search+Down -> Next (aka PageDown)
    614          ui::VKEY_DOWN, ui::EF_COMMAND_DOWN, ui::VKEY_NEXT, 0},
    615         {  // Search+Period -> Insert
    616          ui::VKEY_OEM_PERIOD, ui::EF_COMMAND_DOWN, ui::VKEY_INSERT, 0}};
    617 
    618     rewritten = RewriteWithKeyboardRemappingsByKeyCode(
    619         kSearchRemappings, arraysize(kSearchRemappings), incoming, state);
    620   }
    621 
    622   if (!rewritten && (incoming.flags & ui::EF_ALT_DOWN)) {
    623     static const KeyboardRemapping kNonSearchRemappings[] = {
    624         {  // Alt+BackSpace -> Delete
    625          ui::VKEY_BACK, ui::EF_ALT_DOWN, ui::VKEY_DELETE, 0},
    626         {  // Control+Alt+Up -> Home
    627          ui::VKEY_UP, ui::EF_ALT_DOWN | ui::EF_CONTROL_DOWN, ui::VKEY_HOME, 0},
    628         {  // Alt+Up -> Prior (aka PageUp)
    629          ui::VKEY_UP, ui::EF_ALT_DOWN, ui::VKEY_PRIOR, 0},
    630         {  // Control+Alt+Down -> End
    631          ui::VKEY_DOWN, ui::EF_ALT_DOWN | ui::EF_CONTROL_DOWN, ui::VKEY_END, 0},
    632         {  // Alt+Down -> Next (aka PageDown)
    633          ui::VKEY_DOWN, ui::EF_ALT_DOWN, ui::VKEY_NEXT, 0}};
    634 
    635     rewritten = RewriteWithKeyboardRemappingsByKeyCode(
    636         kNonSearchRemappings, arraysize(kNonSearchRemappings), incoming, state);
    637   }
    638 }
    639 
    640 void EventRewriter::RewriteFunctionKeys(const ui::KeyEvent& key_event,
    641                                         MutableKeyState* state) {
    642   CHECK(key_event.type() == ui::ET_KEY_PRESSED ||
    643         key_event.type() == ui::ET_KEY_RELEASED);
    644   MutableKeyState incoming = *state;
    645   bool rewritten = false;
    646 
    647   if ((incoming.key_code >= ui::VKEY_F1) &&
    648       (incoming.key_code <= ui::VKEY_F24)) {
    649     // By default the top row (F1-F12) keys are system keys for back, forward,
    650     // brightness, volume, etc. However, windows for v2 apps can optionally
    651     // request raw function keys for these keys.
    652     bool top_row_keys_are_function_keys = TopRowKeysAreFunctionKeys(key_event);
    653     bool search_is_pressed = (incoming.flags & ui::EF_COMMAND_DOWN) != 0;
    654 
    655     //  Search? Top Row   Result
    656     //  ------- --------  ------
    657     //  No      Fn        Unchanged
    658     //  No      System    Fn -> System
    659     //  Yes     Fn        Fn -> System
    660     //  Yes     System    Search+Fn -> Fn
    661     if (top_row_keys_are_function_keys == search_is_pressed) {
    662       // Rewrite the F1-F12 keys on a Chromebook keyboard to system keys.
    663       static const KeyboardRemapping kFkeysToSystemKeys[] = {
    664           {ui::VKEY_F1, 0, ui::VKEY_BROWSER_BACK, 0},
    665           {ui::VKEY_F2, 0, ui::VKEY_BROWSER_FORWARD, 0},
    666           {ui::VKEY_F3, 0, ui::VKEY_BROWSER_REFRESH, 0},
    667           {ui::VKEY_F4, 0, ui::VKEY_MEDIA_LAUNCH_APP2, 0},
    668           {ui::VKEY_F5, 0, ui::VKEY_MEDIA_LAUNCH_APP1, 0},
    669           {ui::VKEY_F6, 0, ui::VKEY_BRIGHTNESS_DOWN, 0},
    670           {ui::VKEY_F7, 0, ui::VKEY_BRIGHTNESS_UP, 0},
    671           {ui::VKEY_F8, 0, ui::VKEY_VOLUME_MUTE, 0},
    672           {ui::VKEY_F9, 0, ui::VKEY_VOLUME_DOWN, 0},
    673           {ui::VKEY_F10, 0, ui::VKEY_VOLUME_UP, 0},
    674       };
    675       MutableKeyState incoming_without_command = incoming;
    676       incoming_without_command.flags &= ~ui::EF_COMMAND_DOWN;
    677       rewritten =
    678           RewriteWithKeyboardRemappingsByKeyCode(kFkeysToSystemKeys,
    679                                                  arraysize(kFkeysToSystemKeys),
    680                                                  incoming_without_command,
    681                                                  state);
    682     } else if (search_is_pressed) {
    683       // Allow Search to avoid rewriting F1-F12.
    684       state->flags &= ~ui::EF_COMMAND_DOWN;
    685       rewritten = true;
    686     }
    687   }
    688 
    689   if (!rewritten && (incoming.flags & ui::EF_COMMAND_DOWN)) {
    690     // Remap Search+<number> to F<number>.
    691     // We check the keycode here instead of the keysym, as these keys have
    692     // different keysyms when modifiers are pressed, such as shift.
    693 
    694     // TODO(danakj): On some i18n keyboards, these choices will be bad and we
    695     // should make layout-specific choices here. For eg. on a french keyboard
    696     // "-" and "6" are the same key, so F11 will not be accessible.
    697     static const KeyboardRemapping kNumberKeysToFkeys[] = {
    698         {ui::VKEY_1, ui::EF_COMMAND_DOWN, ui::VKEY_F1, 0},
    699         {ui::VKEY_2, ui::EF_COMMAND_DOWN, ui::VKEY_F2, 0},
    700         {ui::VKEY_3, ui::EF_COMMAND_DOWN, ui::VKEY_F3, 0},
    701         {ui::VKEY_4, ui::EF_COMMAND_DOWN, ui::VKEY_F4, 0},
    702         {ui::VKEY_5, ui::EF_COMMAND_DOWN, ui::VKEY_F5, 0},
    703         {ui::VKEY_6, ui::EF_COMMAND_DOWN, ui::VKEY_F6, 0},
    704         {ui::VKEY_7, ui::EF_COMMAND_DOWN, ui::VKEY_F7, 0},
    705         {ui::VKEY_8, ui::EF_COMMAND_DOWN, ui::VKEY_F8, 0},
    706         {ui::VKEY_9, ui::EF_COMMAND_DOWN, ui::VKEY_F9, 0},
    707         {ui::VKEY_0, ui::EF_COMMAND_DOWN, ui::VKEY_F10, 0},
    708         {ui::VKEY_OEM_MINUS, ui::EF_COMMAND_DOWN, ui::VKEY_F11, 0},
    709         {ui::VKEY_OEM_PLUS, ui::EF_COMMAND_DOWN, ui::VKEY_F12, 0}};
    710     rewritten = RewriteWithKeyboardRemappingsByKeyCode(
    711         kNumberKeysToFkeys, arraysize(kNumberKeysToFkeys), incoming, state);
    712   }
    713 }
    714 
    715 void EventRewriter::RewriteLocatedEvent(const ui::Event& event,
    716                                         int* flags) {
    717   const PrefService* pref_service = GetPrefService();
    718   if (!pref_service)
    719     return;
    720 
    721   // First, remap modifier masks.
    722   *flags = GetRemappedModifierMasks(*pref_service, event, *flags);
    723 
    724 #if defined(USE_X11)
    725   // TODO(kpschoedel): de-X11 with unified device ids from crbug.com/360377
    726   XEvent* xevent = event.native_event();
    727   if (!xevent || xevent->type != GenericEvent)
    728     return;
    729   XIDeviceEvent* xievent = static_cast<XIDeviceEvent*>(xevent->xcookie.data);
    730   if (xievent->evtype != XI_ButtonPress && xievent->evtype != XI_ButtonRelease)
    731     return;
    732   UpdateX11EventMask(*flags,
    733                      reinterpret_cast<unsigned int*>(&xievent->mods.effective));
    734 
    735   // Then, remap Alt+Button1 to Button3.
    736   if ((xievent->evtype == XI_ButtonPress ||
    737        pressed_device_ids_.count(xievent->sourceid)) &&
    738       (xievent->mods.effective & Mod1Mask) && xievent->detail == Button1) {
    739     *flags &= ~(ui::EF_ALT_DOWN | ui::EF_LEFT_MOUSE_BUTTON);
    740     *flags |= ui::EF_RIGHT_MOUSE_BUTTON;
    741     xievent->mods.effective &= ~Mod1Mask;
    742     xievent->detail = Button3;
    743     if (xievent->evtype == XI_ButtonRelease) {
    744       // On the release clear the left button from the existing state and the
    745       // mods, and set the right button.
    746       XISetMask(xievent->buttons.mask, Button3);
    747       XIClearMask(xievent->buttons.mask, Button1);
    748       xievent->mods.effective &= ~Button1Mask;
    749       pressed_device_ids_.erase(xievent->sourceid);
    750     } else {
    751       pressed_device_ids_.insert(xievent->sourceid);
    752     }
    753   }
    754 #endif  // defined(USE_X11)
    755 }
    756 
    757 EventRewriter::DeviceType EventRewriter::DeviceAddedInternal(
    758     int device_id,
    759     const std::string& device_name) {
    760   const DeviceType type = GetDeviceType(device_name);
    761   if (type == kDeviceAppleKeyboard) {
    762     VLOG(1) << "Apple keyboard '" << device_name << "' connected: "
    763             << "id=" << device_id;
    764   }
    765   // Always overwrite the existing device_id since the X server may reuse a
    766   // device id for an unattached device.
    767   device_id_to_type_[device_id] = type;
    768   return type;
    769 }
    770 
    771 #if defined(USE_X11)
    772 void EventRewriter::WillProcessEvent(const ui::PlatformEvent& event) {
    773   XEvent* xevent = event;
    774   if (xevent->type == GenericEvent) {
    775     XIDeviceEvent* xievent = static_cast<XIDeviceEvent*>(xevent->xcookie.data);
    776     if (xievent->evtype == XI_KeyPress || xievent->evtype == XI_KeyRelease) {
    777       if (xievent->deviceid == xievent->sourceid)
    778         DeviceKeyPressedOrReleased(xievent->deviceid);
    779     }
    780   }
    781 }
    782 
    783 void EventRewriter::DidProcessEvent(const ui::PlatformEvent& event) {
    784 }
    785 
    786 void EventRewriter::DeviceHierarchyChanged() {
    787 }
    788 
    789 void EventRewriter::DeviceAdded(int device_id) {
    790   DCHECK_NE(XIAllDevices, device_id);
    791   DCHECK_NE(XIAllMasterDevices, device_id);
    792   if (device_id == XIAllDevices || device_id == XIAllMasterDevices) {
    793     LOG(ERROR) << "Unexpected device_id passed: " << device_id;
    794     return;
    795   }
    796 
    797   int ndevices_return = 0;
    798   XIDeviceInfo* device_info =
    799       XIQueryDevice(gfx::GetXDisplay(), device_id, &ndevices_return);
    800 
    801   // Since |device_id| is neither XIAllDevices nor XIAllMasterDevices,
    802   // the number of devices found should be either 0 (not found) or 1.
    803   if (!device_info) {
    804     LOG(ERROR) << "XIQueryDevice: Device ID " << device_id << " is unknown.";
    805     return;
    806   }
    807 
    808   DCHECK_EQ(1, ndevices_return);
    809   for (int i = 0; i < ndevices_return; ++i) {
    810     DCHECK_EQ(device_id, device_info[i].deviceid);  // see the comment above.
    811     DCHECK(device_info[i].name);
    812     DeviceAddedInternal(device_info[i].deviceid, device_info[i].name);
    813   }
    814 
    815   XIFreeDeviceInfo(device_info);
    816 }
    817 
    818 void EventRewriter::DeviceRemoved(int device_id) {
    819   device_id_to_type_.erase(device_id);
    820 }
    821 #endif
    822 
    823 }  // namespace chromeos
    824