mirror of
				https://bitbucket.org/chromiumembedded/cef
				synced 2025-06-05 21:39:12 +02:00 
			
		
		
		
	
		
			
				
	
	
		
			634 lines
		
	
	
		
			24 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			634 lines
		
	
	
		
			24 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| // Copyright 2015 The Chromium Embedded Framework Authors. All rights reserved.
 | |
| // Use of this source code is governed by a BSD-style license that can be
 | |
| // found in the LICENSE file.
 | |
| 
 | |
| #include "cef/libcef/browser/native/browser_platform_delegate_native_win.h"
 | |
| 
 | |
| #include <shellapi.h>
 | |
| #include <wininet.h>
 | |
| #include <winspool.h>
 | |
| 
 | |
| #include "base/base_paths_win.h"
 | |
| #include "base/files/file_util.h"
 | |
| #include "base/path_service.h"
 | |
| #include "base/strings/utf_string_conversions.h"
 | |
| #include "base/win/win_util.h"
 | |
| #include "cef/libcef/browser/alloy/alloy_browser_host_impl.h"
 | |
| #include "cef/libcef/browser/context.h"
 | |
| #include "cef/libcef/browser/geometry_util.h"
 | |
| #include "cef/libcef/browser/native/window_delegate_view.h"
 | |
| #include "cef/libcef/browser/thread_util.h"
 | |
| #include "components/input/native_web_keyboard_event.h"
 | |
| #include "third_party/blink/public/common/input/web_mouse_event.h"
 | |
| #include "third_party/blink/public/common/input/web_mouse_wheel_event.h"
 | |
| #include "ui/aura/window.h"
 | |
| #include "ui/base/win/shell.h"
 | |
| #include "ui/display/display.h"
 | |
| #include "ui/display/screen.h"
 | |
| #include "ui/display/win/screen_win.h"
 | |
| #include "ui/events/keycodes/dom/dom_key.h"
 | |
| #include "ui/events/keycodes/dom/keycode_converter.h"
 | |
| #include "ui/events/keycodes/keyboard_code_conversion_win.h"
 | |
| #include "ui/events/keycodes/platform_key_map_win.h"
 | |
| #include "ui/gfx/geometry/vector2d.h"
 | |
| #include "ui/gfx/win/hwnd_util.h"
 | |
| #include "ui/views/widget/desktop_aura/desktop_window_tree_host_win.h"
 | |
| #include "ui/views/widget/widget.h"
 | |
| #include "ui/views/win/hwnd_util.h"
 | |
| 
 | |
| #pragma comment(lib, "dwmapi.lib")
 | |
| 
 | |
| namespace {
 | |
| 
 | |
| void WriteTempFileAndView(const std::string& data) {
 | |
|   CEF_REQUIRE_BLOCKING();
 | |
| 
 | |
|   base::FilePath tmp_file;
 | |
|   if (!base::CreateTemporaryFile(&tmp_file)) {
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   // The shell command will look at the file extension to identify the correct
 | |
|   // program to open.
 | |
|   tmp_file = tmp_file.AddExtension(L"txt");
 | |
| 
 | |
|   int write_ct = base::WriteFile(tmp_file, data.c_str(), data.size());
 | |
|   DCHECK_EQ(static_cast<int>(data.size()), write_ct);
 | |
| 
 | |
|   ui::win::OpenFileViaShell(tmp_file);
 | |
| }
 | |
| 
 | |
| gfx::Rect GetDisplayWorkAreaNearestPoint(gfx::Point dip_point) {
 | |
|   const auto display =
 | |
|       display::Screen::GetScreen()->GetDisplayNearestPoint(dip_point);
 | |
|   // Work area in DIP.
 | |
|   return display.work_area();
 | |
| }
 | |
| 
 | |
| CefRect GetScreenFrameRectFromDIPContentRect(HWND window,
 | |
|                                              gfx::Rect dip_rect,
 | |
|                                              DWORD style,
 | |
|                                              DWORD ex_style,
 | |
|                                              bool has_menu) {
 | |
|   // Convert from DIP using a method that can handle multiple displays with
 | |
|   // different DPI. If |window| is nullptr the closest display will be used.
 | |
|   const auto screen_rect =
 | |
|       display::win::ScreenWin::DIPToScreenRect(window, dip_rect);
 | |
| 
 | |
|   RECT rect = {screen_rect.x(), screen_rect.y(),
 | |
|                screen_rect.x() + screen_rect.width(),
 | |
|                screen_rect.y() + screen_rect.height()};
 | |
| 
 | |
|   AdjustWindowRectEx(&rect, style, has_menu, ex_style);
 | |
| 
 | |
|   // Keep the original origin while potentially increasing the size to include
 | |
|   // the frame non-client area.
 | |
|   return CefRect(screen_rect.x(), screen_rect.y(), rect.right - rect.left,
 | |
|                  rect.bottom - rect.top);
 | |
| }
 | |
| 
 | |
| CefRect GetAdjustedScreenFrameRect(CefRect screen_rect,
 | |
|                                    DWORD style,
 | |
|                                    DWORD ex_style,
 | |
|                                    bool has_menu) {
 | |
|   // If height or width is not provided let the OS determine the position and
 | |
|   // size similar to Chromium behavior. Note that |CW_USEDEFAULT| cannot be
 | |
|   // stored in a gfx::Rect due to clamping.
 | |
|   if (screen_rect.width == CW_USEDEFAULT ||
 | |
|       screen_rect.height == CW_USEDEFAULT) {
 | |
|     return CefRect(CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT);
 | |
|   }
 | |
| 
 | |
|   if (screen_rect.x == CW_USEDEFAULT) {
 | |
|     screen_rect.x = 0;
 | |
|   }
 | |
| 
 | |
|   if (screen_rect.y == CW_USEDEFAULT) {
 | |
|     screen_rect.y = 0;
 | |
|   }
 | |
| 
 | |
|   // Convert to DIP using a method that can handle multiple displays with
 | |
|   // different DPI.
 | |
|   const auto dip_rect = display::win::ScreenWin::ScreenToDIPRect(
 | |
|       nullptr, gfx::Rect(screen_rect.x, screen_rect.y, screen_rect.width,
 | |
|                          screen_rect.height));
 | |
|   const auto visible_dip_rect = MakeVisibleOnScreenRect(
 | |
|       dip_rect, GetDisplayWorkAreaNearestPoint(dip_rect.origin()));
 | |
| 
 | |
|   return GetScreenFrameRectFromDIPContentRect(
 | |
|       /*window=*/nullptr, visible_dip_rect, style, ex_style, has_menu);
 | |
| }
 | |
| 
 | |
| }  // namespace
 | |
| 
 | |
| CefBrowserPlatformDelegateNativeWin::CefBrowserPlatformDelegateNativeWin(
 | |
|     const CefWindowInfo& window_info,
 | |
|     SkColor background_color)
 | |
|     : CefBrowserPlatformDelegateNativeAura(window_info, background_color) {}
 | |
| 
 | |
| void CefBrowserPlatformDelegateNativeWin::set_widget(
 | |
|     views::Widget* widget,
 | |
|     CefWindowHandle widget_handle) {
 | |
|   DCHECK(!window_widget_);
 | |
|   window_widget_ = widget;
 | |
|   DCHECK(!window_info_.window);
 | |
|   window_info_.window = widget_handle;
 | |
| }
 | |
| 
 | |
| void CefBrowserPlatformDelegateNativeWin::BrowserDestroyed(
 | |
|     CefBrowserHostBase* browser) {
 | |
|   CefBrowserPlatformDelegateNativeAura::BrowserDestroyed(browser);
 | |
| 
 | |
|   if (host_window_created_) {
 | |
|     // Release the reference added in CreateHostWindow().
 | |
|     browser->Release();
 | |
|   }
 | |
| }
 | |
| 
 | |
| bool CefBrowserPlatformDelegateNativeWin::CreateHostWindow() {
 | |
|   RegisterWindowClass();
 | |
| 
 | |
|   if (window_info_.style == 0) {
 | |
|     // Client didn't intialize the CefWindowInfo. Provide reasonable defaults.
 | |
|     window_info_.SetAsPopup(nullptr, CefString());
 | |
|   }
 | |
| 
 | |
|   has_frame_ = !(window_info_.style & WS_CHILD);
 | |
| 
 | |
|   const std::wstring windowName(CefString(&window_info_.window_name));
 | |
| 
 | |
|   CefRect window_rect = window_info_.bounds;
 | |
| 
 | |
|   if (!window_info_.parent_window) {
 | |
|     const bool has_menu =
 | |
|         !(window_info_.style & WS_CHILD) && (window_info_.menu != nullptr);
 | |
|     window_rect = GetAdjustedScreenFrameRect(window_rect, window_info_.style,
 | |
|                                              window_info_.ex_style, has_menu);
 | |
|   }
 | |
| 
 | |
|   // Create the new browser window.
 | |
|   CreateWindowEx(window_info_.ex_style, GetWndClass(), windowName.c_str(),
 | |
|                  window_info_.style, window_rect.x, window_rect.y,
 | |
|                  window_rect.width, window_rect.height,
 | |
|                  window_info_.parent_window, window_info_.menu,
 | |
|                  ::GetModuleHandle(nullptr), this);
 | |
| 
 | |
|   // It's possible for CreateWindowEx to fail if the parent window was
 | |
|   // destroyed between the call to CreateBrowser and the above one.
 | |
|   DCHECK(window_info_.window);
 | |
|   if (!window_info_.window) {
 | |
|     return false;
 | |
|   }
 | |
| 
 | |
|   host_window_created_ = true;
 | |
| 
 | |
|   // Add a reference that will later be released in DestroyBrowser().
 | |
|   browser_->AddRef();
 | |
| 
 | |
|   if (!called_enable_non_client_dpi_scaling_ && has_frame_) {
 | |
|     // This call gets Windows to scale the non-client area when WM_DPICHANGED
 | |
|     // is fired on Windows versions < 10.0.14393.0.
 | |
|     // Derived signature; not available in headers.
 | |
|     using EnableChildWindowDpiMessagePtr = LRESULT(WINAPI*)(HWND, BOOL);
 | |
|     static const auto enable_child_window_dpi_message_func =
 | |
|         reinterpret_cast<EnableChildWindowDpiMessagePtr>(
 | |
|             base::win::GetUser32FunctionPointer("EnableChildWindowDpiMessage"));
 | |
|     if (enable_child_window_dpi_message_func) {
 | |
|       enable_child_window_dpi_message_func(window_info_.window, TRUE);
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   DCHECK(!window_widget_);
 | |
| 
 | |
|   RECT cr;
 | |
|   GetClientRect(window_info_.window, &cr);
 | |
| 
 | |
|   // Convert to DIP using a method that can handle multiple displays with
 | |
|   // different DPI. Client coordinates always have origin (0,0).
 | |
|   const gfx::Rect dip_rect = display::win::ScreenWin::ScreenToDIPRect(
 | |
|       window_info_.window, gfx::Rect(0, 0, cr.right, cr.bottom));
 | |
| 
 | |
|   // Stay on top if top-most window hosting the web view is topmost.
 | |
|   HWND top_level_window = GetAncestor(window_info_.window, GA_ROOT);
 | |
|   DWORD top_level_window_ex_styles =
 | |
|       GetWindowLongPtr(top_level_window, GWL_EXSTYLE);
 | |
|   bool always_on_top =
 | |
|       (top_level_window_ex_styles & WS_EX_TOPMOST) == WS_EX_TOPMOST;
 | |
| 
 | |
|   CefWindowDelegateView* delegate_view = new CefWindowDelegateView(
 | |
|       GetBackgroundColor(), always_on_top, GetBoundsChangedCallback(),
 | |
|       GetWidgetDeleteCallback());
 | |
|   delegate_view->Init(window_info_.window, web_contents_,
 | |
|                       gfx::Rect(0, 0, dip_rect.width(), dip_rect.height()));
 | |
| 
 | |
|   window_widget_ = delegate_view->GetWidget();
 | |
| 
 | |
|   const HWND widget_hwnd = HWNDForWidget(window_widget_);
 | |
|   DCHECK(widget_hwnd);
 | |
|   const DWORD widget_ex_styles = GetWindowLongPtr(widget_hwnd, GWL_EXSTYLE);
 | |
| 
 | |
|   if (window_info_.ex_style & WS_EX_NOACTIVATE) {
 | |
|     // Add the WS_EX_NOACTIVATE style on the DesktopWindowTreeHostWin HWND
 | |
|     // so that HWNDMessageHandler::Show() called via Widget::Show() does not
 | |
|     // activate the window.
 | |
|     SetWindowLongPtr(widget_hwnd, GWL_EXSTYLE,
 | |
|                      widget_ex_styles | WS_EX_NOACTIVATE);
 | |
|   }
 | |
| 
 | |
|   window_widget_->Show();
 | |
| 
 | |
|   if (window_info_.ex_style & WS_EX_NOACTIVATE) {
 | |
|     // Remove the WS_EX_NOACTIVATE style so that future mouse clicks inside the
 | |
|     // browser correctly activate and focus the window.
 | |
|     SetWindowLongPtr(widget_hwnd, GWL_EXSTYLE, widget_ex_styles);
 | |
|   }
 | |
| 
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| void CefBrowserPlatformDelegateNativeWin::CloseHostWindow() {
 | |
|   if (window_info_.window != nullptr) {
 | |
|     HWND frameWnd = GetAncestor(window_info_.window, GA_ROOT);
 | |
|     PostMessage(frameWnd, WM_CLOSE, 0, 0);
 | |
|   }
 | |
| }
 | |
| 
 | |
| CefWindowHandle CefBrowserPlatformDelegateNativeWin::GetHostWindowHandle()
 | |
|     const {
 | |
|   if (windowless_handler_) {
 | |
|     return windowless_handler_->GetParentWindowHandle();
 | |
|   }
 | |
|   return window_info_.window;
 | |
| }
 | |
| 
 | |
| views::Widget* CefBrowserPlatformDelegateNativeWin::GetWindowWidget() const {
 | |
|   return window_widget_;
 | |
| }
 | |
| 
 | |
| void CefBrowserPlatformDelegateNativeWin::SetFocus(bool setFocus) {
 | |
|   if (!setFocus) {
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   if (window_widget_) {
 | |
|     // Give native focus to the DesktopWindowTreeHostWin ("Chrome_WidgetWin_0")
 | |
|     // associated with the root window. The currently focused HWND may be
 | |
|     // "CefBrowserWindow" if we're called in response to our WndProc receiving
 | |
|     // the WM_SETFOCUS event (possibly due to "CefBrowserWindow" recieving the
 | |
|     // top-level WM_ACTIVATE event), or some other HWND if the client calls
 | |
|     // CefBrowserHost::SetFocus(true) directly. DesktopWindowTreeHostWin may
 | |
|     // also receive focus/blur and mouse click events from the OS directly, in
 | |
|     // which case this method will not be called but the below discussion still
 | |
|     // applies.
 | |
|     //
 | |
|     // The DesktopWindowTreeHostWin::HandleNativeFocus/HandleNativeBlur methods
 | |
|     // are called in response to WM_SETFOCUS/WM_KILLFOCUS respectively. The
 | |
|     // DesktopWindowTreeHostWin::HandleMouseEvent method is called if the user
 | |
|     // clicks on the WebContents. These methods have all been patched to call
 | |
|     // HandleActivationChanged (indirectly via ::SetFocus in the case of mouse
 | |
|     // clicks). HandleActivationChanged will then trigger the following
 | |
|     // behaviors:
 | |
|     // 1. Update focus/activation state of the aura::Window indirectly via
 | |
|     //    wm::FocusController. This allows focus-related behaviors (e.g. focus
 | |
|     //    rings, flashing caret, onFocus/onBlur JS events, etc.) to work as
 | |
|     //    expected (see issue #1677) and also triggers an initial call to
 | |
|     //    WebContents::Focus which gives logical focus to the
 | |
|     //    RenderWidgetHostViewAura in the views hierarchy (see issue #3306).
 | |
|     // 2. Update focus state of the ui::InputMethod. If this does not occur
 | |
|     //    then:
 | |
|     //    (a) InputMethodBase::GetTextInputClient will return NULL and
 | |
|     //    InputMethodWin::OnChar will fail to send character events to the
 | |
|     //    renderer (see issue #1700); and
 | |
|     //    (b) InputMethodWinBase::IsWindowFocused will return false due to
 | |
|     //    ::GetFocus() returning the currently focused HWND (e.g.
 | |
|     //    "CefBrowserWindow") instead of the expected "Chrome_WidgetWin_0" HWND,
 | |
|     //    causing TSF not to handle IME events (see issue #3306). For this same
 | |
|     //    reason, ::SetFocus needs to be called before WebContents::Focus which
 | |
|     //    sends the InputMethod OnWillChangeFocusedClient notification that then
 | |
|     //    calls IsWindowFocused (e.g. WebContents::Focus is intentionally called
 | |
|     //    multiple times).
 | |
|     //
 | |
|     // This differs from activation in Chrome which is handled via
 | |
|     // HWNDMessageHandler::PostProcessActivateMessage (Widget::Show indirectly
 | |
|     // calls HWNDMessageHandler::Activate which calls ::SetForegroundWindow
 | |
|     // resulting in a WM_ACTIVATE message being sent to the window). The Chrome
 | |
|     // code path doesn't work for CEF because IsTopLevelWindow in
 | |
|     // hwnd_message_handler.cc will return false and consequently
 | |
|     // HWNDMessageHandler::PostProcessActivateMessage will not be called.
 | |
|     //
 | |
|     // Activation events are usually reserved for the top-level window so
 | |
|     // triggering activation based on focus events may be incorrect in some
 | |
|     // circumstances. Revisit this implementation if additional problems are
 | |
|     // discovered.
 | |
|     ::SetFocus(HWNDForWidget(window_widget_));
 | |
|   }
 | |
| 
 | |
|   if (web_contents_) {
 | |
|     // Give logical focus to the RenderWidgetHostViewAura in the views
 | |
|     // hierarchy. This does not change the native keyboard focus. When
 | |
|     // |window_widget_| exists this additional Focus() call is necessary to
 | |
|     // correctly assign focus/input state after native focus resulting from
 | |
|     // window activation (see the InputMethod discussion above).
 | |
|     web_contents_->Focus();
 | |
|   }
 | |
| }
 | |
| 
 | |
| void CefBrowserPlatformDelegateNativeWin::NotifyMoveOrResizeStarted() {
 | |
|   // Call the parent method to dismiss any existing popups.
 | |
|   CefBrowserPlatformDelegateNativeAura::NotifyMoveOrResizeStarted();
 | |
| 
 | |
|   if (!window_widget_) {
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   // Notify DesktopWindowTreeHostWin of move events so that screen rectangle
 | |
|   // information is communicated to the renderer process and popups are
 | |
|   // displayed in the correct location.
 | |
|   views::DesktopWindowTreeHostWin* tree_host =
 | |
|       static_cast<views::DesktopWindowTreeHostWin*>(
 | |
|           aura::WindowTreeHost::GetForAcceleratedWidget(
 | |
|               HWNDForWidget(window_widget_)));
 | |
|   DCHECK(tree_host);
 | |
|   if (tree_host) {
 | |
|     // Cast to HWNDMessageHandlerDelegate so we can access HandleMove().
 | |
|     static_cast<views::HWNDMessageHandlerDelegate*>(tree_host)->HandleMove();
 | |
|   }
 | |
| }
 | |
| 
 | |
| void CefBrowserPlatformDelegateNativeWin::SizeTo(int width, int height) {
 | |
|   HWND window = window_info_.window;
 | |
| 
 | |
|   const DWORD style = GetWindowLong(window, GWL_STYLE);
 | |
|   const DWORD ex_style = GetWindowLong(window, GWL_EXSTYLE);
 | |
|   const bool has_menu = !(style & WS_CHILD) && (GetMenu(window) != nullptr);
 | |
| 
 | |
|   const auto frame_rect = GetScreenFrameRectFromDIPContentRect(
 | |
|       window, gfx::Rect(0, 0, width, height), style, ex_style, has_menu);
 | |
| 
 | |
|   // Size the window. The left/top values may be negative.
 | |
|   SetWindowPos(window, nullptr, 0, 0, frame_rect.width, frame_rect.height,
 | |
|                SWP_NOZORDER | SWP_NOMOVE | SWP_NOACTIVATE);
 | |
| }
 | |
| 
 | |
| void CefBrowserPlatformDelegateNativeWin::ViewText(const std::string& text) {
 | |
|   CEF_POST_USER_VISIBLE_TASK(base::BindOnce(WriteTempFileAndView, text));
 | |
| }
 | |
| 
 | |
| bool CefBrowserPlatformDelegateNativeWin::HandleKeyboardEvent(
 | |
|     const input::NativeWebKeyboardEvent& event) {
 | |
|   // Any unhandled keyboard/character messages are sent to DefWindowProc so that
 | |
|   // shortcut keys work correctly.
 | |
|   if (event.os_event) {
 | |
|     const auto& msg = event.os_event->native_event();
 | |
|     return !DefWindowProc(msg.hwnd, msg.message, msg.wParam, msg.lParam);
 | |
|   } else {
 | |
|     MSG msg = {};
 | |
| 
 | |
|     msg.hwnd = GetHostWindowHandle();
 | |
|     if (!msg.hwnd) {
 | |
|       return false;
 | |
|     }
 | |
| 
 | |
|     switch (event.GetType()) {
 | |
|       case blink::WebInputEvent::Type::kRawKeyDown:
 | |
|         msg.message = event.is_system_key ? WM_SYSKEYDOWN : WM_KEYDOWN;
 | |
|         break;
 | |
|       case blink::WebInputEvent::Type::kKeyUp:
 | |
|         msg.message = event.is_system_key ? WM_SYSKEYUP : WM_KEYUP;
 | |
|         break;
 | |
|       case blink::WebInputEvent::Type::kChar:
 | |
|         msg.message = event.is_system_key ? WM_SYSCHAR : WM_CHAR;
 | |
|         break;
 | |
|       default:
 | |
|         DCHECK(false);
 | |
|         return false;
 | |
|     }
 | |
| 
 | |
|     msg.wParam = event.windows_key_code;
 | |
| 
 | |
|     UINT scan_code = ::MapVirtualKeyW(event.windows_key_code, MAPVK_VK_TO_VSC);
 | |
|     msg.lParam = (scan_code << 16) |  // key scan code
 | |
|                  1;                   // key repeat count
 | |
|     if (event.GetModifiers() & input::NativeWebKeyboardEvent::kAltKey) {
 | |
|       msg.lParam |= (1 << 29);
 | |
|     }
 | |
| 
 | |
|     return !DefWindowProc(msg.hwnd, msg.message, msg.wParam, msg.lParam);
 | |
|   }
 | |
| }
 | |
| 
 | |
| CefEventHandle CefBrowserPlatformDelegateNativeWin::GetEventHandle(
 | |
|     const input::NativeWebKeyboardEvent& event) const {
 | |
|   if (!event.os_event) {
 | |
|     return nullptr;
 | |
|   }
 | |
|   return ChromeToWindowsType(
 | |
|       const_cast<CHROME_MSG*>(&event.os_event->native_event()));
 | |
| }
 | |
| 
 | |
| ui::KeyEvent CefBrowserPlatformDelegateNativeWin::TranslateUiKeyEvent(
 | |
|     const CefKeyEvent& key_event) const {
 | |
|   int flags = TranslateUiEventModifiers(key_event.modifiers);
 | |
|   ui::KeyboardCode key_code =
 | |
|       ui::KeyboardCodeForWindowsKeyCode(key_event.windows_key_code);
 | |
|   ui::DomCode dom_code =
 | |
|       ui::KeycodeConverter::NativeKeycodeToDomCode(key_event.native_key_code);
 | |
|   base::TimeTicks time_stamp = GetEventTimeStamp();
 | |
| 
 | |
|   if (key_event.type == KEYEVENT_CHAR) {
 | |
|     return ui::KeyEvent::FromCharacter(/*character=*/key_event.windows_key_code,
 | |
|                                        key_code, dom_code, flags, time_stamp);
 | |
|   }
 | |
| 
 | |
|   ui::EventType type = ui::ET_UNKNOWN;
 | |
|   switch (key_event.type) {
 | |
|     case KEYEVENT_RAWKEYDOWN:
 | |
|     case KEYEVENT_KEYDOWN:
 | |
|       type = ui::ET_KEY_PRESSED;
 | |
|       break;
 | |
|     case KEYEVENT_KEYUP:
 | |
|       type = ui::ET_KEY_RELEASED;
 | |
|       break;
 | |
|     default:
 | |
|       DCHECK(false);
 | |
|   }
 | |
| 
 | |
|   ui::DomKey dom_key =
 | |
|       ui::PlatformKeyMap::DomKeyFromKeyboardCode(key_code, &flags);
 | |
|   return ui::KeyEvent(type, key_code, dom_code, flags, dom_key, time_stamp);
 | |
| }
 | |
| 
 | |
| gfx::Vector2d CefBrowserPlatformDelegateNativeWin::GetUiWheelEventOffset(
 | |
|     int deltaX,
 | |
|     int deltaY) const {
 | |
|   static const ULONG defaultScrollCharsPerWheelDelta = 1;
 | |
|   static const FLOAT scrollbarPixelsPerLine = 100.0f / 3.0f;
 | |
|   static const ULONG defaultScrollLinesPerWheelDelta = 3;
 | |
| 
 | |
|   float wheelDeltaX = float(deltaX) / WHEEL_DELTA;
 | |
|   float wheelDeltaY = float(deltaY) / WHEEL_DELTA;
 | |
|   float scrollDeltaX = wheelDeltaX;
 | |
|   float scrollDeltaY = wheelDeltaY;
 | |
| 
 | |
|   ULONG scrollChars = defaultScrollCharsPerWheelDelta;
 | |
|   SystemParametersInfo(SPI_GETWHEELSCROLLCHARS, 0, &scrollChars, 0);
 | |
|   scrollDeltaX *= static_cast<FLOAT>(scrollChars) * scrollbarPixelsPerLine;
 | |
| 
 | |
|   ULONG scrollLines = defaultScrollLinesPerWheelDelta;
 | |
|   SystemParametersInfo(SPI_GETWHEELSCROLLLINES, 0, &scrollLines, 0);
 | |
|   scrollDeltaY *= static_cast<FLOAT>(scrollLines) * scrollbarPixelsPerLine;
 | |
| 
 | |
|   return gfx::Vector2d(scrollDeltaX, scrollDeltaY);
 | |
| }
 | |
| 
 | |
| // static
 | |
| void CefBrowserPlatformDelegateNativeWin::RegisterWindowClass() {
 | |
|   static bool registered = false;
 | |
|   if (registered) {
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   // Register the window class
 | |
|   WNDCLASSEX wcex = {
 | |
|       /* cbSize = */ sizeof(WNDCLASSEX),
 | |
|       /* style = */ CS_HREDRAW | CS_VREDRAW,
 | |
|       /* lpfnWndProc = */ CefBrowserPlatformDelegateNativeWin::WndProc,
 | |
|       /* cbClsExtra = */ 0,
 | |
|       /* cbWndExtra = */ 0,
 | |
|       /* hInstance = */ ::GetModuleHandle(nullptr),
 | |
|       /* hIcon = */ nullptr,
 | |
|       /* hCursor = */ LoadCursor(nullptr, IDC_ARROW),
 | |
|       /* hbrBackground = */ nullptr,
 | |
|       /* lpszMenuName = */ nullptr,
 | |
|       /* lpszClassName = */ CefBrowserPlatformDelegateNativeWin::GetWndClass(),
 | |
|       /* hIconSm = */ nullptr,
 | |
|   };
 | |
|   RegisterClassEx(&wcex);
 | |
| 
 | |
|   registered = true;
 | |
| }
 | |
| 
 | |
| // static
 | |
| LPCTSTR CefBrowserPlatformDelegateNativeWin::GetWndClass() {
 | |
|   return L"CefBrowserWindow";
 | |
| }
 | |
| 
 | |
| // static
 | |
| LRESULT CALLBACK CefBrowserPlatformDelegateNativeWin::WndProc(HWND hwnd,
 | |
|                                                               UINT message,
 | |
|                                                               WPARAM wParam,
 | |
|                                                               LPARAM lParam) {
 | |
|   CefBrowserPlatformDelegateNativeWin* platform_delegate = nullptr;
 | |
|   CefBrowserHostBase* browser = nullptr;
 | |
| 
 | |
|   if (message != WM_NCCREATE) {
 | |
|     platform_delegate = static_cast<CefBrowserPlatformDelegateNativeWin*>(
 | |
|         gfx::GetWindowUserData(hwnd));
 | |
|     if (platform_delegate) {
 | |
|       browser = platform_delegate->browser_;
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   switch (message) {
 | |
|     case WM_CLOSE:
 | |
|       if (browser && !browser->TryCloseBrowser()) {
 | |
|         // Cancel the close.
 | |
|         return 0;
 | |
|       }
 | |
| 
 | |
|       // Allow the close.
 | |
|       break;
 | |
| 
 | |
|     case WM_NCCREATE: {
 | |
|       CREATESTRUCT* cs = reinterpret_cast<CREATESTRUCT*>(lParam);
 | |
|       platform_delegate =
 | |
|           reinterpret_cast<CefBrowserPlatformDelegateNativeWin*>(
 | |
|               cs->lpCreateParams);
 | |
|       DCHECK(platform_delegate);
 | |
|       // Associate |platform_delegate| with the window handle.
 | |
|       gfx::SetWindowUserData(hwnd, platform_delegate);
 | |
|       platform_delegate->window_info_.window = hwnd;
 | |
| 
 | |
|       if (platform_delegate->has_frame_) {
 | |
|         // This call gets Windows to scale the non-client area when
 | |
|         // WM_DPICHANGED is fired on Windows versions >= 10.0.14393.0.
 | |
|         using EnableNonClientDpiScalingPtr =
 | |
|             decltype(::EnableNonClientDpiScaling)*;
 | |
|         static const auto enable_non_client_dpi_scaling_func =
 | |
|             reinterpret_cast<EnableNonClientDpiScalingPtr>(
 | |
|                 base::win::GetUser32FunctionPointer(
 | |
|                     "EnableNonClientDpiScaling"));
 | |
|         platform_delegate->called_enable_non_client_dpi_scaling_ =
 | |
|             !!(enable_non_client_dpi_scaling_func &&
 | |
|                enable_non_client_dpi_scaling_func(hwnd));
 | |
|       }
 | |
|     } break;
 | |
| 
 | |
|     case WM_NCDESTROY:
 | |
|       if (platform_delegate) {
 | |
|         // Clear the user data pointer.
 | |
|         gfx::SetWindowUserData(hwnd, nullptr);
 | |
| 
 | |
|         // Force the browser to be destroyed. This will result in a call to
 | |
|         // BrowserDestroyed() that will release the reference added in
 | |
|         // CreateHostWindow().
 | |
|         AlloyBrowserHostImpl::FromBaseChecked(browser)->WindowDestroyed();
 | |
|       }
 | |
|       break;
 | |
| 
 | |
|     case WM_SIZE:
 | |
|       if (platform_delegate && platform_delegate->window_widget_) {
 | |
|         // Pass window resize events to the HWND for the DesktopNativeWidgetAura
 | |
|         // root window. Passing size 0x0 (wParam == SIZE_MINIMIZED, for example)
 | |
|         // will cause the widget to be hidden which reduces resource usage.
 | |
|         RECT rc;
 | |
|         GetClientRect(hwnd, &rc);
 | |
|         SetWindowPos(HWNDForWidget(platform_delegate->window_widget_), nullptr,
 | |
|                      rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top,
 | |
|                      SWP_NOZORDER);
 | |
|       }
 | |
|       return 0;
 | |
| 
 | |
|     case WM_MOVING:
 | |
|     case WM_MOVE:
 | |
|       if (browser) {
 | |
|         browser->NotifyMoveOrResizeStarted();
 | |
|       }
 | |
|       return 0;
 | |
| 
 | |
|     case WM_SETFOCUS:
 | |
|       // Selecting "Close window" from the task bar menu may send a focus
 | |
|       // notification even though the window is currently disabled (e.g. while
 | |
|       // a modal JS dialog is displayed).
 | |
|       if (browser && ::IsWindowEnabled(hwnd)) {
 | |
|         browser->SetFocus(true);
 | |
|       }
 | |
|       return 0;
 | |
| 
 | |
|     case WM_ERASEBKGND:
 | |
|       return 0;
 | |
| 
 | |
|     case WM_DPICHANGED:
 | |
|       if (platform_delegate && platform_delegate->has_frame_) {
 | |
|         // Suggested size and position of the current window scaled for the
 | |
|         // new DPI.
 | |
|         const RECT* rect = reinterpret_cast<RECT*>(lParam);
 | |
|         SetWindowPos(platform_delegate->GetHostWindowHandle(), nullptr,
 | |
|                      rect->left, rect->top, rect->right - rect->left,
 | |
|                      rect->bottom - rect->top, SWP_NOZORDER | SWP_NOACTIVATE);
 | |
|       }
 | |
|       break;
 | |
| 
 | |
|     case WM_ENABLE:
 | |
|       if (wParam == TRUE && browser) {
 | |
|         // Give focus to the browser after EnableWindow enables this window
 | |
|         // (e.g. after a modal dialog is dismissed).
 | |
|         browser->SetFocus(true);
 | |
|         return 0;
 | |
|       }
 | |
|       break;
 | |
|   }
 | |
| 
 | |
|   return DefWindowProc(hwnd, message, wParam, lParam);
 | |
| }
 |