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 42 namespace chromeos { 43 44 namespace { 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. 57 const 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 76 const 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. 81 const 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 93 bool HasDiamondKey() { 94 return CommandLine::ForCurrentProcess()->HasSwitch( 95 chromeos::switches::kHasChromeOSDiamondKey); 96 } 97 98 bool 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 108 bool 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 130 EventRewriter::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 152 EventRewriter::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 160 EventRewriter::~EventRewriter() { 161 } 162 163 EventRewriter::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 171 void EventRewriter::RewriteMouseButtonEventForTesting( 172 const ui::MouseEvent& event, 173 scoped_ptr<ui::Event>* rewritten_event) { 174 RewriteMouseButtonEvent(event, rewritten_event); 175 } 176 177 ui::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 206 ui::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 221 void 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 282 void 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 288 const 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 295 bool 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 311 bool 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 321 int 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 365 bool 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 383 ui::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 433 ui::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 467 ui::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 491 ui::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 507 ui::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 525 void 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 645 void 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 671 void 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 747 void 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 822 void 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 830 int 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 848 EventRewriter::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 862 void 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