| OLD | NEW |
| (Empty) |
| 1 // Copyright (c) 2010 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/renderer/mock_keyboard_driver_win.h" | |
| 6 | |
| 7 #include "base/basictypes.h" | |
| 8 #include "base/logging.h" | |
| 9 #include "chrome/renderer/mock_keyboard.h" | |
| 10 | |
| 11 MockKeyboardDriverWin::MockKeyboardDriverWin() { | |
| 12 // Save the keyboard layout and status of the application. | |
| 13 // This class changes the keyboard layout and status of this application. | |
| 14 // This change may break succeeding tests. To prevent this possible break, we | |
| 15 // should save the layout and status here to restore when this instance is | |
| 16 // destroyed. | |
| 17 original_keyboard_layout_ = GetKeyboardLayout(0); | |
| 18 active_keyboard_layout_ = original_keyboard_layout_; | |
| 19 GetKeyboardState(&original_keyboard_states_[0]); | |
| 20 | |
| 21 const UINT num_keyboard_layouts = GetKeyboardLayoutList(0, NULL); | |
| 22 DCHECK(num_keyboard_layouts > 0); | |
| 23 | |
| 24 orig_keyboard_layouts_list_.resize(num_keyboard_layouts); | |
| 25 GetKeyboardLayoutList(num_keyboard_layouts, &orig_keyboard_layouts_list_[0]); | |
| 26 | |
| 27 memset(&keyboard_states_[0], 0, sizeof(keyboard_states_)); | |
| 28 } | |
| 29 | |
| 30 MockKeyboardDriverWin::~MockKeyboardDriverWin() { | |
| 31 // Unload the keyboard-layout driver, restore the keyboard state, and reset | |
| 32 // the keyboard layout for succeeding tests. | |
| 33 MaybeUnloadActiveLayout(); | |
| 34 SetKeyboardState(&original_keyboard_states_[0]); | |
| 35 ActivateKeyboardLayout(original_keyboard_layout_, KLF_RESET); | |
| 36 } | |
| 37 | |
| 38 void MockKeyboardDriverWin::MaybeUnloadActiveLayout() { | |
| 39 // Workaround for http://crbug.com/12093 | |
| 40 // Only unload a keyboard layout if it was loaded by this mock driver. | |
| 41 // Contrary to the documentation on MSDN unloading a keyboard layout | |
| 42 // previously loaded by the system causes that layout to stop working. | |
| 43 // We have confirmation of this behavior on XP & Vista. | |
| 44 for (size_t i = 0; i < orig_keyboard_layouts_list_.size(); ++i) { | |
| 45 if (orig_keyboard_layouts_list_[i] == active_keyboard_layout_) | |
| 46 return; | |
| 47 } | |
| 48 | |
| 49 // If we got here, this keyboard layout wasn't loaded by the system so it's | |
| 50 // safe to unload it ourselve's. | |
| 51 UnloadKeyboardLayout(active_keyboard_layout_); | |
| 52 active_keyboard_layout_ = original_keyboard_layout_; | |
| 53 } | |
| 54 | |
| 55 bool MockKeyboardDriverWin::SetLayout(int layout) { | |
| 56 // Unload the current keyboard-layout driver and load a new keyboard-layout | |
| 57 // driver for mapping a virtual key-code to a Unicode character. | |
| 58 MaybeUnloadActiveLayout(); | |
| 59 | |
| 60 // Scan the mapping table and retrieve a Language ID for the input layout. | |
| 61 // Load the keyboard-layout driver when we find a Language ID. | |
| 62 // This Language IDs are copied from the registry | |
| 63 // "HKLM\SYSTEM\CurrentControlSet\Control\Keyboard layouts". | |
| 64 // TODO(hbono): Add more keyboard-layout drivers. | |
| 65 static const struct { | |
| 66 const wchar_t* language; | |
| 67 MockKeyboard::Layout keyboard_layout; | |
| 68 } kLanguageIDs[] = { | |
| 69 {L"00000401", MockKeyboard::LAYOUT_ARABIC}, | |
| 70 {L"00000402", MockKeyboard::LAYOUT_BULGARIAN}, | |
| 71 {L"00000404", MockKeyboard::LAYOUT_CHINESE_TRADITIONAL}, | |
| 72 {L"00000405", MockKeyboard::LAYOUT_CZECH}, | |
| 73 {L"00000406", MockKeyboard::LAYOUT_DANISH}, | |
| 74 {L"00000407", MockKeyboard::LAYOUT_GERMAN}, | |
| 75 {L"00000408", MockKeyboard::LAYOUT_GREEK}, | |
| 76 {L"00000409", MockKeyboard::LAYOUT_UNITED_STATES}, | |
| 77 {L"0000040a", MockKeyboard::LAYOUT_SPANISH}, | |
| 78 {L"0000040b", MockKeyboard::LAYOUT_FINNISH}, | |
| 79 {L"0000040c", MockKeyboard::LAYOUT_FRENCH}, | |
| 80 {L"0000040d", MockKeyboard::LAYOUT_HEBREW}, | |
| 81 {L"0000040e", MockKeyboard::LAYOUT_HUNGARIAN}, | |
| 82 {L"00000410", MockKeyboard::LAYOUT_ITALIAN}, | |
| 83 {L"00000411", MockKeyboard::LAYOUT_JAPANESE}, | |
| 84 {L"00000412", MockKeyboard::LAYOUT_KOREAN}, | |
| 85 {L"00000415", MockKeyboard::LAYOUT_POLISH}, | |
| 86 {L"00000416", MockKeyboard::LAYOUT_PORTUGUESE_BRAZILIAN}, | |
| 87 {L"00000418", MockKeyboard::LAYOUT_ROMANIAN}, | |
| 88 {L"00000419", MockKeyboard::LAYOUT_RUSSIAN}, | |
| 89 {L"0000041a", MockKeyboard::LAYOUT_CROATIAN}, | |
| 90 {L"0000041b", MockKeyboard::LAYOUT_SLOVAK}, | |
| 91 {L"0000041e", MockKeyboard::LAYOUT_THAI}, | |
| 92 {L"0000041d", MockKeyboard::LAYOUT_SWEDISH}, | |
| 93 {L"0000041f", MockKeyboard::LAYOUT_TURKISH_Q}, | |
| 94 {L"0000042a", MockKeyboard::LAYOUT_VIETNAMESE}, | |
| 95 {L"00000439", MockKeyboard::LAYOUT_DEVANAGARI_INSCRIPT}, | |
| 96 {L"00000816", MockKeyboard::LAYOUT_PORTUGUESE}, | |
| 97 {L"00001409", MockKeyboard::LAYOUT_UNITED_STATES_DVORAK}, | |
| 98 {L"00001009", MockKeyboard::LAYOUT_CANADIAN_FRENCH}, | |
| 99 }; | |
| 100 | |
| 101 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kLanguageIDs); ++i) { | |
| 102 if (layout == kLanguageIDs[i].keyboard_layout) { | |
| 103 HKL new_keyboard_layout = LoadKeyboardLayout(kLanguageIDs[i].language, | |
| 104 KLF_ACTIVATE); | |
| 105 // loaded_keyboard_layout_ must always have a valid keyboard handle | |
| 106 // so we only assign upon success. | |
| 107 if (new_keyboard_layout) { | |
| 108 active_keyboard_layout_ = new_keyboard_layout; | |
| 109 return true; | |
| 110 } | |
| 111 | |
| 112 return false; | |
| 113 } | |
| 114 } | |
| 115 | |
| 116 // Return false if there are not any matching drivers. | |
| 117 return false; | |
| 118 } | |
| 119 | |
| 120 bool MockKeyboardDriverWin::SetModifiers(int modifiers) { | |
| 121 // Over-write the keyboard status with our modifier-key status. | |
| 122 // WebInputEventFactory::keyboardEvent() uses GetKeyState() to retrive | |
| 123 // modifier-key status. So, we update the modifier-key status with this | |
| 124 // SetKeyboardState() call before creating NativeWebKeyboardEvent | |
| 125 // instances. | |
| 126 memset(&keyboard_states_[0], 0, sizeof(keyboard_states_)); | |
| 127 static const struct { | |
| 128 int key_code; | |
| 129 int mask; | |
| 130 } kModifierMasks[] = { | |
| 131 {VK_SHIFT, MockKeyboard::LEFT_SHIFT | MockKeyboard::RIGHT_SHIFT}, | |
| 132 {VK_CONTROL, MockKeyboard::LEFT_CONTROL | MockKeyboard::RIGHT_CONTROL}, | |
| 133 {VK_MENU, MockKeyboard::LEFT_ALT | MockKeyboard::RIGHT_ALT}, | |
| 134 {VK_LSHIFT, MockKeyboard::LEFT_SHIFT}, | |
| 135 {VK_LCONTROL, MockKeyboard::LEFT_CONTROL}, | |
| 136 {VK_LMENU, MockKeyboard::LEFT_ALT}, | |
| 137 {VK_RSHIFT, MockKeyboard::RIGHT_SHIFT}, | |
| 138 {VK_RCONTROL, MockKeyboard::RIGHT_CONTROL}, | |
| 139 {VK_RMENU, MockKeyboard::RIGHT_ALT}, | |
| 140 }; | |
| 141 for (size_t i = 0; i < ARRAYSIZE_UNSAFE(kModifierMasks); ++i) { | |
| 142 const int kKeyDownMask = 0x80; | |
| 143 if (modifiers & kModifierMasks[i].mask) | |
| 144 keyboard_states_[kModifierMasks[i].key_code] = kKeyDownMask; | |
| 145 } | |
| 146 SetKeyboardState(&keyboard_states_[0]); | |
| 147 | |
| 148 return true; | |
| 149 } | |
| 150 | |
| 151 int MockKeyboardDriverWin::GetCharacters(int key_code, | |
| 152 std::wstring* output) { | |
| 153 // Retrieve Unicode characters composed from the input key-code and | |
| 154 // the mofifiers. | |
| 155 CHECK(output); | |
| 156 wchar_t code[16]; | |
| 157 int length = ToUnicodeEx(key_code, MapVirtualKey(key_code, 0), | |
| 158 &keyboard_states_[0], &code[0], arraysize(code), 0, | |
| 159 active_keyboard_layout_); | |
| 160 if (length > 0) | |
| 161 output->assign(code); | |
| 162 return length; | |
| 163 } | |
| OLD | NEW |