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