I am having a very difficult time trying to focus the HTML window that WebView2 loads on startup. I've tried JS focusing from within the web document, Callbacking back and forth between the C interface and the HTML page - nothing seems to work. The window will only be focused when some 'action' occurs like an alert dialog popping up. I was hoping to leverage the power of C and integrate it into the lightweight native browser client, but right now it is proving to be rather difficult. Would really appreciate some insight as to why this is occuring. I have shared 2 pieces of code, one is that of the WebView2 implementation, and the other one is a sample html file that focuses in normal situations. Please do not forget to HTML path to your custom one, I have marked it out for your convenience.
Apologizing in advance for huge chunks of code, I am unaware if we are able to fold code here. Microsoft uses 12 lines to write one function prototype. Quite disorienting sometimes.
In case you do not use Visual Studio, I have made a script so that we are still able to compile and test the code (Run as .bat file):
@echo off
cl /EHsc /GR /FI"iso646.h" /Zc:strictStrings /we4627 /we4927 /wd4351 /W4 /D"_CRT_SECURE_NO_WARNINGS" /nologo /D_UNICODE /DUNICODE /DWIN32 /D_WINDOWS /c /Ipath\to\webview2\include /Ipath\to\winrt\include webweb.cpp&^
link webweb.obj WebView2Loader.dll.lib /subsystem:windows user32.lib&^
webweb.exe
pause
- Sample WebView2 code for testing.
#include <windows.h>
#include <stdlib.h>
#include <string>
#include <tchar.h>
#include <wrl.h>
#include <wil/com.h>
// include WebView2 header
#include "WebView2.h"
using namespace Microsoft::WRL;
// Global variables
// The main window class name.
static TCHAR szWindowClass[] = _T("DesktopApp");
// The string that appears in the application's title bar.
static TCHAR szTitle[] = _T("WebView sample");
HINSTANCE hInst;
// Forward declarations of functions included in this code module:
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
// Pointer to WebViewController
static wil::com_ptr<ICoreWebView2Controller> webviewController;
// Pointer to WebView window
static wil::com_ptr<ICoreWebView2> webviewWindow;
int CALLBACK WinMain(
_In_ HINSTANCE hInstance,
_In_ HINSTANCE hPrevInstance,
_In_ LPSTR lpCmdLine,
_In_ int nCmdShow
)
{
WNDCLASSEX wcex;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = WndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = hInstance;
wcex.hIcon = LoadIcon(hInstance, IDI_APPLICATION);
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW 1);
wcex.lpszMenuName = NULL;
wcex.lpszClassName = szWindowClass;
wcex.hIconSm = LoadIcon(wcex.hInstance, IDI_APPLICATION);
if (!RegisterClassEx(&wcex))
{
MessageBox(NULL,
_T("Call to RegisterClassEx failed!"),
_T("Windows Desktop Guided Tour"),
NULL);
return 1;
}
// Store instance handle in our global variable
hInst = hInstance;
int dispw = GetSystemMetrics(SM_CXSCREEN);
int disph = GetSystemMetrics(SM_CYSCREEN);
int windw = dispw / 2;
int windh = disph / 2;
int x = (dispw - windw) / 2;
int y = (disph - windh) / 2;
// The parameters to CreateWindow explained:
// szWindowClass: the name of the application
// szTitle: the text that appears in the title bar
// WS_OVERLAPPEDWINDOW: the type of window to create
// CW_USEDEFAULT, CW_USEDEFAULT: initial position (x, y)
// 500, 100: initial size (width, length)
// NULL: the parent of this window
// NULL: this application does not have a menu bar
// hInstance: the first parameter from WinMain
// NULL: not used in this application
HWND hWnd = CreateWindow(
szWindowClass,
szTitle,
WS_OVERLAPPEDWINDOW,
x, y,
windw, windh,
NULL,
NULL,
hInstance,
NULL
);
if (!hWnd)
{
MessageBox(NULL,
_T("Call to CreateWindow failed!"),
_T("Windows Desktop Guided Tour"),
NULL);
return 1;
}
// The parameters to ShowWindow explained:
// hWnd: the value returned from CreateWindow
// nCmdShow: the fourth parameter from WinMain
ShowWindow(hWnd,
nCmdShow);
UpdateWindow(hWnd);
// <-- WebView2 sample code starts here -->
// Step 3 - Create a single WebView within the parent window
// Locate the browser and set up the environment for WebView
CreateCoreWebView2EnvironmentWithOptions(nullptr, nullptr, nullptr,
Callback<ICoreWebView2CreateCoreWebView2EnvironmentCompletedHandler>(
[hWnd](HRESULT result, ICoreWebView2Environment* env) -> HRESULT {
// Create a CoreWebView2Controller and get the associated CoreWebView2 whose parent is the main window hWnd
env->CreateCoreWebView2Controller(hWnd, Callback<ICoreWebView2CreateCoreWebView2ControllerCompletedHandler>(
[hWnd](HRESULT result, ICoreWebView2Controller* controller) -> HRESULT {
if (controller != nullptr) {
webviewController = controller;
webviewController->get_CoreWebView2(&webviewWindow);
}
// Add a few settings for the webview
// The demo step is redundant since the values are the default settings
ICoreWebView2Settings* Settings;
webviewWindow->get_Settings(&Settings);
Settings->put_IsScriptEnabled(TRUE);
Settings->put_AreDefaultScriptDialogsEnabled(FALSE);
Settings->put_IsWebMessageEnabled(FALSE);
RECT bounds;
GetClientRect(hWnd, &bounds);
webviewController->put_Bounds(bounds);
webviewWindow->AddScriptToExecuteOnDocumentCreated(L"text.setValue('ayee');", NULL);
webviewWindow->Navigate(L"file:///path/to/test.html");
return S_OK;
}).Get());
return S_OK;
}).Get());
// <-- WebView2 sample code ends here -->
// Main message loop:
MSG msg;
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return (int)msg.wParam;
}
// FUNCTION: WndProc(HWND, UINT, WPARAM, LPARAM)
//
// PURPOSE: Processes messages for the main window.
//
// WM_DESTROY - post a quit message and return
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
TCHAR greeting[] = _T("Hello, Windows desktop!");
switch (message)
{
case WM_SIZE:
if (webviewController != nullptr) {
RECT bounds;
GetClientRect(hWnd, &bounds);
webviewController->put_Bounds(bounds);
};
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
break;
}
return 0;
}
- Sample HTML file for testing
<!DOCTYPE HTML>
<HTML>
<HEAD>
<STYLE>
body
{
display: flex;
width: 100vw;
overflow: none;
scrollbar: none;
align-items: center;
justify-content: center;
}
#textarea
{
width: 400px;
height: 400px;
resize: none;
overflow:auto;
}
</STYLE>
<TITLE>EXAMPLE</TITLE>
</HEAD>
<BODY>
<textarea ID="textpane"></textarea>
<SCRIPT>
var te = document.getElementById('textpane');
window.onload = function()
{
te.focus();
}
</SCRIPT>
</BODY>
</HTML>
CodePudding user response:
After sifting through Microsoft documentation, figured that we have to add:
webviewController->MoveFocus(COREWEBVIEW2_MOVE_FOCUS_REASON_PROGRAMMATIC);
For the WebView component to focust in and of itself. Otherwise, some message/ JS alert dialog has to be rendered along with the view, which will be focused after we have exited out of the rendered dialog window.
- Add after
Navigate()
method. - In some cases, might need to explicitly instruct component focus inside HTML as well. The aforementioned code only activates the WebView, the HTML must still decide which of its components get focus. The reason Win32 API window focus utilities won't work is because they deal with the native windows and will not interpret the inner WebView as such.
CodePudding user response:
The window.h library includes a winuser.h library That library have a SetActiveWindow function For details, here's the documentation:Winuser-SetActiveWindow
There's also the SetFocus function