Skip to content

Commit

Permalink
Slightly modified setting IE window to have focus when sending input
Browse files Browse the repository at this point in the history
This code only affects the browser when the requireWindowFocus
capability is set at session start.
  • Loading branch information
jimevans committed Jul 10, 2019
1 parent 6275e4e commit c346167
Show file tree
Hide file tree
Showing 12 changed files with 132 additions and 88 deletions.
80 changes: 2 additions & 78 deletions cpp/iedriver/ActionSimulators/SendInputActionSimulator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,12 @@

#include "SendInputActionSimulator.h"

#include <UIAutomation.h>

#include "errorcodes.h"
#include "logging.h"

#include "../DocumentHost.h"
#include "../HookProcessor.h"
#include "../messages.h"

#define WAIT_TIME_IN_MILLISECONDS_PER_INPUT_EVENT 100

Expand Down Expand Up @@ -128,7 +127,7 @@ void SendInputActionSimulator::SendInputToBrowser(BrowserHandle browser_wrapper,
int start_index,
int input_count) {
if (input_count > 0) {
bool focus_set = this->SetFocusToBrowser(browser_wrapper);
bool focus_set = browser_wrapper->SetFocusToBrowser();
if (!focus_set) {
LOG(WARN) << "Focus not set to browser window";
}
Expand Down Expand Up @@ -209,81 +208,6 @@ bool SendInputActionSimulator::WaitForInputEventProcessing(int input_count) {
return inputs_processed;
}

bool SendInputActionSimulator::SetFocusToBrowser(BrowserHandle browser_wrapper) {
LOG(TRACE) << "Entering InputManager::SetFocusToBrowser";

HWND top_level_window_handle = browser_wrapper->GetTopLevelWindowHandle();
HWND foreground_window = ::GetAncestor(::GetForegroundWindow(), GA_ROOT);
if (foreground_window != top_level_window_handle) {
LOG(TRACE) << "Top-level IE window is " << top_level_window_handle
<< " foreground window is " << foreground_window;
CComPtr<IUIAutomation> ui_automation;
HRESULT hr = ::CoCreateInstance(CLSID_CUIAutomation,
NULL,
CLSCTX_INPROC_SERVER,
IID_IUIAutomation,
reinterpret_cast<void**>(&ui_automation));
if (SUCCEEDED(hr)) {
LOG(TRACE) << "Using UI Automation to set window focus";
CComPtr<IUIAutomationElement> parent_window;
hr = ui_automation->ElementFromHandle(top_level_window_handle,
&parent_window);
if (SUCCEEDED(hr)) {
CComPtr<IUIAutomationWindowPattern> window_pattern;
hr = parent_window->GetCurrentPatternAs(UIA_WindowPatternId,
IID_PPV_ARGS(&window_pattern));
if (SUCCEEDED(hr)) {
BOOL is_topmost;
hr = window_pattern->get_CurrentIsTopmost(&is_topmost);
WindowVisualState visual_state;
hr = window_pattern->get_CurrentWindowVisualState(&visual_state);
if (visual_state == WindowVisualState::WindowVisualState_Maximized ||
visual_state == WindowVisualState::WindowVisualState_Normal) {
parent_window->SetFocus();
window_pattern->SetWindowVisualState(visual_state);
}
}
}
}
}

foreground_window = ::GetAncestor(::GetForegroundWindow(), GA_ROOT);
if (foreground_window != top_level_window_handle) {
LOG(TRACE) << "Top-level IE window is " << top_level_window_handle
<< " foreground window is " << foreground_window;
LOG(TRACE) << "Window still not in foreground; "
<< "attempting to use SetForegroundWindow API";
UINT_PTR lock_timeout = 0;
DWORD process_id = 0;
DWORD thread_id = ::GetWindowThreadProcessId(browser_wrapper->GetContentWindowHandle(),
&process_id);
DWORD current_thread_id = ::GetCurrentThreadId();
DWORD current_process_id = ::GetCurrentProcessId();
if (current_thread_id != thread_id) {
::AttachThreadInput(current_thread_id, thread_id, TRUE);
::SystemParametersInfo(SPI_GETFOREGROUNDLOCKTIMEOUT,
0,
&lock_timeout,
0);
::SystemParametersInfo(SPI_SETFOREGROUNDLOCKTIMEOUT,
0,
0,
SPIF_SENDWININICHANGE | SPIF_UPDATEINIFILE);
::AllowSetForegroundWindow(current_process_id);
}
::SetForegroundWindow(top_level_window_handle);
if (current_thread_id != thread_id) {
::SystemParametersInfo(SPI_SETFOREGROUNDLOCKTIMEOUT,
0,
reinterpret_cast<void*>(lock_timeout),
SPIF_SENDWININICHANGE | SPIF_UPDATEINIFILE);
::AttachThreadInput(current_thread_id, thread_id, FALSE);
}
}
foreground_window = ::GetAncestor(::GetForegroundWindow(), GA_ROOT);
return foreground_window == top_level_window_handle;
}

} // namespace webdriver

#ifdef __cplusplus
Expand Down
6 changes: 4 additions & 2 deletions cpp/iedriver/ActionSimulators/SendInputActionSimulator.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,10 @@ class SendInputActionSimulator : public ActionSimulator {
unsigned long input_flags);

bool WaitForInputEventProcessing(int input_count);
bool SetFocusToBrowser(BrowserHandle browser_wrapper);
void SendInputToBrowser(BrowserHandle browser_wrapper, std::vector<INPUT> inputs, int start_index, int input_count);
void SendInputToBrowser(BrowserHandle browser_wrapper,
std::vector<INPUT> inputs,
int start_index,
int input_count);
};

} // namespace webdriver
Expand Down
107 changes: 107 additions & 0 deletions cpp/iedriver/DocumentHost.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#include "DocumentHost.h"

#include <IEPMapi.h>
#include <UIAutomation.h>

#include "errorcodes.h"
#include "logging.h"
Expand Down Expand Up @@ -442,6 +443,101 @@ bool DocumentHost::IsProtectedMode() {
return is_protected_mode;
}

bool DocumentHost::SetFocusToBrowser() {
LOG(TRACE) << "Entering DocumentHost::SetFocusToBrowser";

HWND top_level_window_handle = this->GetTopLevelWindowHandle();
HWND foreground_window = ::GetAncestor(::GetForegroundWindow(), GA_ROOT);
if (foreground_window != top_level_window_handle) {
LOG(TRACE) << "Top-level IE window is " << top_level_window_handle
<< " foreground window is " << foreground_window;
CComPtr<IUIAutomation> ui_automation;
HRESULT hr = ::CoCreateInstance(CLSID_CUIAutomation,
NULL,
CLSCTX_INPROC_SERVER,
IID_IUIAutomation,
reinterpret_cast<void**>(&ui_automation));
if (SUCCEEDED(hr)) {
LOG(TRACE) << "Using UI Automation to set window focus";
CComPtr<IUIAutomationElement> parent_window;
hr = ui_automation->ElementFromHandle(top_level_window_handle,
&parent_window);
if (SUCCEEDED(hr)) {
CComPtr<IUIAutomationWindowPattern> window_pattern;
hr = parent_window->GetCurrentPatternAs(UIA_WindowPatternId,
IID_PPV_ARGS(&window_pattern));
if (SUCCEEDED(hr)) {
BOOL is_topmost;
hr = window_pattern->get_CurrentIsTopmost(&is_topmost);
WindowVisualState visual_state;
hr = window_pattern->get_CurrentWindowVisualState(&visual_state);
if (visual_state == WindowVisualState::WindowVisualState_Maximized ||
visual_state == WindowVisualState::WindowVisualState_Normal) {
parent_window->SetFocus();
window_pattern->SetWindowVisualState(visual_state);
}
}
}
}
}

foreground_window = ::GetAncestor(::GetForegroundWindow(), GA_ROOT);
if (foreground_window != top_level_window_handle) {
HWND content_window_handle = this->GetContentWindowHandle();
LOG(TRACE) << "Top-level IE window is " << top_level_window_handle
<< " foreground window is " << foreground_window;
LOG(TRACE) << "Window still not in foreground; "
<< "attempting to use SetForegroundWindow API";
UINT_PTR lock_timeout = 0;
DWORD process_id = 0;
DWORD thread_id = ::GetWindowThreadProcessId(top_level_window_handle,
&process_id);
DWORD current_thread_id = ::GetCurrentThreadId();
DWORD current_process_id = ::GetCurrentProcessId();
if (current_thread_id != thread_id) {
::AttachThreadInput(current_thread_id, thread_id, TRUE);
::SystemParametersInfo(SPI_GETFOREGROUNDLOCKTIMEOUT,
0,
&lock_timeout,
0);
::SystemParametersInfo(SPI_SETFOREGROUNDLOCKTIMEOUT,
0,
0,
SPIF_SENDWININICHANGE | SPIF_UPDATEINIFILE);
HookSettings hook_settings;
hook_settings.hook_procedure_name = "AllowSetForegroundProc";
hook_settings.hook_procedure_type = WH_CALLWNDPROC;
hook_settings.window_handle = content_window_handle;
hook_settings.communication_type = OneWay;

HookProcessor hook;
if (!hook.CanSetWindowsHook(content_window_handle)) {
LOG(WARN) << "Setting window focus may fail because driver and browser "
<< "are not the same bit-ness.";
return false;
}
hook.Initialize(hook_settings);
::SendMessage(content_window_handle,
WD_ALLOW_SET_FOREGROUND,
NULL,
NULL);
hook.Dispose();
}
::SetForegroundWindow(top_level_window_handle);
::Sleep(100);
if (current_thread_id != thread_id) {
::SystemParametersInfo(SPI_SETFOREGROUNDLOCKTIMEOUT,
0,
reinterpret_cast<void*>(lock_timeout),
SPIF_SENDWININICHANGE | SPIF_UPDATEINIFILE);
::AttachThreadInput(current_thread_id, thread_id, FALSE);
}
}
foreground_window = ::GetAncestor(::GetForegroundWindow(), GA_ROOT);
return foreground_window == top_level_window_handle;
}


} // namespace webdriver

#ifdef __cplusplus
Expand All @@ -458,6 +554,17 @@ LRESULT CALLBACK ProtectedModeWndProc(int nCode, WPARAM wParam, LPARAM lParam) {
return ::CallNextHookEx(NULL, nCode, wParam, lParam);
}

LRESULT CALLBACK AllowSetForegroundProc(int nCode, WPARAM wParam, LPARAM lParam) {
if ((nCode == HC_ACTION) && (wParam == PM_REMOVE)) {
MSG* msg = reinterpret_cast<MSG*>(lParam);
if (msg->message == WD_ALLOW_SET_FOREGROUND) {
::AllowSetForegroundWindow(ASFW_ANY);
}
}

return CallNextHookEx(NULL, nCode, wParam, lParam);
}

#ifdef __cplusplus
}
#endif
1 change: 1 addition & 0 deletions cpp/iedriver/DocumentHost.h
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ class DocumentHost {
int SetFocusedFrameByName(const std::string& frame_name);
int SetFocusedFrameByElement(IHTMLElement* frame_element);
void SetFocusedFrameToParent(void);
bool SetFocusToBrowser(void);

bool wait_required(void) const { return this->wait_required_; }
void set_wait_required(const bool value) { this->wait_required_ = value; }
Expand Down
1 change: 1 addition & 0 deletions cpp/iedriver/IECommandExecutor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1376,6 +1376,7 @@ int IECommandExecutor::CreateNewBrowser(std::string* error_message) {
if (is_busy) {
LOG(WARN) << "Browser was launched and attached to, but is still busy.";
}
wrapper->SetFocusToBrowser();
return WD_SUCCESS;
}

Expand Down
1 change: 1 addition & 0 deletions cpp/iedriver/IEDriver.def
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@ EXPORTS
CookieWndProc @4
GetMessageProc @5
ProtectedModeWndProc @6
AllowSetForegroundProc @7
8 changes: 4 additions & 4 deletions cpp/iedriver/IEDriver.rc
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,8 @@ END
//

VS_VERSION_INFO VERSIONINFO
FILEVERSION 3,141,59,1
PRODUCTVERSION 3,141,59,1
FILEVERSION 3,141,59,2
PRODUCTVERSION 3,141,59,2
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
Expand All @@ -68,12 +68,12 @@ BEGIN
BEGIN
VALUE "CompanyName", "Software Freedom Conservancy"
VALUE "FileDescription", "Driver library for the IE driver"
VALUE "FileVersion", "3.141.59.1"
VALUE "FileVersion", "3.141.59.2"
VALUE "InternalName", "IEDriver.dll"
VALUE "LegalCopyright", "Copyright (C) 2019"
VALUE "OriginalFilename", "IEDriver.dll"
VALUE "ProductName", "Selenium WebDriver"
VALUE "ProductVersion", "3.141.59.1"
VALUE "ProductVersion", "3.141.59.2"
END
END
BLOCK "VarFileInfo"
Expand Down
2 changes: 2 additions & 0 deletions cpp/iedriver/messages.h
Original file line number Diff line number Diff line change
Expand Up @@ -60,3 +60,5 @@
#define WD_BROWSER_REATTACH WM_APP + 39
#define WD_BEFORE_BROWSER_REATTACH WM_APP + 40
#define WD_IS_BROWSER_PROTECTED_MODE WM_APP + 41

#define WD_ALLOW_SET_FOREGROUND WM_APP + 42
6 changes: 6 additions & 0 deletions cpp/iedriverserver/CHANGELOG
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,12 @@ available via the project downloads page. Changes in "revision" field indicate
private releases checked into the prebuilts directory of the source tree, but
not made generally available on the downloads page.

v3.151.59.2
===========
* Slightly modified setting IE window to have focus when sending input.
This code only affects the browser when the requireWindowFocus
capability is set at session start.

v3.151.59.1
===========
* Added checking for max expiriation date in IE driver cookie handling.
Expand Down
8 changes: 4 additions & 4 deletions cpp/iedriverserver/IEDriverServer.rc
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,8 @@ END
//

VS_VERSION_INFO VERSIONINFO
FILEVERSION 3,141,59,1
PRODUCTVERSION 3,141,59,1
FILEVERSION 3,141,59,2
PRODUCTVERSION 3,141,59,2
FILEFLAGSMASK 0x3fL
#ifdef _DEBUG
FILEFLAGS 0x1L
Expand All @@ -68,12 +68,12 @@ BEGIN
BEGIN
VALUE "CompanyName", "Software Freedom Conservancy"
VALUE "FileDescription", "Command line server for the IE driver"
VALUE "FileVersion", "3.141.59.1"
VALUE "FileVersion", "3.141.59.2"
VALUE "InternalName", "IEDriverServer.exe"
VALUE "LegalCopyright", "Copyright (C) 2019"
VALUE "OriginalFilename", "IEDriverServer.exe"
VALUE "ProductName", "Selenium WebDriver"
VALUE "ProductVersion", "3.141.59.1"
VALUE "ProductVersion", "3.141.59.2"
END
END
BLOCK "VarFileInfo"
Expand Down
Binary file modified cpp/prebuilt/Win32/Release/IEDriverServer.exe
Binary file not shown.
Binary file modified cpp/prebuilt/x64/Release/IEDriverServer.exe
Binary file not shown.

0 comments on commit c346167

Please sign in to comment.