| // Licensed to the Software Freedom Conservancy (SFC) under one |
| // or more contributor license agreements. See the NOTICE file |
| // distributed with this work for additional information |
| // regarding copyright ownership. The SFC licenses this file |
| // to you under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| #include "JavaScriptActionSimulator.h" |
| |
| #include "errorcodes.h" |
| #include "logging.h" |
| |
| #include "../DocumentHost.h" |
| #include "../Generated/atoms.h" |
| #include "../Script.h" |
| |
| #define WAIT_TIME_IN_MILLISECONDS_PER_INPUT_EVENT 100 |
| |
| namespace webdriver { |
| |
| |
| JavaScriptActionSimulator::JavaScriptActionSimulator() { |
| CComVariant keyboard_state; |
| keyboard_state.vt = VT_NULL; |
| this->keyboard_state_ = keyboard_state; |
| |
| CComVariant mouse_state; |
| mouse_state.vt = VT_NULL; |
| this->mouse_state_ = mouse_state; |
| } |
| |
| JavaScriptActionSimulator::~JavaScriptActionSimulator() { |
| } |
| |
| int JavaScriptActionSimulator::SimulateActions(BrowserHandle browser_wrapper, |
| std::vector<INPUT> inputs, |
| InputState* input_state) { |
| LOG(TRACE) << "Entering JavaScriptActionSimulator::SimulateActions"; |
| for (size_t i = 0; i < inputs.size(); ++i) { |
| INPUT current_input = inputs[i]; |
| this->UpdateInputState(current_input, input_state); |
| if (current_input.type == INPUT_MOUSE) { |
| if (current_input.mi.dwFlags & MOUSEEVENTF_MOVE) { |
| this->SimulatePointerMove(browser_wrapper, current_input); |
| } else if (current_input.mi.dwFlags & MOUSEEVENTF_LEFTDOWN) { |
| this->SimulatePointerDown(browser_wrapper, current_input); |
| } else if (current_input.mi.dwFlags & MOUSEEVENTF_LEFTUP) { |
| this->SimulatePointerUp(browser_wrapper, current_input); |
| } else if (current_input.mi.dwFlags & MOUSEEVENTF_RIGHTDOWN) { |
| this->SimulatePointerDown(browser_wrapper, current_input); |
| } else if (current_input.mi.dwFlags & MOUSEEVENTF_RIGHTUP) { |
| this->SimulatePointerUp(browser_wrapper, current_input); |
| } |
| } else if (current_input.type == INPUT_KEYBOARD) { |
| this->SimulateKeyDown(browser_wrapper, current_input); |
| } else if (current_input.type == INPUT_HARDWARE) { |
| ::Sleep(current_input.hi.uMsg); |
| } |
| } |
| return WD_SUCCESS; |
| } |
| |
| int JavaScriptActionSimulator::SimulateKeyDown(BrowserHandle browser_wrapper, |
| INPUT input) { |
| KeyboardExtraInfo* extra_info = reinterpret_cast<KeyboardExtraInfo*>(input.ki.dwExtraInfo); |
| std::wstring key = extra_info->character; |
| delete extra_info; |
| LOG(DEBUG) << "Using synthetic events for sending keys"; |
| std::wstring script_source = L"(function() { return function(){" + |
| atoms::asString(atoms::INPUTS_BIN) + |
| L"; return webdriver.atoms.inputs.sendKeys(" + |
| L"arguments[0], arguments[1], arguments[2], arguments[3]);" + |
| L"};})();"; |
| CComPtr<IHTMLDocument2> doc; |
| browser_wrapper->GetDocument(&doc); |
| Script script_wrapper(doc, script_source, 4); |
| |
| script_wrapper.AddNullArgument(); |
| script_wrapper.AddArgument(key); |
| script_wrapper.AddArgument(this->keyboard_state_); |
| script_wrapper.AddArgument(true); |
| int status_code = script_wrapper.Execute(); |
| if (status_code == WD_SUCCESS) { |
| this->keyboard_state_ = script_wrapper.result(); |
| } else { |
| LOG(WARN) << "Unable to execute js to send keystrokes"; |
| } |
| return status_code; |
| } |
| |
| int JavaScriptActionSimulator::SimulatePointerMove(BrowserHandle browser_wrapper, |
| INPUT input) { |
| LOG(DEBUG) << "Using synthetic events for mouse move"; |
| MouseExtraInfo* extra_info = reinterpret_cast<MouseExtraInfo*>(input.mi.dwExtraInfo); |
| int x_offset = extra_info->offset_x; |
| int y_offset = extra_info->offset_y; |
| bool is_offset_specified = extra_info->offset_specified; |
| CComPtr<IHTMLElement> target_element = extra_info->element; |
| delete extra_info; |
| |
| std::wstring script_source = L"(function() { return function(){" + |
| atoms::asString(atoms::INPUTS_BIN) + |
| L"; return webdriver.atoms.inputs.mouseMove(arguments[0], arguments[1], arguments[2], arguments[3]);" + |
| L"};})();"; |
| |
| CComPtr<IHTMLDocument2> doc; |
| browser_wrapper->GetDocument(&doc); |
| Script script_wrapper(doc, script_source, 4); |
| |
| if (target_element != NULL) { |
| script_wrapper.AddArgument(target_element); |
| } else { |
| script_wrapper.AddNullArgument(); |
| } |
| |
| if (is_offset_specified) { |
| script_wrapper.AddArgument(x_offset); |
| script_wrapper.AddArgument(y_offset); |
| } else { |
| script_wrapper.AddNullArgument(); |
| script_wrapper.AddNullArgument(); |
| } |
| |
| script_wrapper.AddArgument(this->mouse_state_); |
| int status_code = script_wrapper.Execute(); |
| if (status_code == WD_SUCCESS) { |
| this->mouse_state_ = script_wrapper.result(); |
| } else { |
| LOG(WARN) << "Unable to execute js to mouse move"; |
| } |
| return status_code; |
| } |
| |
| int JavaScriptActionSimulator::SimulatePointerDown(BrowserHandle browser_wrapper, |
| INPUT input) { |
| LOG(DEBUG) << "Using synthetic events for mouse button down"; |
| std::wstring script_source = L"(function() { return function(){" + |
| atoms::asString(atoms::INPUTS_BIN) + |
| L"; return webdriver.atoms.inputs.mouseButtonDown(arguments[0]);" + |
| L"};})();"; |
| |
| CComPtr<IHTMLDocument2> doc; |
| browser_wrapper->GetDocument(&doc); |
| Script script_wrapper(doc, script_source, 1); |
| script_wrapper.AddArgument(this->mouse_state_); |
| int status_code = script_wrapper.Execute(); |
| if (status_code == WD_SUCCESS) { |
| this->mouse_state_ = script_wrapper.result(); |
| } else { |
| LOG(WARN) << "Unable to execute js to perform mouse button down"; |
| return status_code; |
| } |
| return status_code; |
| } |
| |
| int JavaScriptActionSimulator::SimulatePointerUp(BrowserHandle browser_wrapper, |
| INPUT input) { |
| LOG(DEBUG) << "Using synthetic events for mouse button up"; |
| std::wstring script_source = L"(function() { return function(){" + |
| atoms::asString(atoms::INPUTS_BIN) + |
| L"; return webdriver.atoms.inputs.mouseButtonUp(arguments[0]);" + |
| L"};})();"; |
| |
| CComPtr<IHTMLDocument2> doc; |
| browser_wrapper->GetDocument(&doc); |
| Script script_wrapper(doc, script_source, 1); |
| script_wrapper.AddArgument(this->mouse_state_); |
| int status_code = script_wrapper.Execute(); |
| if (status_code == WD_SUCCESS) { |
| this->mouse_state_ = script_wrapper.result(); |
| } else { |
| LOG(WARN) << "Unable to execute js to perform mouse button up"; |
| return status_code; |
| } |
| return status_code; |
| } |
| |
| int JavaScriptActionSimulator::SimulatePause(BrowserHandle browser_wrapper, |
| INPUT input) { |
| ::Sleep(input.hi.uMsg); |
| return WD_SUCCESS; |
| } |
| |
| } // namespace webdriver |