| OLD | NEW |
| 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "chrome/test/webdriver/webdriver_key_converter.h" | 5 #include "chrome/test/webdriver/webdriver_key_converter.h" |
| 6 | 6 |
| 7 #include "base/format_macros.h" |
| 8 #include "base/stringprintf.h" |
| 7 #include "base/utf_string_conversions.h" | 9 #include "base/utf_string_conversions.h" |
| 8 #include "chrome/common/automation_constants.h" | 10 #include "chrome/common/automation_constants.h" |
| 9 #include "chrome/test/automation/automation_json_requests.h" | 11 #include "chrome/test/automation/automation_json_requests.h" |
| 10 #include "chrome/test/webdriver/keycode_text_conversion.h" | 12 #include "chrome/test/webdriver/keycode_text_conversion.h" |
| 11 | 13 |
| 12 namespace { | 14 namespace { |
| 13 | 15 |
| 14 // TODO(kkania): Use this in KeyMap. | 16 // TODO(kkania): Use this in KeyMap. |
| 15 // Ordered list of all the key codes corresponding to special WebDriver keys. | 17 // Ordered list of all the key codes corresponding to special WebDriver keys. |
| 16 // These WebDriver keys are defined in the Unicode Private Use Area. | 18 // These WebDriver keys are defined in the Unicode Private Use Area. |
| (...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 102 // be set. | 104 // be set. |
| 103 bool KeyCodeFromSpecialWebDriverKey(char16 key, ui::KeyboardCode* key_code) { | 105 bool KeyCodeFromSpecialWebDriverKey(char16 key, ui::KeyboardCode* key_code) { |
| 104 int index = static_cast<int>(key) - 0xE000U; | 106 int index = static_cast<int>(key) - 0xE000U; |
| 105 bool is_special_key = index >= 0 && | 107 bool is_special_key = index >= 0 && |
| 106 index < static_cast<int>(arraysize(kSpecialWebDriverKeys)); | 108 index < static_cast<int>(arraysize(kSpecialWebDriverKeys)); |
| 107 if (is_special_key) | 109 if (is_special_key) |
| 108 *key_code = kSpecialWebDriverKeys[index]; | 110 *key_code = kSpecialWebDriverKeys[index]; |
| 109 return is_special_key; | 111 return is_special_key; |
| 110 } | 112 } |
| 111 | 113 |
| 114 // Gets the key code associated with |key|, if it is a special shorthand key. |
| 115 // Shorthand keys are common text equivalents for keys, such as the newline |
| 116 // character, which is shorthand for the return key. Returns whether |key| is |
| 117 // a shorthand key. If true, |key_code| will be set and |client_should_skip| |
| 118 // will be set to whether the key should be skipped. |
| 119 bool KeyCodeFromShorthandKey(char16 key_utf16, |
| 120 ui::KeyboardCode* key_code, |
| 121 bool* client_should_skip) { |
| 122 string16 key_str_utf16; |
| 123 key_str_utf16.push_back(key_utf16); |
| 124 std::string key_str_utf8 = UTF16ToUTF8(key_str_utf16); |
| 125 if (key_str_utf8.length() != 1) |
| 126 return false; |
| 127 bool should_skip = false; |
| 128 char key = key_str_utf8[0]; |
| 129 if (key == '\n') { |
| 130 *key_code = ui::VKEY_RETURN; |
| 131 } else if (key == '\t') { |
| 132 *key_code = ui::VKEY_TAB; |
| 133 } else if (key == '\b') { |
| 134 *key_code = ui::VKEY_BACK; |
| 135 } else if (key == ' ') { |
| 136 *key_code = ui::VKEY_SPACE; |
| 137 } else if (key == '\r') { |
| 138 *key_code = ui::VKEY_UNKNOWN; |
| 139 should_skip = true; |
| 140 } else { |
| 141 return false; |
| 142 } |
| 143 *client_should_skip = should_skip; |
| 144 return true; |
| 145 } |
| 146 |
| 112 } // namespace | 147 } // namespace |
| 113 | 148 |
| 114 namespace webdriver { | 149 namespace webdriver { |
| 115 | 150 |
| 116 WebKeyEvent CreateKeyDownEvent(ui::KeyboardCode key_code, int modifiers) { | 151 WebKeyEvent CreateKeyDownEvent(ui::KeyboardCode key_code, int modifiers) { |
| 117 return WebKeyEvent(automation::kRawKeyDownType, key_code, "", "", modifiers); | 152 return WebKeyEvent(automation::kRawKeyDownType, key_code, "", "", modifiers); |
| 118 } | 153 } |
| 119 | 154 |
| 120 WebKeyEvent CreateKeyUpEvent(ui::KeyboardCode key_code, int modifiers) { | 155 WebKeyEvent CreateKeyUpEvent(ui::KeyboardCode key_code, int modifiers) { |
| 121 return WebKeyEvent(automation::kKeyUpType, key_code, "", "", modifiers); | 156 return WebKeyEvent(automation::kKeyUpType, key_code, "", "", modifiers); |
| 122 } | 157 } |
| 123 | 158 |
| 124 WebKeyEvent CreateCharEvent(const std::string& unmodified_text, | 159 WebKeyEvent CreateCharEvent(const std::string& unmodified_text, |
| 125 const std::string& modified_text, | 160 const std::string& modified_text, |
| 126 int modifiers) { | 161 int modifiers) { |
| 127 return WebKeyEvent(automation::kCharType, | 162 return WebKeyEvent(automation::kCharType, |
| 128 ui::VKEY_UNKNOWN, | 163 ui::VKEY_UNKNOWN, |
| 129 unmodified_text, | 164 unmodified_text, |
| 130 modified_text, | 165 modified_text, |
| 131 modifiers); | 166 modifiers); |
| 132 } | 167 } |
| 133 | 168 |
| 134 void ConvertKeysToWebKeyEvents(const string16& client_keys, | 169 bool ConvertKeysToWebKeyEvents(const string16& client_keys, |
| 135 std::vector<WebKeyEvent>* key_events) { | 170 std::vector<WebKeyEvent>* client_key_events, |
| 171 std::string* error_msg) { |
| 172 std::vector<WebKeyEvent> key_events; |
| 173 |
| 136 // Add an implicit NULL character to the end of the input to depress all | 174 // Add an implicit NULL character to the end of the input to depress all |
| 137 // modifiers. | 175 // modifiers. |
| 138 string16 keys = client_keys; | 176 string16 keys = client_keys; |
| 139 keys.push_back(kWebDriverNullKey); | 177 keys.push_back(kWebDriverNullKey); |
| 140 | 178 |
| 141 int sticky_modifiers = 0; | 179 int sticky_modifiers = 0; |
| 142 for (size_t i = 0; i < keys.size(); ++i) { | 180 for (size_t i = 0; i < keys.size(); ++i) { |
| 143 char16 key = keys[i]; | 181 char16 key = keys[i]; |
| 144 | 182 |
| 145 if (key == kWebDriverNullKey) { | 183 if (key == kWebDriverNullKey) { |
| 146 // Release all modifier keys and clear |stick_modifiers|. | 184 // Release all modifier keys and clear |stick_modifiers|. |
| 147 if (sticky_modifiers & automation::kShiftKeyMask) | 185 if (sticky_modifiers & automation::kShiftKeyMask) |
| 148 key_events->push_back(CreateKeyUpEvent(ui::VKEY_SHIFT, 0)); | 186 key_events.push_back(CreateKeyUpEvent(ui::VKEY_SHIFT, 0)); |
| 149 if (sticky_modifiers & automation::kControlKeyMask) | 187 if (sticky_modifiers & automation::kControlKeyMask) |
| 150 key_events->push_back(CreateKeyUpEvent(ui::VKEY_CONTROL, 0)); | 188 key_events.push_back(CreateKeyUpEvent(ui::VKEY_CONTROL, 0)); |
| 151 if (sticky_modifiers & automation::kAltKeyMask) | 189 if (sticky_modifiers & automation::kAltKeyMask) |
| 152 key_events->push_back(CreateKeyUpEvent(ui::VKEY_MENU, 0)); | 190 key_events.push_back(CreateKeyUpEvent(ui::VKEY_MENU, 0)); |
| 153 if (sticky_modifiers & automation::kMetaKeyMask) | 191 if (sticky_modifiers & automation::kMetaKeyMask) |
| 154 key_events->push_back(CreateKeyUpEvent(ui::VKEY_COMMAND, 0)); | 192 key_events.push_back(CreateKeyUpEvent(ui::VKEY_COMMAND, 0)); |
| 155 sticky_modifiers = 0; | 193 sticky_modifiers = 0; |
| 156 continue; | 194 continue; |
| 157 } | 195 } |
| 158 if (IsModifierKey(key)) { | 196 if (IsModifierKey(key)) { |
| 159 // Press or release the modifier, and adjust |sticky_modifiers|. | 197 // Press or release the modifier, and adjust |sticky_modifiers|. |
| 160 bool modifier_down = false; | 198 bool modifier_down = false; |
| 161 ui::KeyboardCode key_code = ui::VKEY_UNKNOWN; | 199 ui::KeyboardCode key_code = ui::VKEY_UNKNOWN; |
| 162 if (key == kWebDriverShiftKey) { | 200 if (key == kWebDriverShiftKey) { |
| 163 sticky_modifiers ^= automation::kShiftKeyMask; | 201 sticky_modifiers ^= automation::kShiftKeyMask; |
| 164 modifier_down = sticky_modifiers & automation::kShiftKeyMask; | 202 modifier_down = sticky_modifiers & automation::kShiftKeyMask; |
| 165 key_code = ui::VKEY_SHIFT; | 203 key_code = ui::VKEY_SHIFT; |
| 166 } else if (key == kWebDriverControlKey) { | 204 } else if (key == kWebDriverControlKey) { |
| 167 sticky_modifiers ^= automation::kControlKeyMask; | 205 sticky_modifiers ^= automation::kControlKeyMask; |
| 168 modifier_down = sticky_modifiers & automation::kControlKeyMask; | 206 modifier_down = sticky_modifiers & automation::kControlKeyMask; |
| 169 key_code = ui::VKEY_CONTROL; | 207 key_code = ui::VKEY_CONTROL; |
| 170 } else if (key == kWebDriverAltKey) { | 208 } else if (key == kWebDriverAltKey) { |
| 171 sticky_modifiers ^= automation::kAltKeyMask; | 209 sticky_modifiers ^= automation::kAltKeyMask; |
| 172 modifier_down = sticky_modifiers & automation::kAltKeyMask; | 210 modifier_down = sticky_modifiers & automation::kAltKeyMask; |
| 173 key_code = ui::VKEY_MENU; | 211 key_code = ui::VKEY_MENU; |
| 174 } else if (key == kWebDriverCommandKey) { | 212 } else if (key == kWebDriverCommandKey) { |
| 175 sticky_modifiers ^= automation::kMetaKeyMask; | 213 sticky_modifiers ^= automation::kMetaKeyMask; |
| 176 modifier_down = sticky_modifiers & automation::kMetaKeyMask; | 214 modifier_down = sticky_modifiers & automation::kMetaKeyMask; |
| 177 key_code = ui::VKEY_COMMAND; | 215 key_code = ui::VKEY_COMMAND; |
| 178 } else { | 216 } else { |
| 179 NOTREACHED(); | 217 NOTREACHED(); |
| 180 } | 218 } |
| 181 if (modifier_down) | 219 if (modifier_down) |
| 182 key_events->push_back(CreateKeyDownEvent(key_code, sticky_modifiers)); | 220 key_events.push_back(CreateKeyDownEvent(key_code, sticky_modifiers)); |
| 183 else | 221 else |
| 184 key_events->push_back(CreateKeyUpEvent(key_code, sticky_modifiers)); | 222 key_events.push_back(CreateKeyUpEvent(key_code, sticky_modifiers)); |
| 185 continue; | 223 continue; |
| 186 } | 224 } |
| 187 | 225 |
| 188 ui::KeyboardCode key_code = ui::VKEY_UNKNOWN; | 226 ui::KeyboardCode key_code = ui::VKEY_UNKNOWN; |
| 189 std::string unmodified_text, modified_text; | 227 std::string unmodified_text, modified_text; |
| 190 int all_modifiers = sticky_modifiers; | 228 int all_modifiers = sticky_modifiers; |
| 191 | 229 |
| 192 bool is_special_key = KeyCodeFromSpecialWebDriverKey(key, &key_code); | 230 // Get the key code, text, and modifiers for the given key. |
| 193 if (is_special_key && key_code == ui::VKEY_UNKNOWN) { | 231 bool should_skip = false; |
| 194 LOG(ERROR) << "Unknown WebDriver key: " << static_cast<int>(key); | 232 if (KeyCodeFromSpecialWebDriverKey(key, &key_code) || |
| 195 continue; | 233 KeyCodeFromShorthandKey(key, &key_code, &should_skip)) { |
| 196 } | 234 if (should_skip) |
| 197 if (!is_special_key) { | 235 continue; |
| 236 if (key_code == ui::VKEY_UNKNOWN) { |
| 237 *error_msg = StringPrintf( |
| 238 "Unknown WebDriver key(%d) at string index (%" PRIuS ")", |
| 239 static_cast<int>(key), |
| 240 i); |
| 241 return false; |
| 242 } |
| 243 if (key_code == ui::VKEY_RETURN) { |
| 244 // For some reason Chrome expects a carriage return for the return key. |
| 245 modified_text = unmodified_text = "\r"; |
| 246 } else { |
| 247 unmodified_text = ConvertKeyCodeToText(key_code, 0); |
| 248 modified_text = ConvertKeyCodeToText(key_code, all_modifiers); |
| 249 } |
| 250 } else { |
| 198 int necessary_modifiers = 0; | 251 int necessary_modifiers = 0; |
| 199 ConvertCharToKeyCode(key, &key_code, &necessary_modifiers); | 252 ConvertCharToKeyCode(key, &key_code, &necessary_modifiers); |
| 200 all_modifiers |= necessary_modifiers; | 253 all_modifiers |= necessary_modifiers; |
| 201 } | 254 if (key_code != ui::VKEY_UNKNOWN) { |
| 202 if (key_code != ui::VKEY_UNKNOWN) { | 255 unmodified_text = ConvertKeyCodeToText(key_code, 0); |
| 203 unmodified_text = ConvertKeyCodeToText(key_code, 0); | 256 modified_text = ConvertKeyCodeToText(key_code, all_modifiers); |
| 204 modified_text = ConvertKeyCodeToText(key_code, all_modifiers); | 257 } |
| 205 } | 258 if (unmodified_text.empty() || modified_text.empty()) { |
| 206 if (!is_special_key && (unmodified_text.empty() || modified_text.empty())) { | 259 // Do a best effort and use the raw key we were given. |
| 207 // Do a best effort and use the raw key we were given. | 260 LOG(WARNING) << "No translation for key code. Code point: " |
| 208 LOG(WARNING) << "No translation for key code. Code point: " | 261 << static_cast<int>(key); |
| 209 << static_cast<int>(key); | 262 if (unmodified_text.empty()) |
| 210 if (unmodified_text.empty()) | 263 unmodified_text = UTF16ToUTF8(keys.substr(i, 1)); |
| 211 unmodified_text = UTF16ToUTF8(keys.substr(i, 1)); | 264 if (modified_text.empty()) |
| 212 if (modified_text.empty()) | 265 modified_text = UTF16ToUTF8(keys.substr(i, 1)); |
| 213 modified_text = UTF16ToUTF8(keys.substr(i, 1)); | 266 } |
| 214 } | 267 } |
| 215 | 268 |
| 216 // Create the key events. | 269 // Create the key events. |
| 217 bool need_shift_key = | 270 bool need_shift_key = |
| 218 all_modifiers & automation::kShiftKeyMask && | 271 all_modifiers & automation::kShiftKeyMask && |
| 219 !(sticky_modifiers & automation::kShiftKeyMask); | 272 !(sticky_modifiers & automation::kShiftKeyMask); |
| 220 if (need_shift_key) { | 273 if (need_shift_key) { |
| 221 key_events->push_back( | 274 key_events.push_back( |
| 222 CreateKeyDownEvent(ui::VKEY_SHIFT, sticky_modifiers)); | 275 CreateKeyDownEvent(ui::VKEY_SHIFT, sticky_modifiers)); |
| 223 } | 276 } |
| 224 | 277 |
| 225 key_events->push_back(CreateKeyDownEvent(key_code, all_modifiers)); | 278 key_events.push_back(CreateKeyDownEvent(key_code, all_modifiers)); |
| 226 if (unmodified_text.length() || modified_text.length()) { | 279 if (unmodified_text.length() || modified_text.length()) { |
| 227 key_events->push_back( | 280 key_events.push_back( |
| 228 CreateCharEvent(unmodified_text, modified_text, all_modifiers)); | 281 CreateCharEvent(unmodified_text, modified_text, all_modifiers)); |
| 229 } | 282 } |
| 230 key_events->push_back(CreateKeyUpEvent(key_code, all_modifiers)); | 283 key_events.push_back(CreateKeyUpEvent(key_code, all_modifiers)); |
| 231 | 284 |
| 232 if (need_shift_key) { | 285 if (need_shift_key) { |
| 233 key_events->push_back( | 286 key_events.push_back( |
| 234 CreateKeyUpEvent(ui::VKEY_SHIFT, sticky_modifiers)); | 287 CreateKeyUpEvent(ui::VKEY_SHIFT, sticky_modifiers)); |
| 235 } | 288 } |
| 236 } | 289 } |
| 290 client_key_events->swap(key_events); |
| 291 return true; |
| 237 } | 292 } |
| 238 | 293 |
| 239 } // namespace webdriver | 294 } // namespace webdriver |
| OLD | NEW |