Home | History | Annotate | Download | only in ash
      1 // Copyright (c) 2012 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/ui/ash/event_rewriter.h"
      6 
      7 #include <vector>
      8 
      9 #include "ash/shell.h"
     10 #include "base/logging.h"
     11 #include "base/prefs/pref_service.h"
     12 #include "base/strings/string_util.h"
     13 #include "chrome/browser/profiles/profile_manager.h"
     14 #include "ui/aura/root_window.h"
     15 #include "ui/base/events/event.h"
     16 #include "ui/base/events/event_utils.h"
     17 #include "ui/base/keycodes/keyboard_code_conversion.h"
     18 
     19 #if defined(OS_CHROMEOS)
     20 #include <X11/extensions/XInput2.h>
     21 #include <X11/keysym.h>
     22 #include <X11/XF86keysym.h>
     23 #include <X11/Xlib.h>
     24 
     25 // Get rid of a macro from Xlib.h that conflicts with OwnershipService class.
     26 #undef Status
     27 
     28 #include "base/chromeos/chromeos_version.h"
     29 #include "base/command_line.h"
     30 #include "chrome/browser/chromeos/keyboard_driven_event_rewriter.h"
     31 #include "chrome/browser/chromeos/login/login_display_host_impl.h"
     32 #include "chrome/browser/chromeos/login/user_manager.h"
     33 #include "chrome/browser/chromeos/xinput_hierarchy_changed_event_listener.h"
     34 #include "chrome/common/pref_names.h"
     35 #include "chromeos/chromeos_switches.h"
     36 #include "chromeos/ime/input_method_manager.h"
     37 #include "chromeos/ime/xkeyboard.h"
     38 #include "ui/base/keycodes/keyboard_code_conversion_x.h"
     39 #include "ui/base/x/x11_util.h"
     40 #endif
     41 
     42 namespace {
     43 
     44 const int kBadDeviceId = -1;
     45 
     46 #if defined(OS_CHROMEOS)
     47 const char kNeo2LayoutId[] = "xkb:de:neo:ger";
     48 const char kCaMultixLayoutId[] = "xkb:ca:multix:fra";
     49 
     50 // A key code and a flag we should use when a key is remapped to |remap_to|.
     51 const struct ModifierRemapping {
     52   int remap_to;
     53   int flag;
     54   unsigned int native_modifier;
     55   ui::KeyboardCode keycode;
     56   KeySym native_keysyms[4];  // left, right, shift+left, shift+right.
     57 } kModifierRemappings[] = {
     58   { chromeos::input_method::kSearchKey, 0, Mod4Mask, ui::VKEY_LWIN,
     59     { XK_Super_L, XK_Super_L, XK_Super_L, XK_Super_L }},
     60   { chromeos::input_method::kControlKey, ui::EF_CONTROL_DOWN, ControlMask,
     61     ui::VKEY_CONTROL,
     62     { XK_Control_L, XK_Control_R, XK_Control_L, XK_Control_R }},
     63   { chromeos::input_method::kAltKey, ui::EF_ALT_DOWN, Mod1Mask,
     64     ui::VKEY_MENU, { XK_Alt_L, XK_Alt_R, XK_Meta_L, XK_Meta_R }},
     65   { chromeos::input_method::kVoidKey, 0, 0U, ui::VKEY_UNKNOWN,
     66     { XK_VoidSymbol, XK_VoidSymbol, XK_VoidSymbol, XK_VoidSymbol }},
     67   { chromeos::input_method::kCapsLockKey, 0, 0U, ui::VKEY_CAPITAL,
     68     { XK_Caps_Lock, XK_Caps_Lock, XK_Caps_Lock, XK_Caps_Lock }},
     69 };
     70 
     71 const ModifierRemapping* kModifierRemappingCtrl = &kModifierRemappings[1];
     72 
     73 // A structure for converting |native_modifier| to a pair of |flag| and
     74 // |pref_name|.
     75 const struct ModifierFlagToPrefName {
     76   unsigned int native_modifier;
     77   int flag;
     78   const char* pref_name;
     79 } kModifierFlagToPrefName[] = {
     80   // TODO(yusukes): When the device has a Chrome keyboard (i.e. the one without
     81   // Caps Lock), we should not check kLanguageRemapCapsLockKeyTo.
     82   { Mod3Mask, 0, prefs::kLanguageRemapCapsLockKeyTo },
     83   { Mod4Mask, 0, prefs::kLanguageRemapSearchKeyTo },
     84   { ControlMask, ui::EF_CONTROL_DOWN, prefs::kLanguageRemapControlKeyTo },
     85   { Mod1Mask, ui::EF_ALT_DOWN, prefs::kLanguageRemapAltKeyTo },
     86   { Mod2Mask, 0, prefs::kLanguageRemapDiamondKeyTo },
     87 };
     88 
     89 // Gets a remapped key for |pref_name| key. For example, to find out which
     90 // key Search is currently remapped to, call the function with
     91 // prefs::kLanguageRemapSearchKeyTo.
     92 const ModifierRemapping* GetRemappedKey(const std::string& pref_name,
     93                                         const PrefService& pref_service) {
     94   if (!pref_service.FindPreference(pref_name.c_str()))
     95     return NULL;  // The |pref_name| hasn't been registered. On login screen?
     96   const int value = pref_service.GetInteger(pref_name.c_str());
     97   for (size_t i = 0; i < arraysize(kModifierRemappings); ++i) {
     98     if (value == kModifierRemappings[i].remap_to)
     99       return &kModifierRemappings[i];
    100   }
    101   return NULL;
    102 }
    103 
    104 bool IsRight(KeySym native_keysym) {
    105   switch (native_keysym) {
    106     case XK_Alt_R:
    107     case XK_Control_R:
    108     case XK_Hyper_R:
    109     case XK_Meta_R:
    110     case XK_Shift_R:
    111     case XK_Super_R:
    112       return true;
    113     default:
    114       break;
    115   }
    116   return false;
    117 }
    118 
    119 bool HasDiamondKey() {
    120   return CommandLine::ForCurrentProcess()->HasSwitch(
    121       chromeos::switches::kHasChromeOSDiamondKey);
    122 }
    123 
    124 bool IsMod3UsedByCurrentInputMethod() {
    125   // Since both German Neo2 XKB layout and Caps Lock depend on Mod3Mask,
    126   // it's not possible to make both features work. For now, we don't remap
    127   // Mod3Mask when Neo2 is in use.
    128   // TODO(yusukes): Remove the restriction.
    129   chromeos::input_method::InputMethodManager* manager =
    130       chromeos::input_method::InputMethodManager::Get();
    131   return manager->GetCurrentInputMethod().id() == kNeo2LayoutId ||
    132       manager->GetCurrentInputMethod().id() == kCaMultixLayoutId;
    133 }
    134 #endif
    135 
    136 const PrefService* GetPrefService() {
    137   Profile* profile = ProfileManager::GetDefaultProfile();
    138   if (profile)
    139     return profile->GetPrefs();
    140   return NULL;
    141 }
    142 
    143 }  // namespace
    144 
    145 EventRewriter::EventRewriter()
    146     : last_device_id_(kBadDeviceId),
    147 #if defined(OS_CHROMEOS)
    148       xkeyboard_(NULL),
    149       keyboard_driven_event_rewritter_(
    150           new chromeos::KeyboardDrivenEventRewriter),
    151 #endif
    152       pref_service_(NULL) {
    153   // The ash shell isn't instantiated for our unit tests.
    154   if (ash::Shell::HasInstance())
    155     ash::Shell::GetPrimaryRootWindow()->AddRootWindowObserver(this);
    156 #if defined(OS_CHROMEOS)
    157   if (base::chromeos::IsRunningOnChromeOS()) {
    158     chromeos::XInputHierarchyChangedEventListener::GetInstance()
    159         ->AddObserver(this);
    160   }
    161   RefreshKeycodes();
    162 #endif
    163 }
    164 
    165 EventRewriter::~EventRewriter() {
    166   if (ash::Shell::HasInstance())
    167     ash::Shell::GetPrimaryRootWindow()->RemoveRootWindowObserver(this);
    168 #if defined(OS_CHROMEOS)
    169   if (base::chromeos::IsRunningOnChromeOS()) {
    170     chromeos::XInputHierarchyChangedEventListener::GetInstance()
    171         ->RemoveObserver(this);
    172   }
    173 #endif
    174 }
    175 
    176 EventRewriter::DeviceType EventRewriter::DeviceAddedForTesting(
    177     int device_id,
    178     const std::string& device_name) {
    179   return DeviceAddedInternal(device_id, device_name);
    180 }
    181 
    182 // static
    183 EventRewriter::DeviceType EventRewriter::GetDeviceType(
    184     const std::string& device_name) {
    185   std::vector<std::string> tokens;
    186   Tokenize(device_name, " .", &tokens);
    187 
    188   // If the |device_name| contains the two words, "apple" and "keyboard", treat
    189   // it as an Apple keyboard.
    190   bool found_apple = false;
    191   bool found_keyboard = false;
    192   for (size_t i = 0; i < tokens.size(); ++i) {
    193     if (!found_apple && LowerCaseEqualsASCII(tokens[i], "apple"))
    194       found_apple = true;
    195     if (!found_keyboard && LowerCaseEqualsASCII(tokens[i], "keyboard"))
    196       found_keyboard = true;
    197     if (found_apple && found_keyboard)
    198       return kDeviceAppleKeyboard;
    199   }
    200 
    201   return kDeviceUnknown;
    202 }
    203 
    204 void EventRewriter::RewriteForTesting(ui::KeyEvent* event) {
    205   Rewrite(event);
    206 }
    207 
    208 ash::EventRewriterDelegate::Action EventRewriter::RewriteOrFilterKeyEvent(
    209     ui::KeyEvent* event) {
    210   if (event->HasNativeEvent())
    211     Rewrite(event);
    212   return ash::EventRewriterDelegate::ACTION_REWRITE_EVENT;
    213 }
    214 
    215 ash::EventRewriterDelegate::Action EventRewriter::RewriteOrFilterLocatedEvent(
    216     ui::LocatedEvent* event) {
    217   if (event->HasNativeEvent())
    218     RewriteLocatedEvent(event);
    219   return ash::EventRewriterDelegate::ACTION_REWRITE_EVENT;
    220 }
    221 
    222 void EventRewriter::OnKeyboardMappingChanged(const aura::RootWindow* root) {
    223 #if defined(OS_CHROMEOS)
    224   RefreshKeycodes();
    225 #endif
    226 }
    227 
    228 #if defined(OS_CHROMEOS)
    229 void EventRewriter::DeviceAdded(int device_id) {
    230   DCHECK_NE(XIAllDevices, device_id);
    231   DCHECK_NE(XIAllMasterDevices, device_id);
    232   if (device_id == XIAllDevices || device_id == XIAllMasterDevices) {
    233     LOG(ERROR) << "Unexpected device_id passed: " << device_id;
    234     return;
    235   }
    236 
    237   int ndevices_return = 0;
    238   XIDeviceInfo* device_info = XIQueryDevice(ui::GetXDisplay(),
    239                                             device_id,
    240                                             &ndevices_return);
    241 
    242   // Since |device_id| is neither XIAllDevices nor XIAllMasterDevices,
    243   // the number of devices found should be either 0 (not found) or 1.
    244   if (!device_info) {
    245     LOG(ERROR) << "XIQueryDevice: Device ID " << device_id << " is unknown.";
    246     return;
    247   }
    248 
    249   DCHECK_EQ(1, ndevices_return);
    250   for (int i = 0; i < ndevices_return; ++i) {
    251     DCHECK_EQ(device_id, device_info[i].deviceid);  // see the comment above.
    252     DCHECK(device_info[i].name);
    253     DeviceAddedInternal(device_info[i].deviceid, device_info[i].name);
    254   }
    255 
    256   XIFreeDeviceInfo(device_info);
    257 }
    258 
    259 void EventRewriter::DeviceRemoved(int device_id) {
    260   device_id_to_type_.erase(device_id);
    261 }
    262 
    263 void EventRewriter::DeviceKeyPressedOrReleased(int device_id) {
    264   std::map<int, DeviceType>::const_iterator iter =
    265       device_id_to_type_.find(device_id);
    266   if (iter == device_id_to_type_.end()) {
    267     // |device_id| is unknown. This means the device was connected before
    268     // booting the OS. Query the name of the device and add it to the map.
    269     DeviceAdded(device_id);
    270   }
    271 
    272   last_device_id_ = device_id;
    273 }
    274 
    275 void EventRewriter::RefreshKeycodes() {
    276   keysym_to_keycode_map_.clear();
    277 }
    278 
    279 KeyCode EventRewriter::NativeKeySymToNativeKeycode(KeySym keysym) {
    280   if (keysym_to_keycode_map_.count(keysym))
    281     return keysym_to_keycode_map_[keysym];
    282 
    283   Display* display = ui::GetXDisplay();
    284   KeyCode keycode = XKeysymToKeycode(display, keysym);
    285   keysym_to_keycode_map_[keysym] = keycode;
    286   return keycode;
    287 }
    288 
    289 bool EventRewriter::RewriteWithKeyboardRemappingsByKeySym(
    290     const KeyboardRemapping* remappings,
    291     size_t num_remappings,
    292     KeySym keysym,
    293     unsigned int native_mods,
    294     unsigned int mods,
    295     KeySym* remapped_native_keysym,
    296     unsigned int* remapped_native_mods,
    297     ui::KeyboardCode* remapped_keycode,
    298     unsigned int* remapped_mods) {
    299   for (size_t i = 0; i < num_remappings; ++i) {
    300     const KeyboardRemapping& map = remappings[i];
    301 
    302     if (keysym != map.input_keysym)
    303       continue;
    304     unsigned int matched_mods = native_mods & map.input_native_mods;
    305     if (matched_mods != map.input_native_mods)
    306       continue;
    307 
    308     *remapped_native_keysym = map.output_keysym;
    309     *remapped_keycode = map.output_keycode;
    310     *remapped_native_mods = (native_mods & ~map.input_native_mods) |
    311                             map.output_native_mods;
    312     *remapped_mods = (mods & ~map.input_mods) | map.output_mods;
    313     return true;
    314   }
    315 
    316   return false;
    317 }
    318 
    319 bool EventRewriter::RewriteWithKeyboardRemappingsByKeyCode(
    320     const KeyboardRemapping* remappings,
    321     size_t num_remappings,
    322     KeyCode keycode,
    323     unsigned int native_mods,
    324     unsigned int mods,
    325     KeySym* remapped_native_keysym,
    326     unsigned int* remapped_native_mods,
    327     ui::KeyboardCode* remapped_keycode,
    328     unsigned int* remapped_mods) {
    329   for (size_t i = 0; i < num_remappings; ++i) {
    330     const KeyboardRemapping& map = remappings[i];
    331 
    332     KeyCode input_keycode = NativeKeySymToNativeKeycode(map.input_keysym);
    333     if (keycode != input_keycode)
    334       continue;
    335     unsigned int matched_mods = native_mods & map.input_native_mods;
    336     if (matched_mods != map.input_native_mods)
    337       continue;
    338 
    339     *remapped_native_keysym = map.output_keysym;
    340     *remapped_keycode = map.output_keycode;
    341     *remapped_native_mods = (native_mods & ~map.input_native_mods) |
    342                             map.output_native_mods;
    343     *remapped_mods = (mods & ~map.input_mods) | map.output_mods;
    344     return true;
    345   }
    346 
    347   return false;
    348 }
    349 #endif
    350 
    351 void EventRewriter::Rewrite(ui::KeyEvent* event) {
    352 #if defined(OS_CHROMEOS)
    353   // Do not rewrite an event sent by ui_controls::SendKeyPress(). See
    354   // crbug.com/136465.
    355   if (event->native_event()->xkey.send_event)
    356     return;
    357 
    358   // Keyboard driven rewriting needs to happen before RewriteExtendedKeys
    359   // to handle Ctrl+Alt+Shift+(Up | Down) so that they are not translated
    360   // to Home/End.
    361   keyboard_driven_event_rewritter_->RewriteIfKeyboardDrivenOnLoginScreen(event);
    362 #endif
    363   RewriteModifiers(event);
    364   RewriteNumPadKeys(event);
    365   RewriteExtendedKeys(event);
    366   RewriteFunctionKeys(event);
    367 }
    368 
    369 bool EventRewriter::IsAppleKeyboard() const {
    370   if (last_device_id_ == kBadDeviceId)
    371     return false;
    372 
    373   // Check which device generated |event|.
    374   std::map<int, DeviceType>::const_iterator iter =
    375       device_id_to_type_.find(last_device_id_);
    376   if (iter == device_id_to_type_.end()) {
    377     LOG(ERROR) << "Device ID " << last_device_id_ << " is unknown.";
    378     return false;
    379   }
    380 
    381   const DeviceType type = iter->second;
    382   return type == kDeviceAppleKeyboard;
    383 }
    384 
    385 void EventRewriter::GetRemappedModifierMasks(
    386     int original_flags,
    387     unsigned int original_native_modifiers,
    388     int* remapped_flags,
    389     unsigned int* remapped_native_modifiers) const {
    390 #if defined(OS_CHROMEOS)
    391   // TODO(glotov): remove the following condition when we do not restart chrome
    392   // when user logs in as guest. See Rewrite() for details.
    393   if (chromeos::UserManager::Get()->IsLoggedInAsGuest() &&
    394       chromeos::LoginDisplayHostImpl::default_host()) {
    395     return;
    396   }
    397 
    398   const PrefService* pref_service =
    399       pref_service_ ? pref_service_ : GetPrefService();
    400   if (!pref_service)
    401     return;
    402 
    403   // When a diamond key is not available, a Mod2Mask should not treated as a
    404   // configurable modifier because Mod2Mask may be worked as NumLock mask.
    405   // (cf. http://crbug.com/173956)
    406   const bool skip_mod2 = !HasDiamondKey();
    407   // If Mod3 is used by the current input method, don't allow the CapsLock
    408   // pref to remap it, or the keyboard behavior will be broken.
    409   const bool skip_mod3 = IsMod3UsedByCurrentInputMethod();
    410 
    411   for (size_t i = 0; i < arraysize(kModifierFlagToPrefName); ++i) {
    412     if ((skip_mod2 && kModifierFlagToPrefName[i].native_modifier == Mod2Mask) ||
    413         (skip_mod3 && kModifierFlagToPrefName[i].native_modifier == Mod3Mask)) {
    414       continue;
    415     }
    416     if (original_native_modifiers &
    417         kModifierFlagToPrefName[i].native_modifier) {
    418       const ModifierRemapping* remapped_key =
    419           GetRemappedKey(kModifierFlagToPrefName[i].pref_name, *pref_service);
    420       // Rewrite Command-L/R key presses on an Apple keyboard to Control-L/R.
    421       if (IsAppleKeyboard() &&
    422           (kModifierFlagToPrefName[i].native_modifier == Mod4Mask)) {
    423         remapped_key = kModifierRemappingCtrl;
    424       }
    425       if (remapped_key) {
    426         *remapped_flags |= remapped_key->flag;
    427         *remapped_native_modifiers |= remapped_key->native_modifier;
    428       } else {
    429         *remapped_flags |= kModifierFlagToPrefName[i].flag;
    430         *remapped_native_modifiers |=
    431             kModifierFlagToPrefName[i].native_modifier;
    432       }
    433     }
    434   }
    435 
    436   *remapped_flags =
    437       (original_flags & ~(ui::EF_CONTROL_DOWN | ui::EF_ALT_DOWN)) |
    438       *remapped_flags;
    439 
    440   unsigned int native_mask = Mod4Mask | ControlMask | Mod1Mask;
    441   if (!skip_mod2)
    442     native_mask |= Mod2Mask;
    443   if (!skip_mod3)
    444     native_mask |= Mod3Mask;
    445   *remapped_native_modifiers =
    446       (original_native_modifiers & ~native_mask) |
    447       *remapped_native_modifiers;
    448 #endif
    449 }
    450 
    451 bool EventRewriter::RewriteModifiers(ui::KeyEvent* event) {
    452   // Do nothing if we have just logged in as guest but have not restarted chrome
    453   // process yet (so we are still on the login screen). In this situations we
    454   // have no user profile so can not do anything useful.
    455   // Note that currently, unlike other accounts, when user logs in as guest, we
    456   // restart chrome process. In future this is to be changed.
    457   // TODO(glotov): remove the following condition when we do not restart chrome
    458   // when user logs in as guest.
    459 #if defined(OS_CHROMEOS)
    460   if (chromeos::UserManager::Get()->IsLoggedInAsGuest() &&
    461       chromeos::LoginDisplayHostImpl::default_host())
    462     return false;
    463 #endif  // defined(OS_CHROMEOS)
    464   const PrefService* pref_service =
    465       pref_service_ ? pref_service_ : GetPrefService();
    466   if (!pref_service)
    467     return false;
    468 
    469 #if defined(OS_CHROMEOS)
    470   DCHECK_EQ(chromeos::input_method::kControlKey,
    471             kModifierRemappingCtrl->remap_to);
    472 
    473   XEvent* xev = event->native_event();
    474   XKeyEvent* xkey = &(xev->xkey);
    475   KeySym keysym = XLookupKeysym(xkey, 0);
    476 
    477   ui::KeyboardCode remapped_keycode = event->key_code();
    478   KeyCode remapped_native_keycode = xkey->keycode;
    479 
    480   // First, remap |keysym|.
    481   const ModifierRemapping* remapped_key = NULL;
    482   switch (keysym) {
    483     // On Chrome OS, XF86XK_Launch6 (F15) with Mod2Mask is sent when Diamond
    484     // key is pressed.
    485     case XF86XK_Launch6:
    486       // When diamond key is not available, the configuration UI for Diamond
    487       // key is not shown. Therefore, ignore the kLanguageRemapDiamondKeyTo
    488       // syncable pref.
    489       if (HasDiamondKey())
    490         remapped_key =
    491             GetRemappedKey(prefs::kLanguageRemapDiamondKeyTo, *pref_service);
    492       // Default behavior is Ctrl key.
    493       if (!remapped_key)
    494         remapped_key = kModifierRemappingCtrl;
    495       break;
    496     // On Chrome OS, XF86XK_Launch7 (F16) with Mod3Mask is sent when Caps Lock
    497     // is pressed (with one exception: when IsMod3UsedByCurrentInputMethod() is
    498     // true, the key generates XK_ISO_Level3_Shift with Mod3Mask, not
    499     // XF86XK_Launch7).
    500     case XF86XK_Launch7:
    501       remapped_key =
    502           GetRemappedKey(prefs::kLanguageRemapCapsLockKeyTo, *pref_service);
    503       break;
    504     case XK_Super_L:
    505     case XK_Super_R:
    506       // Rewrite Command-L/R key presses on an Apple keyboard to Control-L/R.
    507       if (IsAppleKeyboard())
    508         remapped_key = kModifierRemappingCtrl;
    509       else
    510         remapped_key =
    511             GetRemappedKey(prefs::kLanguageRemapSearchKeyTo, *pref_service);
    512       // Default behavior is Super key, hence don't remap the event if the pref
    513       // is unavailable.
    514       break;
    515     case XK_Control_L:
    516     case XK_Control_R:
    517       remapped_key =
    518           GetRemappedKey(prefs::kLanguageRemapControlKeyTo, *pref_service);
    519       break;
    520     case XK_Alt_L:
    521     case XK_Alt_R:
    522     case XK_Meta_L:
    523     case XK_Meta_R:
    524       remapped_key =
    525           GetRemappedKey(prefs::kLanguageRemapAltKeyTo, *pref_service);
    526       break;
    527     default:
    528       break;
    529   }
    530 
    531   if (remapped_key) {
    532     remapped_keycode = remapped_key->keycode;
    533     const size_t level = (event->IsShiftDown() ? (1 << 1) : 0) +
    534         (IsRight(keysym) ? (1 << 0) : 0);
    535     const KeySym native_keysym = remapped_key->native_keysyms[level];
    536     remapped_native_keycode = NativeKeySymToNativeKeycode(native_keysym);
    537   }
    538 
    539   // Next, remap modifier bits.
    540   int remapped_flags = 0;
    541   unsigned int remapped_native_modifiers = 0U;
    542   GetRemappedModifierMasks(event->flags(), xkey->state,
    543                            &remapped_flags, &remapped_native_modifiers);
    544 
    545   // Toggle Caps Lock if the remapped key is ui::VKEY_CAPITAL, but do nothing if
    546   // the original key is ui::VKEY_CAPITAL (i.e. a Caps Lock key on an external
    547   // keyboard is pressed) since X can handle that case.
    548   if ((event->type() == ui::ET_KEY_PRESSED) &&
    549       (event->key_code() != ui::VKEY_CAPITAL) &&
    550       (remapped_keycode == ui::VKEY_CAPITAL)) {
    551     chromeos::input_method::XKeyboard* xkeyboard = xkeyboard_ ?
    552         xkeyboard_ :
    553         chromeos::input_method::InputMethodManager::Get()->GetXKeyboard();
    554     xkeyboard->SetCapsLockEnabled(!xkeyboard->CapsLockIsEnabled());
    555   }
    556 
    557   OverwriteEvent(event,
    558                  remapped_native_keycode, remapped_native_modifiers,
    559                  remapped_keycode, remapped_flags);
    560   return true;
    561 #else
    562   // TODO(yusukes): Support Ash on other platforms if needed.
    563   return false;
    564 #endif
    565 }
    566 
    567 bool EventRewriter::RewriteNumPadKeys(ui::KeyEvent* event) {
    568   bool rewritten = false;
    569 #if defined(OS_CHROMEOS)
    570   XEvent* xev = event->native_event();
    571   XKeyEvent* xkey = &(xev->xkey);
    572 
    573   const KeySym keysym = XLookupKeysym(xkey, 0);
    574   switch (keysym) {
    575     case XK_KP_Insert:
    576       OverwriteEvent(event, NativeKeySymToNativeKeycode(XK_KP_0),
    577                      xkey->state | Mod2Mask,
    578                      ui::VKEY_NUMPAD0, event->flags());
    579       rewritten = true;
    580       break;
    581     case XK_KP_Delete:
    582       OverwriteEvent(event, NativeKeySymToNativeKeycode(XK_KP_Decimal),
    583                      xkey->state | Mod2Mask,
    584                      ui::VKEY_DECIMAL, event->flags());
    585       rewritten = true;
    586       break;
    587     case XK_KP_End:
    588       OverwriteEvent(event, NativeKeySymToNativeKeycode(XK_KP_1),
    589                      xkey->state | Mod2Mask,
    590                      ui::VKEY_NUMPAD1, event->flags());
    591       rewritten = true;
    592       break;
    593     case XK_KP_Down:
    594       OverwriteEvent(event, NativeKeySymToNativeKeycode(XK_KP_2),
    595                      xkey->state | Mod2Mask,
    596                      ui::VKEY_NUMPAD2, event->flags());
    597       rewritten = true;
    598       break;
    599     case XK_KP_Next:
    600       OverwriteEvent(event, NativeKeySymToNativeKeycode(XK_KP_3),
    601                      xkey->state | Mod2Mask,
    602                      ui::VKEY_NUMPAD3, event->flags());
    603       rewritten = true;
    604       break;
    605     case XK_KP_Left:
    606       OverwriteEvent(event, NativeKeySymToNativeKeycode(XK_KP_4),
    607                      xkey->state | Mod2Mask,
    608                      ui::VKEY_NUMPAD4, event->flags());
    609       rewritten = true;
    610       break;
    611     case XK_KP_Begin:
    612       OverwriteEvent(event, NativeKeySymToNativeKeycode(XK_KP_5),
    613                      xkey->state | Mod2Mask,
    614                      ui::VKEY_NUMPAD5, event->flags());
    615       rewritten = true;
    616       break;
    617     case XK_KP_Right:
    618       OverwriteEvent(event, NativeKeySymToNativeKeycode(XK_KP_6),
    619                      xkey->state | Mod2Mask,
    620                      ui::VKEY_NUMPAD6, event->flags());
    621       rewritten = true;
    622       break;
    623     case XK_KP_Home:
    624       OverwriteEvent(event, NativeKeySymToNativeKeycode(XK_KP_7),
    625                      xkey->state | Mod2Mask,
    626                      ui::VKEY_NUMPAD7, event->flags());
    627       rewritten = true;
    628       break;
    629     case XK_KP_Up:
    630       OverwriteEvent(event, NativeKeySymToNativeKeycode(XK_KP_8),
    631                      xkey->state | Mod2Mask,
    632                      ui::VKEY_NUMPAD8, event->flags());
    633       rewritten = true;
    634       break;
    635     case XK_KP_Prior:
    636       OverwriteEvent(event, NativeKeySymToNativeKeycode(XK_KP_9),
    637                      xkey->state | Mod2Mask,
    638                      ui::VKEY_NUMPAD9, event->flags());
    639       rewritten = true;
    640       break;
    641     case XK_KP_Divide:
    642     case XK_KP_Multiply:
    643     case XK_KP_Subtract:
    644     case XK_KP_Add:
    645     case XK_KP_Enter:
    646       // Add Mod2Mask for consistency.
    647       OverwriteEvent(event, xkey->keycode, xkey->state | Mod2Mask,
    648                      event->key_code(), event->flags());
    649       rewritten = true;
    650       break;
    651     default:
    652       break;
    653   }
    654 #else
    655   // TODO(yusukes): Support Ash on other platforms if needed.
    656 #endif
    657   return rewritten;
    658 }
    659 
    660 bool EventRewriter::RewriteExtendedKeys(ui::KeyEvent* event) {
    661 #if defined(OS_CHROMEOS)
    662   XEvent* xev = event->native_event();
    663   XKeyEvent* xkey = &(xev->xkey);
    664   const KeySym keysym = XLookupKeysym(xkey, 0);
    665 
    666   KeySym remapped_native_keysym = 0;
    667   unsigned int remapped_native_mods = 0;
    668   ui::KeyboardCode remapped_keycode = ui::VKEY_UNKNOWN;
    669   unsigned int remapped_mods = 0;
    670 
    671   if (xkey->state & Mod4Mask) {
    672     // Allow Search to avoid rewriting extended keys.
    673     static const KeyboardRemapping kAvoidRemappings[] = {
    674       { // Alt+Backspace
    675         XK_BackSpace,
    676         ui::EF_ALT_DOWN, Mod1Mask | Mod4Mask,
    677         XK_BackSpace, ui::VKEY_BACK,
    678         ui::EF_ALT_DOWN, Mod1Mask,
    679       },
    680       { // Control+Alt+Up
    681         XK_Up,
    682         ui::EF_ALT_DOWN | ui::EF_CONTROL_DOWN,
    683         Mod1Mask | ControlMask | Mod4Mask,
    684         XK_Up, ui::VKEY_UP,
    685         ui::EF_ALT_DOWN | ui::EF_CONTROL_DOWN, Mod1Mask | ControlMask,
    686       },
    687       { // Alt+Up
    688         XK_Up,
    689         ui::EF_ALT_DOWN, Mod1Mask | Mod4Mask,
    690         XK_Up, ui::VKEY_UP,
    691         ui::EF_ALT_DOWN, Mod1Mask,
    692       },
    693       { // Control+Alt+Down
    694         XK_Down,
    695         ui::EF_ALT_DOWN | ui::EF_CONTROL_DOWN,
    696         Mod1Mask | ControlMask | Mod4Mask,
    697         XK_Down, ui::VKEY_DOWN,
    698         ui::EF_ALT_DOWN | ui::EF_CONTROL_DOWN, Mod1Mask | ControlMask,
    699       },
    700       { // Alt+Down
    701         XK_Down,
    702         ui::EF_ALT_DOWN, Mod1Mask | Mod4Mask,
    703         XK_Down, ui::VKEY_DOWN,
    704         ui::EF_ALT_DOWN, Mod1Mask,
    705       }
    706     };
    707 
    708     RewriteWithKeyboardRemappingsByKeySym(kAvoidRemappings,
    709                                           arraysize(kAvoidRemappings),
    710                                           keysym,
    711                                           xkey->state,
    712                                           event->flags(),
    713                                           &remapped_native_keysym,
    714                                           &remapped_native_mods,
    715                                           &remapped_keycode,
    716                                           &remapped_mods);
    717   }
    718 
    719   if (remapped_keycode == ui::VKEY_UNKNOWN) {
    720     static const KeyboardRemapping kSearchRemappings[] = {
    721       { // Search+BackSpace -> Delete
    722         XK_BackSpace,
    723         0, Mod4Mask,
    724         XK_Delete, ui::VKEY_DELETE,
    725         0, 0
    726       },
    727       { // Search+Left -> Home
    728         XK_Left,
    729         0, Mod4Mask,
    730         XK_Home, ui::VKEY_HOME,
    731         0, 0
    732       },
    733       { // Search+Up -> Prior (aka PageUp)
    734         XK_Up,
    735         0, Mod4Mask,
    736         XK_Prior, ui::VKEY_PRIOR,
    737         0, 0
    738       },
    739       { // Search+Right -> End
    740         XK_Right,
    741         0, Mod4Mask,
    742         XK_End, ui::VKEY_END,
    743         0, 0
    744       },
    745       { // Search+Down -> Next (aka PageDown)
    746         XK_Down,
    747         0, Mod4Mask,
    748         XK_Next, ui::VKEY_NEXT,
    749         0, 0
    750       },
    751       { // Search+Period -> Insert
    752         XK_period,
    753         0, Mod4Mask,
    754         XK_Insert, ui::VKEY_INSERT,
    755         0, 0
    756       }
    757     };
    758 
    759     RewriteWithKeyboardRemappingsByKeySym(kSearchRemappings,
    760                                           arraysize(kSearchRemappings),
    761                                           keysym,
    762                                           xkey->state,
    763                                           event->flags(),
    764                                           &remapped_native_keysym,
    765                                           &remapped_native_mods,
    766                                           &remapped_keycode,
    767                                           &remapped_mods);
    768   }
    769 
    770   if (remapped_keycode == ui::VKEY_UNKNOWN) {
    771     static const KeyboardRemapping kNonSearchRemappings[] = {
    772       { // Alt+BackSpace -> Delete
    773         XK_BackSpace,
    774         ui::EF_ALT_DOWN, Mod1Mask,
    775         XK_Delete, ui::VKEY_DELETE,
    776         0, 0
    777       },
    778       { // Control+Alt+Up -> Home
    779         XK_Up,
    780         ui::EF_ALT_DOWN | ui::EF_CONTROL_DOWN, Mod1Mask | ControlMask,
    781         XK_Home, ui::VKEY_HOME,
    782         0, 0
    783       },
    784       { // Alt+Up -> Prior (aka PageUp)
    785         XK_Up,
    786         ui::EF_ALT_DOWN, Mod1Mask,
    787         XK_Prior, ui::VKEY_PRIOR,
    788         0, 0
    789       },
    790       { // Control+Alt+Down -> End
    791         XK_Down,
    792         ui::EF_ALT_DOWN | ui::EF_CONTROL_DOWN, Mod1Mask | ControlMask,
    793         XK_End, ui::VKEY_END,
    794         0, 0
    795       },
    796       { // Alt+Down -> Next (aka PageDown)
    797         XK_Down,
    798         ui::EF_ALT_DOWN, Mod1Mask,
    799         XK_Next, ui::VKEY_NEXT,
    800         0, 0
    801       }
    802     };
    803 
    804     RewriteWithKeyboardRemappingsByKeySym(kNonSearchRemappings,
    805                                           arraysize(kNonSearchRemappings),
    806                                           keysym,
    807                                           xkey->state,
    808                                           event->flags(),
    809                                           &remapped_native_keysym,
    810                                           &remapped_native_mods,
    811                                           &remapped_keycode,
    812                                           &remapped_mods);
    813   }
    814 
    815   if (remapped_keycode == ui::VKEY_UNKNOWN)
    816     return false;
    817 
    818   OverwriteEvent(event,
    819                  NativeKeySymToNativeKeycode(remapped_native_keysym),
    820                  remapped_native_mods,
    821                  remapped_keycode,
    822                  remapped_mods);
    823   return true;
    824 #else
    825   // TODO(yusukes): Support Ash on other platforms if needed.
    826   return false;
    827 #endif
    828 }
    829 
    830 bool EventRewriter::RewriteFunctionKeys(ui::KeyEvent* event) {
    831 #if defined(OS_CHROMEOS)
    832   XEvent* xev = event->native_event();
    833   XKeyEvent* xkey = &(xev->xkey);
    834   const KeySym keysym = XLookupKeysym(xkey, 0);
    835 
    836   KeySym remapped_native_keysym = 0;
    837   unsigned int remapped_native_mods = 0;
    838   ui::KeyboardCode remapped_keycode = ui::VKEY_UNKNOWN;
    839   unsigned int remapped_mods = 0;
    840 
    841   if (xkey->state & Mod4Mask) {
    842     // Allow Search to avoid rewriting F1-F12.
    843     static const KeyboardRemapping kFkeysToFkeys[] = {
    844       { XK_F1, 0, Mod4Mask, XK_F1, ui::VKEY_F1, },
    845       { XK_F2, 0, Mod4Mask, XK_F2, ui::VKEY_F2, },
    846       { XK_F3, 0, Mod4Mask, XK_F3, ui::VKEY_F3, },
    847       { XK_F4, 0, Mod4Mask, XK_F4, ui::VKEY_F4, },
    848       { XK_F5, 0, Mod4Mask, XK_F5, ui::VKEY_F5, },
    849       { XK_F6, 0, Mod4Mask, XK_F6, ui::VKEY_F6, },
    850       { XK_F7, 0, Mod4Mask, XK_F7, ui::VKEY_F7, },
    851       { XK_F8, 0, Mod4Mask, XK_F8, ui::VKEY_F8, },
    852       { XK_F9, 0, Mod4Mask, XK_F9, ui::VKEY_F9, },
    853       { XK_F10, 0, Mod4Mask, XK_F10, ui::VKEY_F10, },
    854       { XK_F11, 0, Mod4Mask, XK_F11, ui::VKEY_F11, },
    855       { XK_F12, 0, Mod4Mask, XK_F12, ui::VKEY_F12, },
    856     };
    857 
    858     RewriteWithKeyboardRemappingsByKeySym(kFkeysToFkeys,
    859                                           arraysize(kFkeysToFkeys),
    860                                           keysym,
    861                                           xkey->state,
    862                                           event->flags(),
    863                                           &remapped_native_keysym,
    864                                           &remapped_native_mods,
    865                                           &remapped_keycode,
    866                                           &remapped_mods);
    867   }
    868 
    869   if (remapped_keycode == ui::VKEY_UNKNOWN) {
    870     // Rewrite the actual F1-F12 keys on a Chromebook keyboard to special keys.
    871     static const KeyboardRemapping kFkeysToSpecialKeys[] = {
    872       { XK_F1, 0, 0, XF86XK_Back, ui::VKEY_BROWSER_BACK, 0, 0 },
    873       { XK_F2, 0, 0, XF86XK_Forward, ui::VKEY_BROWSER_FORWARD, 0, 0 },
    874       { XK_F3, 0, 0, XF86XK_Reload, ui::VKEY_BROWSER_REFRESH, 0, 0 },
    875       { XK_F4, 0, 0, XF86XK_LaunchB, ui::VKEY_MEDIA_LAUNCH_APP2, 0, 0 },
    876       { XK_F5, 0, 0, XF86XK_LaunchA, ui::VKEY_MEDIA_LAUNCH_APP1, 0, 0 },
    877       { XK_F6, 0, 0, XF86XK_MonBrightnessDown, ui::VKEY_BRIGHTNESS_DOWN, 0, 0 },
    878       { XK_F7, 0, 0, XF86XK_MonBrightnessUp, ui::VKEY_BRIGHTNESS_UP, 0, 0 },
    879       { XK_F8, 0, 0, XF86XK_AudioMute, ui::VKEY_VOLUME_MUTE, 0, 0 },
    880       { XK_F9, 0, 0, XF86XK_AudioLowerVolume, ui::VKEY_VOLUME_DOWN, 0, 0 },
    881       { XK_F10, 0, 0, XF86XK_AudioRaiseVolume, ui::VKEY_VOLUME_UP, 0, 0 },
    882     };
    883 
    884     RewriteWithKeyboardRemappingsByKeySym(kFkeysToSpecialKeys,
    885                                           arraysize(kFkeysToSpecialKeys),
    886                                           keysym,
    887                                           xkey->state,
    888                                           event->flags(),
    889                                           &remapped_native_keysym,
    890                                           &remapped_native_mods,
    891                                           &remapped_keycode,
    892                                           &remapped_mods);
    893   }
    894 
    895   if (remapped_keycode == ui::VKEY_UNKNOWN && xkey->state & Mod4Mask) {
    896     // Remap Search+<number> to F<number>.
    897     // We check the keycode here instead of the keysym, as these keys have
    898     // different keysyms when modifiers are pressed, such as shift.
    899 
    900     // TODO(danakj): On some i18n keyboards, these choices will be bad and we
    901     // should make layout-specific choices here. For eg. on a french keyboard
    902     // "-" and "6" are the same key, so F11 will not be accessible.
    903     static const KeyboardRemapping kNumberKeysToFkeys[] = {
    904       { XK_1, 0, Mod4Mask, XK_F1, ui::VKEY_F1, 0, 0 },
    905       { XK_2, 0, Mod4Mask, XK_F2, ui::VKEY_F2, 0, 0 },
    906       { XK_3, 0, Mod4Mask, XK_F3, ui::VKEY_F3, 0, 0 },
    907       { XK_4, 0, Mod4Mask, XK_F4, ui::VKEY_F4, 0, 0 },
    908       { XK_5, 0, Mod4Mask, XK_F5, ui::VKEY_F5, 0, 0 },
    909       { XK_6, 0, Mod4Mask, XK_F6, ui::VKEY_F6, 0, 0 },
    910       { XK_7, 0, Mod4Mask, XK_F7, ui::VKEY_F7, 0, 0 },
    911       { XK_8, 0, Mod4Mask, XK_F8, ui::VKEY_F8, 0, 0 },
    912       { XK_9, 0, Mod4Mask, XK_F9, ui::VKEY_F9, 0, 0 },
    913       { XK_0, 0, Mod4Mask, XK_F10, ui::VKEY_F10, 0, 0 },
    914       { XK_minus, 0, Mod4Mask, XK_F11, ui::VKEY_F11, 0, 0 },
    915       { XK_equal, 0, Mod4Mask, XK_F12, ui::VKEY_F12, 0, 0 }
    916     };
    917 
    918     RewriteWithKeyboardRemappingsByKeyCode(kNumberKeysToFkeys,
    919                                            arraysize(kNumberKeysToFkeys),
    920                                            xkey->keycode,
    921                                            xkey->state,
    922                                            event->flags(),
    923                                            &remapped_native_keysym,
    924                                            &remapped_native_mods,
    925                                            &remapped_keycode,
    926                                            &remapped_mods);
    927   }
    928 
    929   if (remapped_keycode == ui::VKEY_UNKNOWN)
    930     return false;
    931 
    932   OverwriteEvent(event,
    933                  NativeKeySymToNativeKeycode(remapped_native_keysym),
    934                  remapped_native_mods,
    935                  remapped_keycode,
    936                  remapped_mods);
    937   return true;
    938 #else
    939   // TODO(danakj): Support Ash on other platforms if needed.
    940   return false;
    941 #endif
    942 }
    943 
    944 void EventRewriter::RewriteLocatedEvent(ui::LocatedEvent* event) {
    945 #if defined(OS_CHROMEOS)
    946   if (event->flags() & ui::EF_IS_SYNTHESIZED)
    947     return;
    948 
    949   XEvent* xevent = event->native_event();
    950   if (!xevent || xevent->type != GenericEvent)
    951     return;
    952 
    953   XIDeviceEvent* xievent = static_cast<XIDeviceEvent*>(xevent->xcookie.data);
    954   if (xievent->evtype != XI_ButtonPress && xievent->evtype != XI_ButtonRelease)
    955     return;
    956 
    957   // First, remap modifier masks.
    958   int remapped_flags = 0;
    959   unsigned int remapped_native_modifiers = 0U;
    960   GetRemappedModifierMasks(event->flags(), xievent->mods.effective,
    961                            &remapped_flags, &remapped_native_modifiers);
    962   xievent->mods.effective = remapped_native_modifiers;
    963 
    964   // Then, remap Alt+Button1 to Button3.
    965   if ((xievent->mods.effective & Mod1Mask) && xievent->detail == 1) {
    966     xievent->mods.effective &= ~Mod1Mask;
    967     xievent->detail = 3;
    968     if (xievent->evtype == XI_ButtonRelease) {
    969       // On the release clear the left button from the existing state and the
    970       // mods, and set the right button.
    971       XISetMask(xievent->buttons.mask, 3);
    972       XIClearMask(xievent->buttons.mask, 1);
    973       xievent->mods.effective &= ~Button1Mask;
    974     }
    975   }
    976 
    977   const int mouse_event_flags = event->flags() &
    978       (ui::EF_IS_DOUBLE_CLICK | ui::EF_IS_TRIPLE_CLICK | ui::EF_IS_NON_CLIENT |
    979        ui::EF_IS_SYNTHESIZED | ui::EF_FROM_TOUCH);
    980   event->set_flags(mouse_event_flags | ui::EventFlagsFromNative(xevent));
    981 #else
    982   // TODO(yusukes): Support Ash on other platforms if needed.
    983 #endif
    984 }
    985 
    986 void EventRewriter::OverwriteEvent(ui::KeyEvent* event,
    987                                    unsigned int new_native_keycode,
    988                                    unsigned int new_native_state,
    989                                    ui::KeyboardCode new_keycode,
    990                                    int new_flags) {
    991 #if defined(OS_CHROMEOS)
    992   XEvent* xev = event->native_event();
    993   XKeyEvent* xkey = &(xev->xkey);
    994   xkey->keycode = new_native_keycode;
    995   xkey->state = new_native_state;
    996   event->set_key_code(new_keycode);
    997   event->set_character(ui::GetCharacterFromKeyCode(event->key_code(),
    998                                                    new_flags));
    999   event->set_flags(new_flags);
   1000   event->NormalizeFlags();
   1001 #else
   1002   // TODO(yusukes): Support Ash on other platforms if needed.
   1003 #endif
   1004 }
   1005 
   1006 EventRewriter::DeviceType EventRewriter::DeviceAddedInternal(
   1007     int device_id,
   1008     const std::string& device_name) {
   1009   const DeviceType type = EventRewriter::GetDeviceType(device_name);
   1010   if (type == kDeviceAppleKeyboard) {
   1011     VLOG(1) << "Apple keyboard '" << device_name << "' connected: "
   1012             << "id=" << device_id;
   1013   }
   1014   // Always overwrite the existing device_id since the X server may reuse a
   1015   // device id for an unattached device.
   1016   device_id_to_type_[device_id] = type;
   1017   return type;
   1018 }
   1019