Files
coco df489d5640 a
2026-07-03 16:05:30 +08:00

1139 lines
30 KiB
C++

#define WIN32_LEAN_AND_MEAN
#if !defined(_WIN32_WINNT) || (_WIN32_WINNT < 0x501)
#undef _WIN32_WINNT
#define _WIN32_WINNT 0x501
#endif
#define _CRT_SECURE_NO_WARNINGS 1
#include "Resource.h"
#include "../wke.h"
#include "RenderGDI.h"
#include <windows.h>
#include <windowsx.h>
#include <stdio.h>
#include <malloc.h>
#include <memory.h>
#include <tchar.h>
#include <time.h>
#include <stdlib.h>
#include <ShellAPI.h>
class CTimer {
public:
void Start()
{
QueryPerformanceCounter(&m_StartCounter);
}
void End()
{
QueryPerformanceCounter(&m_EndCounter);
}
unsigned int GetCounter()
{
return m_EndCounter.LowPart - m_StartCounter.LowPart;
}
unsigned int GetTime()
{
LARGE_INTEGER freq;
QueryPerformanceFrequency(&freq);
return unsigned int((long double)(m_EndCounter.QuadPart - m_StartCounter.QuadPart) / (long double)freq.QuadPart * 1000.f);
}
private:
LARGE_INTEGER m_StartCounter;
LARGE_INTEGER m_EndCounter;
};
#define MAX_LOADSTRING 100
#define URLBAR_HEIGHT 24
HINSTANCE hInst;
HWND hMainWnd;
HWND hURLBarWnd = NULL;
HWND hViewWindow = NULL;
TCHAR szTitle[MAX_LOADSTRING] = L"wkeBrowserTitle";
WCHAR szWindowClass[] = L"wkeBrowserDemo";
wkeWebView g_webView = NULL;
CRenderGDI* g_render = NULL;
int g_cursorInfoType = 0;
ATOM myRegisterClass(HINSTANCE hInstance);
BOOL initInstance(HINSTANCE, int);
LRESULT CALLBACK wndProc(HWND, UINT, WPARAM, LPARAM);
INT_PTR CALLBACK about(HWND, UINT, WPARAM, LPARAM);
WNDPROC DefEditProc = NULL;
LRESULT CALLBACK urlEditProc(HWND, UINT, WPARAM, LPARAM);
void resizeSubViews();
LRESULT CALLBACK webViewWndProc(HWND, UINT, WPARAM, LPARAM);
const LPCWSTR wkeWebViewClassName = L"wkeWebView*";
bool registerWebViewWindowClass();
jsValue JS_CALL jsMsgBox(jsExecState es)
{
wchar_t text[1025] = { 0 };
wcsncpy(text, jsToTempStringW(es, jsArg(es, 0)), 1024);
wchar_t title[1025] = { 0 };
wcsncpy(title, jsToTempStringW(es, jsArg(es, 1)), 1024);
MessageBoxW(hMainWnd, text, title, MB_OK);
return jsUndefined();
}
static int s_testCount = 0;
jsValue JS_CALL jsGetTestCount(jsExecState es)
{
return jsInt(s_testCount);
}
jsValue JS_CALL jsSetTestCount(jsExecState es)
{
s_testCount = jsToInt(es, jsArg(es, 0));
return jsUndefined();
}
void onTitleChanged(wkeWebView webView, void* param, const wkeString title)
{
SetWindowTextW(hMainWnd, wkeGetStringW(title));
}
void onURLChanged(wkeWebView webView, void* param, const wkeString url)
{
SetWindowTextW(hURLBarWnd, wkeGetStringW(url));
}
bool onNavigation(wkeWebView webView, void* param, wkeNavigationType type, const wkeString urlStr)
{
const wchar_t* url = wkeGetStringW(urlStr);
if (wcsstr(url, L"exec://") == url) {
PROCESS_INFORMATION processInfo = { 0 };
STARTUPINFOW startupInfo = { 0 };
startupInfo.cb = sizeof(startupInfo);
BOOL succeeded = CreateProcessW(NULL, (LPWSTR)url + 7, NULL, NULL, FALSE, 0, NULL, NULL, &startupInfo, &processInfo);
if (succeeded) {
CloseHandle(processInfo.hProcess);
CloseHandle(processInfo.hThread);
}
return false;
}
return true;
}
wkeWebView onBrowserCreateView(wkeWebView webView, void* param, wkeNavigationType navType, const wkeString urlStr, const wkeWindowFeatures* features)
{
const wchar_t* url = wkeGetStringW(urlStr);
wkeWebView newWindow = wkeCreateWebWindow(WKE_WINDOW_TYPE_POPUP, NULL, features->x, features->y, features->width, features->height);
wkeShowWindow(newWindow, true);
return newWindow;
}
const wchar_t* messageSourceName(int i)
{
const wchar_t* s_names[] = {
L"html",
L"xml",
L"js",
L"network",
L"console",
L"other"
};
return s_names[i];
}
const wchar_t* messageTypeName(int i)
{
const wchar_t* s_names[] = {
L"log",
L"dir",
L"dir-xml",
L"trace",
L"start-group",
L"start-group-collapsed",
L"end-group",
L"assert"
};
return s_names[i];
}
const wchar_t* messageLevelName(int i)
{
const wchar_t* s_names[] = {
L"tip",
L"log",
L"warning",
L"error",
L"debug"
};
return s_names[i];
}
FILE* g_consoleLog = NULL;
void onConsoleMessage(wkeWebView webView, void* param, wkeConsoleLevel level, const wkeString message, const wkeString sourceName, unsigned sourceLine, const wkeString stackTrace)
{
const utf8* msg = wkeToString(message);
}
/*
## 测试绑定对象功能
运行wkeWebBrowser.exe,在地址栏输入`inject`回车,即可注册JS对象`test`,注册后就JS中可访问`test`对象的成员变量`value`和成员函数`msgbox`了。
在地址栏输入`javascript:test.msgbox('1')`测试调用成员函数。
在地址栏输入`javascript:document.write(test.value)`测试访问成员变量。
*/
struct BindTestFunction {
static jsValue js_callAsFunction(jsExecState es, jsValue object, jsValue* args, int argCount)
{
wchar_t text[1025] = { 0 };
wchar_t title[1025] = { 0 };
if (argCount >= 1)
wcsncpy(text, jsToTempStringW(es, jsArg(es, 0)), 1024);
if (argCount >= 2)
wcsncpy(title, jsToTempStringW(es, jsArg(es, 1)), 1024);
MessageBoxW(NULL, text, title[0] ? title : NULL, MB_OK);
return jsInt(0);
}
static void js_releaseFunction(jsData* data)
{
delete data;
}
static void bindToGlobal(jsExecState es)
{
jsData* data = new jsData();
memset(data, 0, sizeof(jsData));
strcpy(data->typeName, "Function");
data->callAsFunction = js_callAsFunction;
data->finalize = js_releaseFunction;
jsValue func = jsFunction(es, data);
jsSetGlobal(es, "popup", func);
}
static void bindToObject(jsExecState es, jsValue obj)
{
jsData* data = new jsData();
memset(data, 0, sizeof(jsData));
strcpy(data->typeName, "Function");
data->callAsFunction = js_callAsFunction;
data->finalize = js_releaseFunction;
jsValue func = jsFunction(es, data);
jsSet(es, obj, "popup", func);
}
};
class BindTestObject : public jsData {
public:
BindTestObject()
: m_value(0)
{
jsData* data = this;
memset(data, 0, sizeof(jsData));
strcpy(data->typeName, "Object");
data->propertyGet = js_getObjectProp;
data->propertySet = js_setObjectProp;
data->finalize = js_releaseObject;
}
void msgbox(const wchar_t* msg, const wchar_t* title)
{
MessageBoxW(NULL, msg, title, MB_OK);
}
protected:
static bool js_setObjectProp(jsExecState es, jsValue object, const char* propertyName, jsValue value)
{
BindTestObject* pthis = (BindTestObject*)jsGetData(es, object);
if (strcmp(propertyName, "value") == 0)
return pthis->m_value = jsToInt(es, value), true;
else
return false;
}
static void js_releaseObject(jsData* data)
{
BindTestObject* pthis = (BindTestObject*)data;
delete pthis;
}
class BindTestMsgbox : public jsData {
public:
BindTestMsgbox(BindTestObject* obj)
{
jsData* data = this;
memset(data, 0, sizeof(jsData));
strcpy(data->typeName, "Function");
data->callAsFunction = js_callAsFunction;
data->finalize = js_releaseFunction;
m_obj = obj;
}
protected:
static void js_releaseFunction(jsData* data)
{
BindTestMsgbox* pthis = (BindTestMsgbox*)data;
delete pthis;
}
static jsValue js_callAsFunction(jsExecState es, jsValue object, jsValue* args, int argCount)
{
BindTestMsgbox* pthis = (BindTestMsgbox*)jsGetData(es, object);
wchar_t text[1025] = { 0 };
wchar_t title[1025] = { 0 };
if (argCount >= 1)
wcsncpy(text, jsToTempStringW(es, jsArg(es, 0)), 1024);
if (argCount >= 2)
wcsncpy(title, jsToTempStringW(es, jsArg(es, 1)), 1024);
pthis->m_obj->msgbox(text, title[0] ? title : NULL);
return jsInt(0);
}
protected:
BindTestObject* m_obj;
};
static jsValue js_getObjectProp(jsExecState es, jsValue object, const char* propertyName)
{
BindTestObject* pthis = (BindTestObject*)jsGetData(es, object);
if (strcmp(propertyName, "value") == 0)
return jsInt(pthis->m_value);
else if (strcmp(propertyName, "msgbox") == 0) {
return jsFunction(es, new BindTestMsgbox(pthis));
} else
return jsUndefined();
}
protected:
int m_value;
};
void onPaintUpdatedCallback(wkeWebView webView, void* param, const HDC hdc, int x, int y, int cx, int cy)
{
g_render->renderOnBlinkPaint(g_webView, hdc, x, y, cx, cy);
}
ATOM myRegisterClass(HINSTANCE hInstance)
{
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, MAKEINTRESOURCE(IDI_WKEBROWSER));
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
wcex.lpszMenuName = MAKEINTRESOURCE(IDC_WKEBROWSER);
wcex.lpszClassName = szWindowClass;
wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));
return RegisterClassEx(&wcex);
}
BOOL initInstance(HINSTANCE hInstance, int nCmdShow)
{
hInst = hInstance;
hMainWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);
if (!hMainWnd)
return FALSE;
ShowWindow(hMainWnd, nCmdShow);
UpdateWindow(hMainWnd);
return TRUE;
}
static int s_currentZoom = 100;
static int s_zoomLevels[] = { 30, 50, 67, 80, 90, 100, 110, 120, 133, 150, 170, 200, 240, 300 };
void zoom(bool zoomIn)
{
if (!g_webView)
return;
int count = sizeof(s_zoomLevels) / sizeof(int);
int i = 0;
for (i = 0; i < count; ++i) {
if (s_zoomLevels[i] == s_currentZoom)
break;
}
if (zoomIn)
i = i + 1;
else
i = i - 1;
if (i < 0)
i = 0;
if (i >= count)
i = count - 1;
s_currentZoom = s_zoomLevels[i];
wkeSetZoomFactor(g_webView, s_currentZoom / 100.f);
}
void resetZoom()
{
s_currentZoom = 100;
if (g_webView)
wkeSetZoomFactor(g_webView, s_currentZoom / 100.f);
}
void convertFilename(wchar_t* filename)
{
int i;
for (i = 0; filename[i]; ++i) {
if (filename[i] == L'\\'
|| filename[i] == L'/'
|| filename[i] == L':'
|| filename[i] == L'*'
|| filename[i] == L'?'
|| filename[i] == L'\"'
|| filename[i] == L'<'
|| filename[i] == L'>'
|| filename[i] == L'|') {
filename[i] = L'_';
}
}
}
void saveBitmap(void* pixels, int w, int h, const wchar_t* title)
{
BITMAPFILEHEADER fileHdr = { 0 };
BITMAPINFOHEADER infoHdr = { 0 };
FILE * fp = NULL;
fileHdr.bfType = 0x4d42; //'BM'
fileHdr.bfOffBits = sizeof(fileHdr) + sizeof(infoHdr);
fileHdr.bfSize = w * h * 4 + fileHdr.bfOffBits;
infoHdr.biSize = sizeof(BITMAPINFOHEADER);
infoHdr.biWidth = w;
infoHdr.biHeight = -h;
infoHdr.biPlanes = 1;
infoHdr.biBitCount = 32;
infoHdr.biCompression = 0;
infoHdr.biSizeImage = w * h * 4;
infoHdr.biXPelsPerMeter = 3780;
infoHdr.biYPelsPerMeter = 3780;
struct tm t;
time_t utc_time;
time(&utc_time);
localtime_s(&t, &utc_time);
wchar_t name[1024];
swprintf(name, 1024, L"%s_%4d%02d%02d_%02d%02d%02d.bmp", title,
t.tm_year + 1900, t.tm_mon + 1, t.tm_mday, t.tm_hour, t.tm_min, t.tm_sec);
convertFilename(name);
wchar_t pathname[1024];
swprintf(pathname, 1024, L"screenshots\\%s", name);
_wmkdir(L"screenshots");
_wfopen_s(&fp, pathname, L"wb");
if (fp == NULL)
return;
fwrite(&fileHdr, sizeof(fileHdr), 1, fp);
fwrite(&infoHdr, sizeof(infoHdr), 1, fp);
fwrite(pixels, infoHdr.biSizeImage, 1, fp);
fclose(fp);
}
void takeScreenshot()
{
if (g_webView == NULL)
return;
wkeRunJS(g_webView, "document.body.style.overflow='hidden'");
int w = wkeGetContentWidth(g_webView);
int h = wkeGetContentHeight(g_webView);
int oldwidth = wkeGetWidth(g_webView);
int oldheight = wkeGetHeight(g_webView);
wkeResize(g_webView, w, h);
wkeUpdate();
void* pixels = malloc(w * h * 4);
wkePaint(g_webView, pixels, 0);
//save bitmap
saveBitmap(pixels, w, h, wkeGetTitleW(g_webView));
free(pixels);
wkeResize(g_webView, oldwidth, oldheight);
wkeRunJS(g_webView, "document.body.style.overflow='visible'");
}
void viewCookie()
{
if (g_webView == NULL)
return;
const wchar_t* cookie = wkeGetCookieW(g_webView);
MessageBoxW(NULL, cookie, L"Cookie", MB_OK | MB_ICONINFORMATION);
}
LRESULT CALLBACK wndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
int wmId, wmEvent;
PAINTSTRUCT ps;
HDC hdc;
switch (message) {
case WM_COMMAND:
wmId = LOWORD(wParam);
wmEvent = HIWORD(wParam);
switch (wmId) {
case IDM_ABOUT:
DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, about);
break;
case IDM_MB_SIMPLE:
break;
case ID_FILE_GOBACK:
if (g_webView)
wkeGoBack(g_webView);
break;
case ID_FILE_GOFORWARD:
if (g_webView)
wkeGoForward(g_webView);
break;
case ID_ZOOM_IN:
zoom(true);
break;
case ID_ZOOM_OUT:
zoom(false);
break;
case ID_RESET_ZOOM:
resetZoom();
break;
case ID_TAKE_SCREENSHOT:
takeScreenshot();
break;
case ID_TOOLS_VIEWCOOKIE:
viewCookie();
break;
case ID_SET_EDITABLE:
if (g_webView) {
HMENU hMenu = GetMenu(hWnd);
UINT state = GetMenuState(hMenu, ID_SET_EDITABLE, MF_BYCOMMAND);
if (state & MF_CHECKED) {
wkeSetEditable(g_webView, false);
CheckMenuItem(hMenu, ID_SET_EDITABLE, MF_BYCOMMAND | MF_UNCHECKED);
} else {
wkeSetEditable(g_webView, true);
CheckMenuItem(hMenu, ID_SET_EDITABLE, MF_BYCOMMAND | MF_CHECKED);
}
}
break;
case ID_URL_SF:
SetWindowText(hURLBarWnd, L"http://miniblink.net");
SendMessage(hURLBarWnd, WM_CHAR, L'\r', 0);
break;
case ID_URL_GITHUB:
SetWindowText(hURLBarWnd, L"http://www.github.com/weolar/miniblink49");
SendMessage(hURLBarWnd, WM_CHAR, L'\r', 0);
break;
case IDM_EXIT:
DestroyWindow(hWnd);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
break;
case WM_INITMENU:
{
bool canGoBack = false;
bool canGoForward = false;
if (g_webView && wkeCanGoBack(g_webView))
canGoBack = true;
if (g_webView && wkeCanGoForward(g_webView))
canGoForward = true;
EnableMenuItem((HMENU)wParam, ID_FILE_GOBACK, canGoBack ? MF_ENABLED : MF_DISABLED);
EnableMenuItem((HMENU)wParam, ID_FILE_GOFORWARD, canGoForward ? MF_ENABLED : MF_DISABLED);
}
break;
case WM_PAINT:
hdc = BeginPaint(hWnd, &ps);
EndPaint(hWnd, &ps);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
case WM_SIZE:
resizeSubViews();
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
INT_PTR CALLBACK about(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
UNREFERENCED_PARAMETER(lParam);
switch (message) {
case WM_INITDIALOG:
{
}
return (INT_PTR)TRUE;
case WM_COMMAND:
if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL) {
EndDialog(hDlg, LOWORD(wParam));
return (INT_PTR)TRUE;
}
break;
}
return (INT_PTR)FALSE;
}
void onCursorChange()
{
g_cursorInfoType = wkeGetCursorInfoType(g_webView);
}
bool setCursorInfoTypeByCache(HWND hWnd)
{
RECT rc;
::GetClientRect(hWnd, &rc);
POINT pt;
::GetCursorPos(&pt);
::ScreenToClient(hWnd, &pt);
if (!::PtInRect(&rc, pt))
return false;
HCURSOR hCur = NULL;
switch (g_cursorInfoType) {
case WkeCursorInfoPointer:
hCur = ::LoadCursor(NULL, IDC_ARROW);
break;
case WkeCursorInfoIBeam:
hCur = ::LoadCursor(NULL, IDC_IBEAM);
break;
case WkeCursorInfoHand:
hCur = ::LoadCursor(NULL, IDC_HAND);
break;
case WkeCursorInfoWait:
hCur = ::LoadCursor(NULL, IDC_WAIT);
break;
case WkeCursorInfoHelp:
hCur = ::LoadCursor(NULL, IDC_HELP);
break;
case WkeCursorInfoEastResize:
hCur = ::LoadCursor(NULL, IDC_SIZEWE);
break;
case WkeCursorInfoNorthResize:
hCur = ::LoadCursor(NULL, IDC_SIZENS);
break;
case WkeCursorInfoSouthWestResize:
case WkeCursorInfoNorthEastResize:
hCur = ::LoadCursor(NULL, IDC_SIZENESW);
break;
case WkeCursorInfoSouthResize:
case WkeCursorInfoNorthSouthResize:
hCur = ::LoadCursor(NULL, IDC_SIZENS);
break;
case WkeCursorInfoNorthWestResize:
case WkeCursorInfoSouthEastResize:
hCur = ::LoadCursor(NULL, IDC_SIZENWSE);
break;
case WkeCursorInfoWestResize:
case WkeCursorInfoEastWestResize:
hCur = ::LoadCursor(NULL, IDC_SIZEWE);
break;
case WkeCursorInfoNorthEastSouthWestResize:
case WkeCursorInfoNorthWestSouthEastResize:
hCur = ::LoadCursor(NULL, IDC_SIZEALL);
break;
default:
hCur = ::LoadCursor(NULL, IDC_ARROW);
break;
}
if (hCur) {
::SetCursor(hCur);
return true;
}
return false;
}
LRESULT CALLBACK webViewWndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
bool handled = true;
switch (message) {
//cexer 增加拖放加载
case WM_CREATE:
DragAcceptFiles(hWnd, TRUE);
return 0;
case WM_SETCURSOR:
if (setCursorInfoTypeByCache(hWnd))
return 0;
break;
case WM_DROPFILES:
{
if (g_webView) {
wchar_t szFile[MAX_PATH + 8] = { 0 };
wcscpy(szFile, L"file:///");
HDROP hDrop = reinterpret_cast<HDROP>(wParam);
UINT uFilesCount = DragQueryFileW(hDrop, 0xFFFFFFFF, szFile, MAX_PATH);
if (uFilesCount != 0) {
UINT uRet = DragQueryFileW(hDrop, 0, (wchar_t*)szFile + 8, MAX_PATH);
if (uRet != 0) {
wkeLoadURLW(g_webView, szFile);
SetWindowTextW(hWnd, szFile);
}
}
DragFinish(hDrop);
}
}
return 0;
case WM_COMMAND:
SendMessage(GetParent(hWnd), message, wParam, lParam);
return 0;
case WM_SIZE:
if (g_webView && g_render) {
wkeResize(g_webView, LOWORD(lParam), HIWORD(lParam));
g_render->resize(LOWORD(lParam), HIWORD(lParam));
}
break;
case WM_PAINT:
PAINTSTRUCT paintInfo;
BeginPaint(hWnd, &paintInfo);
g_render->renderOnWindowPaint(g_webView, paintInfo.hdc);
EndPaint(hWnd, &paintInfo);
break;
case WM_KEYDOWN:
{
unsigned int virtualKeyCode = wParam;
unsigned int flags = 0;
if (HIWORD(lParam) & KF_REPEAT)
flags |= WKE_REPEAT;
if (HIWORD(lParam) & KF_EXTENDED)
flags |= WKE_EXTENDED;
handled = wkeFireKeyDownEvent(g_webView, virtualKeyCode, flags, false);
}
break;
case WM_KEYUP:
{
unsigned int virtualKeyCode = wParam;
unsigned int flags = 0;
if (HIWORD(lParam) & KF_REPEAT)
flags |= WKE_REPEAT;
if (HIWORD(lParam) & KF_EXTENDED)
flags |= WKE_EXTENDED;
handled = wkeFireKeyUpEvent(g_webView, virtualKeyCode, flags, false);
}
break;
case WM_CHAR:
{
unsigned int charCode = wParam;
unsigned int flags = 0;
if (HIWORD(lParam) & KF_REPEAT)
flags |= WKE_REPEAT;
if (HIWORD(lParam) & KF_EXTENDED)
flags |= WKE_EXTENDED;
handled = wkeFireKeyPressEvent(g_webView, charCode, flags, false);
}
break;
case WM_LBUTTONDOWN:
case WM_MBUTTONDOWN:
case WM_RBUTTONDOWN:
case WM_LBUTTONDBLCLK: //
case WM_MBUTTONDBLCLK:
case WM_RBUTTONDBLCLK:
case WM_LBUTTONUP:
case WM_MBUTTONUP:
case WM_RBUTTONUP:
case WM_MOUSEMOVE:
{
onCursorChange();
if (message == WM_LBUTTONDOWN || message == WM_MBUTTONDOWN || message == WM_RBUTTONDOWN) {
SetFocus(hWnd);
SetCapture(hWnd);
} else if (message == WM_LBUTTONUP || message == WM_MBUTTONUP || message == WM_RBUTTONUP) {
ReleaseCapture();
}
int x = GET_X_LPARAM(lParam);
int y = GET_Y_LPARAM(lParam);
unsigned int flags = 0;
if (wParam & MK_CONTROL)
flags |= WKE_CONTROL;
if (wParam & MK_SHIFT)
flags |= WKE_SHIFT;
if (wParam & MK_LBUTTON)
flags |= WKE_LBUTTON;
if (wParam & MK_MBUTTON)
flags |= WKE_MBUTTON;
if (wParam & MK_RBUTTON)
flags |= WKE_RBUTTON;
//flags = wParam;
handled = wkeFireMouseEvent(g_webView, message, x, y, flags);
}
break;
case WM_CONTEXTMENU:
{
POINT pt;
pt.x = GET_X_LPARAM(lParam);
pt.y = GET_Y_LPARAM(lParam);
if (pt.x != -1 && pt.y != -1)
ScreenToClient(hWnd, &pt);
unsigned int flags = 0;
if (wParam & MK_CONTROL)
flags |= WKE_CONTROL;
if (wParam & MK_SHIFT)
flags |= WKE_SHIFT;
if (wParam & MK_LBUTTON)
flags |= WKE_LBUTTON;
if (wParam & MK_MBUTTON)
flags |= WKE_MBUTTON;
if (wParam & MK_RBUTTON)
flags |= WKE_RBUTTON;
handled = wkeFireContextMenuEvent(g_webView, pt.x, pt.y, flags);
}
break;
case WM_MOUSEWHEEL:
{
POINT pt;
pt.x = GET_X_LPARAM(lParam);
pt.y = GET_Y_LPARAM(lParam);
ScreenToClient(hWnd, &pt);
int delta = GET_WHEEL_DELTA_WPARAM(wParam);
unsigned int flags = 0;
if (wParam & MK_CONTROL)
flags |= WKE_CONTROL;
if (wParam & MK_SHIFT)
flags |= WKE_SHIFT;
if (wParam & MK_LBUTTON)
flags |= WKE_LBUTTON;
if (wParam & MK_MBUTTON)
flags |= WKE_MBUTTON;
if (wParam & MK_RBUTTON)
flags |= WKE_RBUTTON;
//flags = wParam;
handled = wkeFireMouseWheelEvent(g_webView, pt.x, pt.y, delta, flags);
}
break;
case WM_SETFOCUS:
wkeSetFocus(g_webView);
break;
case WM_KILLFOCUS:
wkeKillFocus(g_webView);
break;
case WM_IME_STARTCOMPOSITION:
{
wkeRect caret = wkeGetCaretRect(g_webView);
CANDIDATEFORM form;
form.dwIndex = 0;
form.dwStyle = CFS_EXCLUDE;
form.ptCurrentPos.x = caret.x;
form.ptCurrentPos.y = caret.y + caret.h;
form.rcArea.top = caret.y;
form.rcArea.bottom = caret.y + caret.h;
form.rcArea.left = caret.x;
form.rcArea.right = caret.x + caret.w;
HIMC hIMC = ImmGetContext(hWnd);
ImmSetCandidateWindow(hIMC, &form);
ImmReleaseContext(hWnd, hIMC);
}
break;
default:
handled = false;
break;
}
if (!handled)
return DefWindowProc(hWnd, message, wParam, lParam);
return 0;
}
void resizeSubViews()
{
if (hURLBarWnd && hViewWindow) {
RECT rcClient;
GetClientRect(hMainWnd, &rcClient);
MoveWindow(hURLBarWnd, 0, 0, rcClient.right, URLBAR_HEIGHT, TRUE);
MoveWindow(hViewWindow, 0, URLBAR_HEIGHT, rcClient.right, rcClient.bottom - URLBAR_HEIGHT, TRUE);
wkeResize(g_webView, rcClient.right, rcClient.bottom - URLBAR_HEIGHT);
}
}
bool registerWebViewWindowClass()
{
WNDCLASSEX wcex;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_DBLCLKS;// CS_HREDRAW | CS_VREDRAW; //
wcex.lpfnWndProc = webViewWndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = hInst;
wcex.hIcon = 0;
wcex.hCursor = LoadCursor(0, IDC_ARROW);
wcex.hbrBackground = 0;
wcex.lpszMenuName = 0;
wcex.lpszClassName = wkeWebViewClassName;
wcex.hIconSm = 0;
return !!RegisterClassEx(&wcex);
}
#define MAX_URL_LENGTH 1024
LRESULT CALLBACK urlEditProc(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)
{
if (message == WM_CHAR && wParam == 13) //Enter Key
{
wchar_t url[MAX_URL_LENGTH] = { 0 };
*((LPWORD)url) = MAX_URL_LENGTH;
int len = SendMessage(hDlg, EM_GETLINE, 0, (LPARAM)url);
if (len == 0)
return 0;
if (wcsstr(url, L"inject") == url) {
//jsObjectData* data = new jsObjectData();
// memset(data, 0, sizeof(jsObjectData));
// strcpy(data->typeName, "Test");
// data->propertyGet = js_getObjectProp;
// data->propertySet = js_setObjectProp;
// data->finalize = js_releaseObject;
BindTestObject* testObj = new BindTestObject();
jsExecState es = wkeGlobalExec(g_webView);
jsValue obj = jsObject(es, testObj);
jsSetGlobal(es, "test", obj);
BindTestFunction::bindToGlobal(es);
} else if (wcsstr(url, L"javascript:") == url) {
url[len] = L'\0';
wkeRunJSW(g_webView, url + wcslen(L"javascript:"));
} else if (wcsstr(url, L"call") == url) {
jsExecState es = wkeGlobalExec(g_webView);
jsValue jsDocument = jsGet(es, jsGlobalObject(es), "document");
{
char prop[10] = { 0 };
strcpy(prop, "URL");
jsValue jsUrl = jsGet(es, jsDocument, prop);
MessageBoxW(NULL, jsToTempStringW(es, jsUrl), NULL, MB_OK);
}
{
char prop[10] = { 0 };
strcpy(prop, "title");
jsValue jsTitle = jsGet(es, jsDocument, prop);
MessageBoxW(NULL, jsToTempStringW(es, jsTitle), NULL, MB_OK);
}
{
char prop[10] = { 0 };
strcpy(prop, "cookie");
jsValue jsCookie = jsGet(es, jsDocument, prop);
MessageBoxW(NULL, jsToTempStringW(es, jsCookie), NULL, MB_OK);
}
} else {
url[len] = L'\0';
wkeLoadURLW(g_webView, url);
SetFocus(hViewWindow);
}
return 0;
}
return (LRESULT)CallWindowProc((WNDPROC)DefEditProc, hDlg, message, wParam, lParam);
}
int APIENTRY wkeBrowserMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
UNREFERENCED_PARAMETER(hPrevInstance);
UNREFERENCED_PARAMETER(lpCmdLine);
myRegisterClass(hInstance);
if (!initInstance(hInstance, nCmdShow))
return 0;
CTimer t1, t2, t3;
wkeInitialize();
t1.Start();
wkeSettings settings;
memset(&settings, 0, sizeof(settings));
#if defined(WKE_BROWSER_USE_LOCAL_PROXY)
settings.proxy.type = WKE_PROXY_SOCKS5;
strcpy(settings.proxy.hostname, "127.0.0.1");
settings.proxy.port = 1080;
settings.mask |= WKE_SETTING_PROXY;
#endif
wkeConfigure(&settings);
t1.End();
jsBindFunction("msgBox", jsMsgBox, 2);
jsBindGetter("testCount", jsGetTestCount);
jsBindSetter("testCount", jsSetTestCount);
t2.Start();
g_webView = wkeCreateWebView();
t2.End();
t3.Start();
wkeSetTransparent(g_webView, false);
wkeOnTitleChanged(g_webView, onTitleChanged, NULL);
wkeOnURLChanged(g_webView, onURLChanged, NULL);
wkeOnNavigation(g_webView, onNavigation, NULL);
wkeOnCreateView(g_webView, onBrowserCreateView, NULL);
wkeOnPaintUpdated(g_webView, onPaintUpdatedCallback, NULL);
if (g_consoleLog = fopen("wkeBrowserConsole.txt", "wb"))
fwrite("\xFF\xFE", 2, 1, g_consoleLog);
wkeOnConsole(g_webView, onConsoleMessage, NULL);
wkeSetUserAgent(g_webView, "Mozilla/5.0 (Windows NT 6.1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/69.0.2228.0 Safari/537.36");
int argc = 0;
LPWSTR* argv = CommandLineToArgvW(GetCommandLineW(), &argc);
if (argc > 1)
wkeLoadW(g_webView, argv[1]);
else {
//wkeLoadHTMLW(g_webView, L"<p style=\"background-color: #00FF00\">Testing</p><img id=\"webkit logo\" src=\"http://webkit.org/images/icon-gold.png\" alt=\"Face\"><div style=\"border: solid blue; background: white;\" contenteditable=\"true\">div with blue border</div><ul><li>foo<li>bar<li>baz</ul>");
wkeLoadURL(g_webView, "http://github.com/weolar/miniblink49");
}
LocalFree(argv);
t3.End();
unsigned int ms1 = t1.GetTime();
unsigned int ms2 = t2.GetTime();
unsigned int ms3 = t3.GetTime();
hURLBarWnd = CreateWindow(L"EDIT", 0,
WS_CHILD | WS_VISIBLE | WS_BORDER | ES_LEFT | ES_AUTOVSCROLL,
0, 0, 0, 0,
hMainWnd,
0,
hInstance, 0);
registerWebViewWindowClass();
hViewWindow = CreateWindow(wkeWebViewClassName, 0,
WS_CHILD | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN,
0, 0, 0, 0,
hMainWnd,
0,
hInstance, 0);
//有窗口句柄插件必须设置
wkeSetHandle(g_webView, hViewWindow);
resizeSubViews();
DefEditProc = reinterpret_cast<WNDPROC>(GetWindowLongPtr(hURLBarWnd, /*GWL_WNDPROC*/(-4)));
SetWindowLongPtr(hURLBarWnd, /*GWL_WNDPROC*/(-4), reinterpret_cast<LONG_PTR>(urlEditProc));
SetFocus(hURLBarWnd);
g_render = new CRenderGDI();
g_render->init(hViewWindow);
return 0;
}