| 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 42b1b8e6d928b410dc41ab1c72bb1c6bf1488542..7ac9fe8ea3fb35df7acdcf712dad59196af015e6 100644
 | 
| --- a/chrome/browser/ui/ash/event_rewriter.cc
 | 
| +++ b/chrome/browser/ui/ash/event_rewriter.cc
 | 
| @@ -121,12 +121,6 @@ bool HasChromeOSKeyboard() {
 | 
|        switches::kHasChromeOSKeyboard);
 | 
|  }
 | 
|  
 | 
| -bool EventSourceIsChromebookKeyboard(ui::KeyEvent* /* event */) {
 | 
| -  // TODO(danakj): Determine if the event came from a Chromebook internal
 | 
| -  // keyboard.
 | 
| -  return true;
 | 
| -}
 | 
| -
 | 
|  bool IsMod3UsedByCurrentInputMethod() {
 | 
|    // Since both German Neo2 XKB layout and Caps Lock depend on Mod3Mask,
 | 
|    // it's not possible to make both features work. For now, we don't remap
 | 
| @@ -149,6 +143,7 @@ const PrefService* GetPrefService() {
 | 
|  EventRewriter::EventRewriter()
 | 
|      : last_device_id_(kBadDeviceId),
 | 
|  #if defined(OS_CHROMEOS)
 | 
| +      force_chromeos_keyboard_for_testing_(false),
 | 
|        xkeyboard_(NULL),
 | 
|  #endif
 | 
|        pref_service_(NULL) {
 | 
| @@ -200,6 +195,17 @@ EventRewriter::DeviceType EventRewriter::GetDeviceType(
 | 
|        return kDeviceAppleKeyboard;
 | 
|    }
 | 
|  
 | 
| +#if defined(OS_CHROMEOS)
 | 
| +  if (HasChromeOSKeyboard()) {
 | 
| +    // The chromebook internal keyboard's name.
 | 
| +    if (LowerCaseEqualsASCII(device_name, "at translated set 2 keyboard"))
 | 
| +      return kDeviceChromeOSKeyboard;
 | 
| +    // The chromebox chrome-specific keyboard's name.
 | 
| +    if (LowerCaseEqualsASCII(device_name, "samsung usb keyboard"))
 | 
| +      return kDeviceChromeOSKeyboard;
 | 
| +  }
 | 
| +#endif
 | 
| +
 | 
|    return kDeviceUnknown;
 | 
|  }
 | 
|  
 | 
| @@ -275,90 +281,95 @@ void EventRewriter::DeviceKeyPressedOrReleased(int device_id) {
 | 
|  }
 | 
|  
 | 
|  void EventRewriter::RefreshKeycodes() {
 | 
| -  Display* display = ui::GetXDisplay();
 | 
| -  control_l_xkeycode_ = XKeysymToKeycode(display, XK_Control_L);
 | 
| -  control_r_xkeycode_ = XKeysymToKeycode(display, XK_Control_R);
 | 
| -  alt_l_xkeycode_ = XKeysymToKeycode(display, XK_Alt_L);
 | 
| -  alt_r_xkeycode_ = XKeysymToKeycode(display, XK_Alt_R);
 | 
| -  meta_l_xkeycode_ = XKeysymToKeycode(display, XK_Meta_L);
 | 
| -  meta_r_xkeycode_ = XKeysymToKeycode(display, XK_Meta_R);
 | 
| -  windows_l_xkeycode_ = XKeysymToKeycode(display, XK_Super_L);
 | 
| -  caps_lock_xkeycode_ = XKeysymToKeycode(display, XK_Caps_Lock);
 | 
| -  void_symbol_xkeycode_ = XKeysymToKeycode(display, XK_VoidSymbol);
 | 
| -  delete_xkeycode_ = XKeysymToKeycode(display, XK_Delete);
 | 
| -  home_xkeycode_ = XKeysymToKeycode(display, XK_Home);
 | 
| -  end_xkeycode_ = XKeysymToKeycode(display, XK_End);
 | 
| -  prior_xkeycode_ = XKeysymToKeycode(display, XK_Prior);
 | 
| -  next_xkeycode_ = XKeysymToKeycode(display, XK_Next);
 | 
| -  kp_0_xkeycode_ = XKeysymToKeycode(display, XK_KP_0);
 | 
| -  kp_1_xkeycode_ = XKeysymToKeycode(display, XK_KP_1);
 | 
| -  kp_2_xkeycode_ = XKeysymToKeycode(display, XK_KP_2);
 | 
| -  kp_3_xkeycode_ = XKeysymToKeycode(display, XK_KP_3);
 | 
| -  kp_4_xkeycode_ = XKeysymToKeycode(display, XK_KP_4);
 | 
| -  kp_5_xkeycode_ = XKeysymToKeycode(display, XK_KP_5);
 | 
| -  kp_6_xkeycode_ = XKeysymToKeycode(display, XK_KP_6);
 | 
| -  kp_7_xkeycode_ = XKeysymToKeycode(display, XK_KP_7);
 | 
| -  kp_8_xkeycode_ = XKeysymToKeycode(display, XK_KP_8);
 | 
| -  kp_9_xkeycode_ = XKeysymToKeycode(display, XK_KP_9);
 | 
| -  kp_decimal_xkeycode_ = XKeysymToKeycode(display, XK_KP_Decimal);
 | 
| +  keysym_to_keycode_map_.clear();
 | 
|  }
 | 
|  
 | 
|  KeyCode EventRewriter::NativeKeySymToNativeKeycode(KeySym keysym) {
 | 
| -  switch (keysym) {
 | 
| -    case XK_Control_L:
 | 
| -      return control_l_xkeycode_;
 | 
| -    case XK_Control_R:
 | 
| -      return control_r_xkeycode_;
 | 
| -    case XK_Alt_L:
 | 
| -      return alt_l_xkeycode_;
 | 
| -    case XK_Alt_R:
 | 
| -      return alt_r_xkeycode_;
 | 
| -    case XK_Meta_L:
 | 
| -      return meta_l_xkeycode_;
 | 
| -    case XK_Meta_R:
 | 
| -      return meta_r_xkeycode_;
 | 
| -    case XK_Super_L:
 | 
| -      return windows_l_xkeycode_;
 | 
| -    case XK_Caps_Lock:
 | 
| -      return caps_lock_xkeycode_;
 | 
| -    case XK_VoidSymbol:
 | 
| -      return void_symbol_xkeycode_;
 | 
| -    case XK_Delete:
 | 
| -      return delete_xkeycode_;
 | 
| -    case XK_Home:
 | 
| -      return home_xkeycode_;
 | 
| -    case XK_End:
 | 
| -      return end_xkeycode_;
 | 
| -    case XK_Prior:
 | 
| -      return prior_xkeycode_;
 | 
| -    case XK_Next:
 | 
| -      return next_xkeycode_;
 | 
| -    case XK_KP_0:
 | 
| -      return kp_0_xkeycode_;
 | 
| -    case XK_KP_1:
 | 
| -      return kp_1_xkeycode_;
 | 
| -    case XK_KP_2:
 | 
| -      return kp_2_xkeycode_;
 | 
| -    case XK_KP_3:
 | 
| -      return kp_3_xkeycode_;
 | 
| -    case XK_KP_4:
 | 
| -      return kp_4_xkeycode_;
 | 
| -    case XK_KP_5:
 | 
| -      return kp_5_xkeycode_;
 | 
| -    case XK_KP_6:
 | 
| -      return kp_6_xkeycode_;
 | 
| -    case XK_KP_7:
 | 
| -      return kp_7_xkeycode_;
 | 
| -    case XK_KP_8:
 | 
| -      return kp_8_xkeycode_;
 | 
| -    case XK_KP_9:
 | 
| -      return kp_9_xkeycode_;
 | 
| -    case XK_KP_Decimal:
 | 
| -      return kp_decimal_xkeycode_;
 | 
| -    default:
 | 
| -      break;
 | 
| +  if (keysym_to_keycode_map_.count(keysym))
 | 
| +    return keysym_to_keycode_map_[keysym];
 | 
| +
 | 
| +  Display* display = ui::GetXDisplay();
 | 
| +  KeyCode keycode = XKeysymToKeycode(display, keysym);
 | 
| +  keysym_to_keycode_map_[keysym] = keycode;
 | 
| +  return keycode;
 | 
| +}
 | 
| +
 | 
| +bool EventRewriter::EventSourceIsChromeOSKeyboard() const {
 | 
| +  if (force_chromeos_keyboard_for_testing_)
 | 
| +    return true;
 | 
| +
 | 
| +  if (last_device_id_ == kBadDeviceId)
 | 
| +    return false;
 | 
| +
 | 
| +  // Check which device generated |event|.
 | 
| +  std::map<int, DeviceType>::const_iterator iter =
 | 
| +      device_id_to_type_.find(last_device_id_);
 | 
| +  if (iter == device_id_to_type_.end()) {
 | 
| +    LOG(ERROR) << "Device ID " << last_device_id_ << " is unknown.";
 | 
| +    return false;
 | 
| +  }
 | 
| +
 | 
| +  const DeviceType type = iter->second;
 | 
| +  return type == kDeviceChromeOSKeyboard;
 | 
| +}
 | 
| +
 | 
| +bool EventRewriter::RewriteWithKeyboardRemappingsByKeySym(
 | 
| +    const KeyboardRemapping* remappings,
 | 
| +    size_t num_remappings,
 | 
| +    KeySym keysym,
 | 
| +    unsigned int native_mods,
 | 
| +    unsigned int mods,
 | 
| +    KeySym* remapped_native_keysym,
 | 
| +    unsigned int* remapped_native_mods,
 | 
| +    ui::KeyboardCode* remapped_keycode,
 | 
| +    unsigned int* remapped_mods) {
 | 
| +  for (size_t i = 0; i < num_remappings; ++i) {
 | 
| +    const KeyboardRemapping& map = remappings[i];
 | 
| +
 | 
| +    if (keysym != map.input_keysym)
 | 
| +      continue;
 | 
| +    unsigned int matched_mods = native_mods & map.input_native_mods;
 | 
| +    if (matched_mods != map.input_native_mods)
 | 
| +      continue;
 | 
| +
 | 
| +    *remapped_native_keysym = map.output_keysym;
 | 
| +    *remapped_keycode = map.output_keycode;
 | 
| +    *remapped_native_mods = native_mods & ~map.input_native_mods;
 | 
| +    *remapped_mods = mods & ~map.input_mods;
 | 
| +    return true;
 | 
|    }
 | 
| -  return 0U;
 | 
| +
 | 
| +  return false;
 | 
| +}
 | 
| +
 | 
| +bool EventRewriter::RewriteWithKeyboardRemappingsByKeyCode(
 | 
| +    const KeyboardRemapping* remappings,
 | 
| +    size_t num_remappings,
 | 
| +    KeyCode keycode,
 | 
| +    unsigned int native_mods,
 | 
| +    unsigned int mods,
 | 
| +    KeySym* remapped_native_keysym,
 | 
| +    unsigned int* remapped_native_mods,
 | 
| +    ui::KeyboardCode* remapped_keycode,
 | 
| +    unsigned int* remapped_mods) {
 | 
| +  for (size_t i = 0; i < num_remappings; ++i) {
 | 
| +    const KeyboardRemapping& map = remappings[i];
 | 
| +
 | 
| +    KeyCode input_keycode = NativeKeySymToNativeKeycode(map.input_keysym);
 | 
| +    if (keycode != input_keycode)
 | 
| +      continue;
 | 
| +    unsigned int matched_mods = native_mods & map.input_native_mods;
 | 
| +    if (matched_mods != map.input_native_mods)
 | 
| +      continue;
 | 
| +
 | 
| +    *remapped_native_keysym = map.output_keysym;
 | 
| +    *remapped_keycode = map.output_keycode;
 | 
| +    *remapped_native_mods = native_mods & ~map.input_native_mods;
 | 
| +    *remapped_mods = mods & ~map.input_mods;
 | 
| +    return true;
 | 
| +  }
 | 
| +
 | 
| +  return false;
 | 
|  }
 | 
|  #endif
 | 
|  
 | 
| @@ -372,7 +383,7 @@ void EventRewriter::Rewrite(ui::KeyEvent* event) {
 | 
|    RewriteModifiers(event);
 | 
|    RewriteNumPadKeys(event);
 | 
|    RewriteBackspaceAndArrowKeys(event);
 | 
| -  // TODO(yusukes): Implement crosbug.com/27167 (allow sending function keys).
 | 
| +  RewriteFunctionKeys(event);
 | 
|  }
 | 
|  
 | 
|  bool EventRewriter::IsAppleKeyboard() const {
 | 
| @@ -568,57 +579,68 @@ bool EventRewriter::RewriteNumPadKeys(ui::KeyEvent* event) {
 | 
|    const KeySym keysym = XLookupKeysym(xkey, 0);
 | 
|    switch (keysym) {
 | 
|      case XK_KP_Insert:
 | 
| -      OverwriteEvent(event, kp_0_xkeycode_, xkey->state | Mod2Mask,
 | 
| +      OverwriteEvent(event, NativeKeySymToNativeKeycode(XK_KP_0),
 | 
| +                     xkey->state | Mod2Mask,
 | 
|                       ui::VKEY_NUMPAD0, event->flags());
 | 
|        rewritten = true;
 | 
|        break;
 | 
|      case XK_KP_Delete:
 | 
| -      OverwriteEvent(event, kp_decimal_xkeycode_, xkey->state | Mod2Mask,
 | 
| +      OverwriteEvent(event, NativeKeySymToNativeKeycode(XK_KP_Decimal),
 | 
| +                     xkey->state | Mod2Mask,
 | 
|                       ui::VKEY_DECIMAL, event->flags());
 | 
|        rewritten = true;
 | 
|        break;
 | 
|      case XK_KP_End:
 | 
| -      OverwriteEvent(event, kp_1_xkeycode_, xkey->state | Mod2Mask,
 | 
| +      OverwriteEvent(event, NativeKeySymToNativeKeycode(XK_KP_1),
 | 
| +                     xkey->state | Mod2Mask,
 | 
|                       ui::VKEY_NUMPAD1, event->flags());
 | 
|        rewritten = true;
 | 
|        break;
 | 
|      case XK_KP_Down:
 | 
| -      OverwriteEvent(event, kp_2_xkeycode_, xkey->state | Mod2Mask,
 | 
| +      OverwriteEvent(event, NativeKeySymToNativeKeycode(XK_KP_2),
 | 
| +                     xkey->state | Mod2Mask,
 | 
|                       ui::VKEY_NUMPAD2, event->flags());
 | 
|        rewritten = true;
 | 
|        break;
 | 
|      case XK_KP_Next:
 | 
| -      OverwriteEvent(event, kp_3_xkeycode_, xkey->state | Mod2Mask,
 | 
| +      OverwriteEvent(event, NativeKeySymToNativeKeycode(XK_KP_3),
 | 
| +                     xkey->state | Mod2Mask,
 | 
|                       ui::VKEY_NUMPAD3, event->flags());
 | 
|        rewritten = true;
 | 
|        break;
 | 
|      case XK_KP_Left:
 | 
| -      OverwriteEvent(event, kp_4_xkeycode_, xkey->state | Mod2Mask,
 | 
| +      OverwriteEvent(event, NativeKeySymToNativeKeycode(XK_KP_4),
 | 
| +                     xkey->state | Mod2Mask,
 | 
|                       ui::VKEY_NUMPAD4, event->flags());
 | 
|        rewritten = true;
 | 
|        break;
 | 
|      case XK_KP_Begin:
 | 
| -      OverwriteEvent(event, kp_5_xkeycode_, xkey->state | Mod2Mask,
 | 
| +      OverwriteEvent(event, NativeKeySymToNativeKeycode(XK_KP_5),
 | 
| +                     xkey->state | Mod2Mask,
 | 
|                       ui::VKEY_NUMPAD5, event->flags());
 | 
|        rewritten = true;
 | 
|        break;
 | 
|      case XK_KP_Right:
 | 
| -      OverwriteEvent(event, kp_6_xkeycode_, xkey->state | Mod2Mask,
 | 
| +      OverwriteEvent(event, NativeKeySymToNativeKeycode(XK_KP_6),
 | 
| +                     xkey->state | Mod2Mask,
 | 
|                       ui::VKEY_NUMPAD6, event->flags());
 | 
|        rewritten = true;
 | 
|        break;
 | 
|      case XK_KP_Home:
 | 
| -      OverwriteEvent(event, kp_7_xkeycode_, xkey->state | Mod2Mask,
 | 
| +      OverwriteEvent(event, NativeKeySymToNativeKeycode(XK_KP_7),
 | 
| +                     xkey->state | Mod2Mask,
 | 
|                       ui::VKEY_NUMPAD7, event->flags());
 | 
|        rewritten = true;
 | 
|        break;
 | 
|      case XK_KP_Up:
 | 
| -      OverwriteEvent(event, kp_8_xkeycode_, xkey->state | Mod2Mask,
 | 
| +      OverwriteEvent(event, NativeKeySymToNativeKeycode(XK_KP_8),
 | 
| +                     xkey->state | Mod2Mask,
 | 
|                       ui::VKEY_NUMPAD8, event->flags());
 | 
|        rewritten = true;
 | 
|        break;
 | 
|      case XK_KP_Prior:
 | 
| -      OverwriteEvent(event, kp_9_xkeycode_, xkey->state | Mod2Mask,
 | 
| +      OverwriteEvent(event, NativeKeySymToNativeKeycode(XK_KP_9),
 | 
| +                     xkey->state | Mod2Mask,
 | 
|                       ui::VKEY_NUMPAD9, event->flags());
 | 
|        rewritten = true;
 | 
|        break;
 | 
| @@ -642,13 +664,12 @@ bool EventRewriter::RewriteNumPadKeys(ui::KeyEvent* event) {
 | 
|  }
 | 
|  
 | 
|  bool EventRewriter::RewriteBackspaceAndArrowKeys(ui::KeyEvent* event) {
 | 
| -  bool rewritten = false;
 | 
|  #if defined(OS_CHROMEOS)
 | 
| -  // On a Chromebook keyboard, modifier keys can be used to access extended
 | 
| +  // On a ChromeOS keyboard, modifier keys can be used to access extended
 | 
|    // keyboard shortcuts. On other keyboards, keys such as delete and page up are
 | 
|    // already available, so we do not need to rewrite anything here.
 | 
| -  if (!EventSourceIsChromebookKeyboard(event))
 | 
| -    return rewritten;
 | 
| +  if (!EventSourceIsChromeOSKeyboard())
 | 
| +    return false;
 | 
|  
 | 
|    const PrefService* pref_service =
 | 
|        pref_service_ ? pref_service_ : GetPrefService();
 | 
| @@ -657,78 +678,211 @@ bool EventRewriter::RewriteBackspaceAndArrowKeys(ui::KeyEvent* event) {
 | 
|  
 | 
|    bool search_as_function_key = chromebook_function_key && pref_service &&
 | 
|        pref_service->GetBoolean(prefs::kLanguageSearchKeyActsAsFunctionKey);
 | 
| +  if (search_as_function_key)
 | 
| +    DCHECK(HasChromeOSKeyboard());
 | 
|  
 | 
|    XEvent* xev = event->native_event();
 | 
|    XKeyEvent* xkey = &(xev->xkey);
 | 
|    const KeySym keysym = XLookupKeysym(xkey, 0);
 | 
|  
 | 
| +  KeySym remapped_native_keysym = 0;
 | 
| +  unsigned int remapped_native_mods = 0;
 | 
| +  ui::KeyboardCode remapped_keycode = ui::VKEY_UNKNOWN;
 | 
| +  unsigned int remapped_mods = 0;
 | 
| +
 | 
|    if (!search_as_function_key) {
 | 
| -    if (keysym == XK_BackSpace && (xkey->state & Mod1Mask)) {
 | 
| -      // Without Search as Function key: Remap Alt+Backspace to Delete.
 | 
| -      OverwriteEvent(event, delete_xkeycode_, xkey->state & ~Mod1Mask,
 | 
| -                     ui::VKEY_DELETE, event->flags() & ~ui::EF_ALT_DOWN);
 | 
| -      rewritten = true;
 | 
| -    } else if (keysym == XK_Up &&
 | 
| -               (xkey->state & ControlMask) && (xkey->state & Mod1Mask)) {
 | 
| -      // Without Search as Function key: Remap Ctrl+Alt+Up to Home.
 | 
| -      OverwriteEvent(event,
 | 
| -                     home_xkeycode_,
 | 
| -                     xkey->state & ~(Mod1Mask | ControlMask),
 | 
| -                     ui::VKEY_HOME,
 | 
| -                     event->flags() & ~(ui::EF_ALT_DOWN | ui::EF_CONTROL_DOWN));
 | 
| -      rewritten = true;
 | 
| -    } else if (keysym == XK_Up && (xkey->state & Mod1Mask)) {
 | 
| -      // Without Search as Function key: Remap Alt+Up to Prior (aka PageUp).
 | 
| -      OverwriteEvent(event, prior_xkeycode_, xkey->state & ~Mod1Mask,
 | 
| -                     ui::VKEY_PRIOR, event->flags() & ~ui::EF_ALT_DOWN);
 | 
| -      rewritten = true;
 | 
| -    } else if (keysym == XK_Down &&
 | 
| -               (xkey->state & ControlMask) && (xkey->state & Mod1Mask)) {
 | 
| -      // Without Search as Function key: Remap Ctrl+Alt+Down to End.
 | 
| -      OverwriteEvent(event,
 | 
| -                     end_xkeycode_,
 | 
| -                     xkey->state & ~(Mod1Mask | ControlMask),
 | 
| -                     ui::VKEY_END,
 | 
| -                     event->flags() & ~(ui::EF_ALT_DOWN | ui::EF_CONTROL_DOWN));
 | 
| -      rewritten = true;
 | 
| -    } else if (keysym == XK_Down && (xkey->state & Mod1Mask)) {
 | 
| -      // Without Search as Function key: Remap Alt+Down to Next (aka PageDown).
 | 
| -      OverwriteEvent(event, next_xkeycode_, xkey->state & ~Mod1Mask,
 | 
| -                     ui::VKEY_NEXT, event->flags() & ~ui::EF_ALT_DOWN);
 | 
| -      rewritten = true;
 | 
| -    }
 | 
| +    static const KeyboardRemapping remappings[] = {
 | 
| +      { // Alt+BackSpace -> Delete
 | 
| +        XK_BackSpace,
 | 
| +        ui::EF_ALT_DOWN, Mod1Mask,
 | 
| +        XK_Delete, ui::VKEY_DELETE,
 | 
| +      },
 | 
| +      { // Control+Alt+Up -> Home
 | 
| +        XK_Up,
 | 
| +        ui::EF_ALT_DOWN | ui::EF_CONTROL_DOWN, Mod1Mask | ControlMask,
 | 
| +        XK_Home, ui::VKEY_HOME,
 | 
| +      },
 | 
| +      { // Alt+Up -> Prior (aka PageUp)
 | 
| +        XK_Up,
 | 
| +        ui::EF_ALT_DOWN, Mod1Mask,
 | 
| +        XK_Prior, ui::VKEY_PRIOR,
 | 
| +      },
 | 
| +      { // Control+Alt+Down -> End
 | 
| +        XK_Down,
 | 
| +        ui::EF_ALT_DOWN | ui::EF_CONTROL_DOWN, Mod1Mask | ControlMask,
 | 
| +        XK_End, ui::VKEY_END,
 | 
| +      },
 | 
| +      { // Alt+Down -> Next (aka PageDown)
 | 
| +        XK_Down,
 | 
| +        ui::EF_ALT_DOWN, Mod1Mask,
 | 
| +        XK_Next, ui::VKEY_NEXT,
 | 
| +      }
 | 
| +    };
 | 
| +
 | 
| +    RewriteWithKeyboardRemappingsByKeySym(remappings,
 | 
| +                                          arraysize(remappings),
 | 
| +                                          keysym,
 | 
| +                                          xkey->state,
 | 
| +                                          event->flags(),
 | 
| +                                          &remapped_native_keysym,
 | 
| +                                          &remapped_native_mods,
 | 
| +                                          &remapped_keycode,
 | 
| +                                          &remapped_mods);
 | 
|    } else {
 | 
| -    if (keysym == XK_BackSpace && (xkey->state & Mod4Mask)) {
 | 
| -      // With Search as Function key: Remap Search+Backspace to Delete.
 | 
| -      OverwriteEvent(event, delete_xkeycode_, xkey->state & ~Mod4Mask,
 | 
| -                     ui::VKEY_DELETE, event->flags());
 | 
| -      rewritten = true;
 | 
| -    } else if (keysym == XK_Left && (xkey->state & Mod4Mask)) {
 | 
| -      // With Search as Function key: Remap Search+Left to Home.
 | 
| -      OverwriteEvent(event, home_xkeycode_, xkey->state & ~Mod4Mask,
 | 
| -                     ui::VKEY_HOME, event->flags());
 | 
| -      rewritten = true;
 | 
| -    } else if (keysym == XK_Up && (xkey->state & Mod4Mask)) {
 | 
| -      // With Search as Function key: Remap Search+Up to Prior (aka PageUp).
 | 
| -      OverwriteEvent(event, prior_xkeycode_, xkey->state & ~Mod4Mask,
 | 
| -                     ui::VKEY_PRIOR, event->flags());
 | 
| -      rewritten = true;
 | 
| -    } else if (keysym == XK_Right && (xkey->state & Mod4Mask)) {
 | 
| -      // With Search as Function key: Remap Search+Right to End.
 | 
| -      OverwriteEvent(event, end_xkeycode_, xkey->state & ~Mod4Mask,
 | 
| -                     ui::VKEY_END, event->flags());
 | 
| -      rewritten = true;
 | 
| -    } else if (keysym == XK_Down && (xkey->state & Mod4Mask)) {
 | 
| -      // With Search as Function key: Remap Search+Down to Next (aka PageDown).
 | 
| -      OverwriteEvent(event, next_xkeycode_, xkey->state & ~Mod4Mask,
 | 
| -                     ui::VKEY_NEXT, event->flags());
 | 
| -      rewritten = true;
 | 
| -    }
 | 
| +    static const KeyboardRemapping remappings[] = {
 | 
| +      { // Search+BackSpace -> Delete
 | 
| +        XK_BackSpace,
 | 
| +        0, Mod4Mask,
 | 
| +        XK_Delete, ui::VKEY_DELETE,
 | 
| +      },
 | 
| +      { // Search+Left -> Home
 | 
| +        XK_Left,
 | 
| +        0, Mod4Mask,
 | 
| +        XK_Home, ui::VKEY_HOME,
 | 
| +      },
 | 
| +      { // Search+Up -> Prior (aka PageUp)
 | 
| +        XK_Up,
 | 
| +        0, Mod4Mask,
 | 
| +        XK_Prior, ui::VKEY_PRIOR,
 | 
| +      },
 | 
| +      { // Search+Right -> End
 | 
| +        XK_Right,
 | 
| +        0, Mod4Mask,
 | 
| +        XK_End, ui::VKEY_END,
 | 
| +      },
 | 
| +      { // Search+Down -> Next (aka PageDown)
 | 
| +        XK_Down,
 | 
| +        0, Mod4Mask,
 | 
| +        XK_Next, ui::VKEY_NEXT,
 | 
| +      }
 | 
| +    };
 | 
| +
 | 
| +    RewriteWithKeyboardRemappingsByKeySym(remappings,
 | 
| +                                          arraysize(remappings),
 | 
| +                                          keysym,
 | 
| +                                          xkey->state,
 | 
| +                                          event->flags(),
 | 
| +                                          &remapped_native_keysym,
 | 
| +                                          &remapped_native_mods,
 | 
| +                                          &remapped_keycode,
 | 
| +                                          &remapped_mods);
 | 
|    }
 | 
| +
 | 
| +  if (!remapped_native_keysym || remapped_keycode == ui::VKEY_UNKNOWN)
 | 
| +    return false;
 | 
| +
 | 
| +  OverwriteEvent(event,
 | 
| +                 NativeKeySymToNativeKeycode(remapped_native_keysym),
 | 
| +                 remapped_native_mods,
 | 
| +                 remapped_keycode,
 | 
| +                 remapped_mods);
 | 
| +  return true;
 | 
|  #else
 | 
|    // TODO(yusukes): Support Ash on other platforms if needed.
 | 
| +  return false;
 | 
| +#endif
 | 
| +}
 | 
| +
 | 
| +bool EventRewriter::RewriteFunctionKeys(ui::KeyEvent* event) {
 | 
| +#if defined(OS_CHROMEOS)
 | 
| +  XEvent* xev = event->native_event();
 | 
| +  XKeyEvent* xkey = &(xev->xkey);
 | 
| +  const KeySym keysym = XLookupKeysym(xkey, 0);
 | 
| +
 | 
| +  KeySym remapped_native_keysym = 0;
 | 
| +  unsigned int remapped_native_mods = 0;
 | 
| +  ui::KeyboardCode remapped_keycode = ui::VKEY_UNKNOWN;
 | 
| +  unsigned int remapped_mods = 0;
 | 
| +
 | 
| +  // On a ChromeOS keyboard, F<number> keys have special purposes. On other
 | 
| +  // keyboards, they should act as usual.
 | 
| +  if (!EventSourceIsChromeOSKeyboard())
 | 
| +    return false;
 | 
| +
 | 
| +  // Rewrite the actual F1-F12 keys on a Chromebook keyboard to special keys.
 | 
| +  static const KeyboardRemapping fkeys_to_special_keys[] = {
 | 
| +    { XK_F1, 0, 0, XF86XK_Back, ui::VKEY_BROWSER_BACK, },
 | 
| +    { XK_F2, 0, 0, XF86XK_Forward, ui::VKEY_BROWSER_FORWARD, },
 | 
| +    { XK_F3, 0, 0, XF86XK_Reload, ui::VKEY_BROWSER_REFRESH, },
 | 
| +    { XK_F4, 0, 0, XF86XK_LaunchB, ui::VKEY_MEDIA_LAUNCH_APP2, },
 | 
| +    { XK_F5, 0, 0, XF86XK_LaunchA, ui::VKEY_MEDIA_LAUNCH_APP1, },
 | 
| +    { XK_F6, 0, 0, XF86XK_MonBrightnessDown, ui::VKEY_BRIGHTNESS_DOWN, },
 | 
| +    { XK_F7, 0, 0, XF86XK_MonBrightnessUp, ui::VKEY_BRIGHTNESS_UP, },
 | 
| +    { XK_F8, 0, 0, XF86XK_AudioMute, ui::VKEY_VOLUME_MUTE, },
 | 
| +    { XK_F9, 0, 0, XF86XK_AudioLowerVolume, ui::VKEY_VOLUME_DOWN, },
 | 
| +    { XK_F10, 0, 0, XF86XK_AudioRaiseVolume, ui::VKEY_VOLUME_UP, },
 | 
| +  };
 | 
| +
 | 
| +  bool remapped =
 | 
| +      RewriteWithKeyboardRemappingsByKeySym(fkeys_to_special_keys,
 | 
| +                                            arraysize(fkeys_to_special_keys),
 | 
| +                                            keysym,
 | 
| +                                            xkey->state,
 | 
| +                                            event->flags(),
 | 
| +                                            &remapped_native_keysym,
 | 
| +                                            &remapped_native_mods,
 | 
| +                                            &remapped_keycode,
 | 
| +                                            &remapped_mods);
 | 
| +
 | 
| +  if (!remapped) {
 | 
| +    const PrefService* pref_service =
 | 
| +        pref_service_ ? pref_service_ : GetPrefService();
 | 
| +    bool chromebook_function_key = CommandLine::ForCurrentProcess()->HasSwitch(
 | 
| +        switches::kEnableChromebookFunctionKey);
 | 
| +
 | 
| +    bool search_as_function_key = chromebook_function_key && pref_service &&
 | 
| +        pref_service->GetBoolean(prefs::kLanguageSearchKeyActsAsFunctionKey);
 | 
| +    if (search_as_function_key)
 | 
| +      DCHECK(HasChromeOSKeyboard());
 | 
| +
 | 
| +    // When using Search as a Function key, remap Search+<number> to F<number>.
 | 
| +    if (search_as_function_key && xkey->state & Mod4Mask) {
 | 
| +      // We check the keycode here instead of the keysym, as these keys have
 | 
| +      // different keysyms when modifiers are pressed, such as shift.
 | 
| +
 | 
| +      // TODO(danakj): On some i18n keyboards, these choices will be bad and we
 | 
| +      // should make layout-specific choices here. For eg. on a french keyboard
 | 
| +      // "-" and "6" are the same key, so F11 will not be accessible.
 | 
| +      static const KeyboardRemapping number_keys_to_fkeys[] = {
 | 
| +        { XK_1, 0, Mod4Mask, XK_F1, ui::VKEY_F1, },
 | 
| +        { XK_2, 0, Mod4Mask, XK_F2, ui::VKEY_F2, },
 | 
| +        { XK_3, 0, Mod4Mask, XK_F3, ui::VKEY_F3, },
 | 
| +        { XK_4, 0, Mod4Mask, XK_F4, ui::VKEY_F4, },
 | 
| +        { XK_5, 0, Mod4Mask, XK_F5, ui::VKEY_F5, },
 | 
| +        { XK_6, 0, Mod4Mask, XK_F6, ui::VKEY_F6, },
 | 
| +        { XK_7, 0, Mod4Mask, XK_F7, ui::VKEY_F7, },
 | 
| +        { XK_8, 0, Mod4Mask, XK_F8, ui::VKEY_F8, },
 | 
| +        { XK_9, 0, Mod4Mask, XK_F9, ui::VKEY_F9, },
 | 
| +        { XK_0, 0, Mod4Mask, XK_F10, ui::VKEY_F10, },
 | 
| +        { XK_minus, 0, Mod4Mask, XK_F11, ui::VKEY_F11, },
 | 
| +        { XK_equal, 0, Mod4Mask, XK_F12, ui::VKEY_F12, }
 | 
| +      };
 | 
| +
 | 
| +      RewriteWithKeyboardRemappingsByKeyCode(number_keys_to_fkeys,
 | 
| +                                             arraysize(number_keys_to_fkeys),
 | 
| +                                             xkey->keycode,
 | 
| +                                             xkey->state,
 | 
| +                                             event->flags(),
 | 
| +                                             &remapped_native_keysym,
 | 
| +                                             &remapped_native_mods,
 | 
| +                                             &remapped_keycode,
 | 
| +                                             &remapped_mods);
 | 
| +    }
 | 
| +  }
 | 
| +
 | 
| +  if (!remapped_native_keysym || remapped_keycode == ui::VKEY_UNKNOWN)
 | 
| +    return false;
 | 
| +
 | 
| +  OverwriteEvent(event,
 | 
| +                 NativeKeySymToNativeKeycode(remapped_native_keysym),
 | 
| +                 remapped_native_mods,
 | 
| +                 remapped_keycode,
 | 
| +                 remapped_mods);
 | 
| +  return true;
 | 
| +#else
 | 
| +  // TODO(danakj): Support Ash on other platforms if needed.
 | 
| +  return false;
 | 
|  #endif
 | 
| -  return rewritten;
 | 
|  }
 | 
|  
 | 
|  void EventRewriter::RewriteLocatedEvent(ui::LocatedEvent* event) {
 | 
| @@ -800,6 +954,11 @@ EventRewriter::DeviceType EventRewriter::DeviceAddedInternal(
 | 
|    if (type == kDeviceAppleKeyboard) {
 | 
|      VLOG(1) << "Apple keyboard '" << device_name << "' connected: "
 | 
|              << "id=" << device_id;
 | 
| +#if defined(OS_CHROMEOS)
 | 
| +  } else if (type == kDeviceChromeOSKeyboard) {
 | 
| +    VLOG(1) << "ChromeOS keyboard '" << device_name << "' connected: "
 | 
| +            << "id=" << device_id;
 | 
| +#endif
 | 
|    }
 | 
|    // Always overwrite the existing device_id since the X server may reuse a
 | 
|    // device id for an unattached device.
 | 
| 
 |