views: Add support for accelerators (issue #2102)

This commit is contained in:
Marshall Greenblatt 2017-02-16 18:19:43 -05:00
parent e4867b5afb
commit bd1b80198f
35 changed files with 948 additions and 74 deletions

View File

@ -63,6 +63,18 @@ typedef struct _cef_browser_view_t {
///
struct _cef_browser_t* (CEF_CALLBACK *get_browser)(
struct _cef_browser_view_t* self);
///
// Sets whether accelerators registered with cef_window_t::SetAccelerator are
// triggered before or after the event is sent to the cef_browser_t. If
// |prefer_accelerators| is true (1) then the matching accelerator will be
// triggered immediately and the event will not be sent to the cef_browser_t.
// If |prefer_accelerators| is false (0) then the matching accelerator will
// only be triggered if the event is not handled by web content or by
// cef_keyboard_handler_t. The default value is false (0).
///
void (CEF_CALLBACK *set_prefer_accelerators)(struct _cef_browser_view_t* self,
int prefer_accelerators);
} cef_browser_view_t;

View File

@ -269,6 +269,27 @@ typedef struct _cef_window_t {
///
void (CEF_CALLBACK *send_mouse_events)(struct _cef_window_t* self,
cef_mouse_button_type_t button, int mouse_down, int mouse_up);
///
// Set the keyboard accelerator for the specified |command_id|. |key_code| can
// be any virtual key or character value. cef_window_delegate_t::OnAccelerator
// will be called if the keyboard combination is triggered while this window
// has focus.
///
void (CEF_CALLBACK *set_accelerator)(struct _cef_window_t* self,
int command_id, int key_code, int shift_pressed, int ctrl_pressed,
int alt_pressed);
///
// Remove the keyboard accelerator for the specified |command_id|.
///
void (CEF_CALLBACK *remove_accelerator)(struct _cef_window_t* self,
int command_id);
///
// Remove all keyboard accelerators.
///
void (CEF_CALLBACK *remove_all_accelerators)(struct _cef_window_t* self);
} cef_window_t;

View File

@ -103,6 +103,22 @@ typedef struct _cef_window_delegate_t {
///
int (CEF_CALLBACK *can_close)(struct _cef_window_delegate_t* self,
struct _cef_window_t* window);
///
// Called when a keyboard accelerator registered with
// cef_window_t::SetAccelerator is triggered. Return true (1) if the
// accelerator was handled or false (0) otherwise.
///
int (CEF_CALLBACK *on_accelerator)(struct _cef_window_delegate_t* self,
struct _cef_window_t* window, int command_id);
///
// Called after all other controls in the window have had a chance to handle
// the event. |event| contains information about the keyboard event. Return
// true (1) if the keyboard event was handled or false (0) otherwise.
///
int (CEF_CALLBACK *on_key_event)(struct _cef_window_delegate_t* self,
struct _cef_window_t* window, const struct _cef_key_event_t* event);
} cef_window_delegate_t;

View File

@ -74,6 +74,18 @@ class CefBrowserView : public CefView {
///
/*--cef()--*/
virtual CefRefPtr<CefBrowser> GetBrowser() =0;
///
// Sets whether accelerators registered with CefWindow::SetAccelerator are
// triggered before or after the event is sent to the CefBrowser. If
// |prefer_accelerators| is true then the matching accelerator will be
// triggered immediately and the event will not be sent to the CefBrowser. If
// |prefer_accelerators| is false then the matching accelerator will only be
// triggered if the event is not handled by web content or by
// CefKeyboardHandler. The default value is false.
///
/*--cef()--*/
virtual void SetPreferAccelerators(bool prefer_accelerators) =0;
};
#endif // CEF_INCLUDE_VIEWS_CEF_BROWSER_VIEW_H_

View File

@ -289,6 +289,30 @@ class CefWindow : public CefPanel {
virtual void SendMouseEvents(cef_mouse_button_type_t button,
bool mouse_down,
bool mouse_up) =0;
///
// Set the keyboard accelerator for the specified |command_id|. |key_code| can
// be any virtual key or character value. CefWindowDelegate::OnAccelerator
// will be called if the keyboard combination is triggered while this window
// has focus.
///
/*--cef()--*/
virtual void SetAccelerator(int command_id,
int key_code,
bool shift_pressed,
bool ctrl_pressed,
bool alt_pressed) =0;
///
// Remove the keyboard accelerator for the specified |command_id|.
///
/*--cef()--*/
virtual void RemoveAccelerator(int command_id) =0;
///
// Remove all keyboard accelerators.
///
/*--cef()--*/
virtual void RemoveAllAccelerators() =0;
};
#endif // CEF_INCLUDE_VIEWS_CEF_WINDOW_H_

View File

@ -95,6 +95,24 @@ class CefWindowDelegate : public CefPanelDelegate {
///
/*--cef()--*/
virtual bool CanClose(CefRefPtr<CefWindow> window) { return true; }
///
// Called when a keyboard accelerator registered with
// CefWindow::SetAccelerator is triggered. Return true if the accelerator was
// handled or false otherwise.
///
/*--cef()--*/
virtual bool OnAccelerator(CefRefPtr<CefWindow> window,
int command_id) { return false; }
///
// Called after all other controls in the window have had a chance to
// handle the event. |event| contains information about the keyboard event.
// Return true if the keyboard event was handled or false otherwise.
///
/*--cef()--*/
virtual bool OnKeyEvent(CefRefPtr<CefWindow> window,
const CefKeyEvent& event) { return false; }
};
#endif // CEF_INCLUDE_VIEWS_CEF_WINDOW_DELEGATE_H_

View File

@ -216,7 +216,8 @@ void CefBrowserPlatformDelegateViews::ViewText(const std::string& text) {
void CefBrowserPlatformDelegateViews::HandleKeyboardEvent(
const content::NativeWebKeyboardEvent& event) {
native_delegate_->HandleKeyboardEvent(event);
// The BrowserView will handle accelerators.
browser_view_->HandleKeyboardEvent(event);
}
void CefBrowserPlatformDelegateViews::HandleExternalProtocol(const GURL& url) {

View File

@ -5,9 +5,14 @@
#include "libcef/browser/views/browser_view_impl.h"
#include "libcef/browser/browser_host_impl.h"
#include "libcef/browser/browser_util.h"
#include "libcef/browser/context.h"
#include "libcef/browser/views/window_impl.h"
#include "libcef/browser/thread_util.h"
#include "content/public/browser/native_web_keyboard_event.h"
#include "ui/content_accelerators/accelerator_util.h"
// static
CefRefPtr<CefBrowserView> CefBrowserView::CreateBrowserView(
CefRefPtr<CefClient> client,
@ -75,11 +80,45 @@ void CefBrowserViewImpl::BrowserDestroyed(CefBrowserHostImpl* browser) {
root_view()->SetWebContents(nullptr);
}
void CefBrowserViewImpl::HandleKeyboardEvent(
const content::NativeWebKeyboardEvent& event) {
if (!root_view())
return;
views::FocusManager* focus_manager = root_view()->GetFocusManager();
if (!focus_manager)
return;
if (HandleAccelerator(event, focus_manager))
return;
// Give the CefWindowDelegate a chance to handle the event.
CefRefPtr<CefWindow> window =
view_util::GetWindowFor(root_view()->GetWidget());
CefWindowImpl* window_impl = static_cast<CefWindowImpl*>(window.get());
if (window_impl) {
CefKeyEvent cef_event;
if (browser_util::GetCefKeyEvent(event, cef_event) &&
window_impl->OnKeyEvent(cef_event)) {
return;
}
}
// Proceed with default native handling.
unhandled_keyboard_event_handler_.HandleKeyboardEvent(event, focus_manager);
}
CefRefPtr<CefBrowser> CefBrowserViewImpl::GetBrowser() {
CEF_REQUIRE_VALID_RETURN(nullptr);
return browser_;
}
void CefBrowserViewImpl::SetPreferAccelerators(bool prefer_accelerators) {
CEF_REQUIRE_VALID_RETURN_VOID();
if (root_view())
root_view()->set_allow_accelerators(prefer_accelerators);
}
void CefBrowserViewImpl::SetBackgroundColor(cef_color_t color) {
CEF_REQUIRE_VALID_RETURN_VOID();
ParentClass::SetBackgroundColor(color);
@ -167,3 +206,39 @@ CefBrowserViewView* CefBrowserViewImpl::CreateRootView() {
void CefBrowserViewImpl::InitializeRootView() {
static_cast<CefBrowserViewView*>(root_view())->Initialize();
}
bool CefBrowserViewImpl::HandleAccelerator(
const content::NativeWebKeyboardEvent& event,
views::FocusManager* focus_manager) {
// Previous calls to TranslateMessage can generate Char events as well as
// RawKeyDown events, even if the latter triggered an accelerator. In these
// cases, we discard the Char events.
if (event.type() == blink::WebInputEvent::Char && ignore_next_char_event_) {
ignore_next_char_event_ = false;
return true;
}
// It's necessary to reset this flag, because a RawKeyDown event may not
// always generate a Char event.
ignore_next_char_event_ = false;
if (event.type() == blink::WebInputEvent::RawKeyDown) {
ui::Accelerator accelerator =
ui::GetAcceleratorFromNativeWebKeyboardEvent(event);
// This is tricky: we want to set ignore_next_char_event_ if
// ProcessAccelerator returns true. But ProcessAccelerator might delete
// |this| if the accelerator is a "close tab" one. So we speculatively
// set the flag and fix it if no event was handled.
ignore_next_char_event_ = true;
if (focus_manager->ProcessAccelerator(accelerator))
return true;
// ProcessAccelerator didn't handle the accelerator, so we know both
// that |this| is still valid, and that we didn't want to set the flag.
ignore_next_char_event_ = false;
}
return false;
}

View File

@ -14,6 +14,8 @@
#include "libcef/browser/views/view_impl.h"
#include "libcef/browser/views/browser_view_view.h"
#include "ui/views/controls/webview/unhandled_keyboard_event_handler.h"
class CefBrowserViewImpl :
public CefViewImpl<CefBrowserViewView, CefBrowserView,
CefBrowserViewDelegate>,
@ -41,8 +43,13 @@ class CefBrowserViewImpl :
void BrowserCreated(CefBrowserHostImpl* browser);
void BrowserDestroyed(CefBrowserHostImpl* browser);
// Called to handle accelerators when the event is unhandled by the web
// content and the browser client.
void HandleKeyboardEvent(const content::NativeWebKeyboardEvent& event);
// CefBrowserView methods:
CefRefPtr<CefBrowser> GetBrowser() override;
void SetPreferAccelerators(bool prefer_accelerators) override;
// CefView methods:
CefRefPtr<CefBrowserView> AsBrowserView() override { return this; }
@ -75,10 +82,20 @@ class CefBrowserViewImpl :
CefBrowserViewView* CreateRootView() override;
void InitializeRootView() override;
std::unique_ptr<CefBrowserHostImpl::CreateParams> pending_browser_create_params_;
// Logic extracted from UnhandledKeyboardEventHandler::HandleKeyboardEvent for
// the handling of accelerators. Returns true if the event was handled by the
// accelerator.
bool HandleAccelerator(const content::NativeWebKeyboardEvent& event,
views::FocusManager* focus_manager);
std::unique_ptr<CefBrowserHostImpl::CreateParams>
pending_browser_create_params_;
CefRefPtr<CefBrowserHostImpl> browser_;
views::UnhandledKeyboardEventHandler unhandled_keyboard_event_handler_;
bool ignore_next_char_event_ = false;
IMPLEMENT_REFCOUNTING_DELETE_ON_UIT(CefBrowserViewImpl);
DISALLOW_COPY_AND_ASSIGN(CefBrowserViewImpl);
};

View File

@ -35,6 +35,7 @@ CEF_BUTTON_IMPL_T class CefButtonImpl : public CEF_VIEW_IMPL_D {
// CefView methods:
CefRefPtr<CefButton> AsButton() override { return this; }
void SetFocusable(bool focusable) override;
protected:
// Create a new implementation object.
@ -68,4 +69,11 @@ CEF_BUTTON_IMPL_T void CEF_BUTTON_IMPL_D::SetAccessibleName(
ParentClass::root_view()->SetAccessibleName(name);
}
CEF_BUTTON_IMPL_T void CEF_BUTTON_IMPL_D::SetFocusable(
bool focusable) {
CEF_REQUIRE_VALID_RETURN_VOID();
ParentClass::root_view()->set_request_focus_on_press(focusable);
ParentClass::SetFocusable(focusable);
}
#endif // CEF_LIBCEF_BROWSER_VIEWS_BUTTON_IMPL_H_

View File

@ -4,6 +4,7 @@
#include "libcef/browser/views/window_impl.h"
#include "libcef/browser/browser_util.h"
#include "libcef/browser/thread_util.h"
#include "libcef/browser/views/display_impl.h"
#include "libcef/browser/views/fill_layout_impl.h"
@ -17,6 +18,7 @@
#if defined(USE_AURA)
#include "ui/aura/test/ui_controls_factory_aura.h"
#include "ui/aura/window.h"
#include "ui/base/test/ui_controls_aura.h"
#if defined(OS_LINUX)
#include "ui/views/test/ui_controls_factory_desktop_aurax11.h"
@ -48,6 +50,58 @@ void InitializeUITesting() {
}
}
#if defined(USE_AURA)
// This class forwards KeyEvents to the CefWindowImpl associated with a widget.
// This allows KeyEvents to be processed after all other targets.
// Events originating from CefBrowserView will instead be delivered via
// CefBrowserViewImpl::HandleKeyboardEvent.
class CefUnhandledKeyEventHandler : public ui::EventHandler {
public:
CefUnhandledKeyEventHandler(CefWindowImpl* window_impl,
views::Widget* widget)
: window_impl_(window_impl),
widget_(widget),
window_(widget->GetNativeWindow()) {
DCHECK(window_);
window_->AddPostTargetHandler(this);
}
~CefUnhandledKeyEventHandler() override {
window_->RemovePostTargetHandler(this);
}
// Implementation of ui::EventHandler:
void OnKeyEvent(ui::KeyEvent* event) override {
// Give the FocusManager a chance to handle accelerators first.
// Widget::OnKeyEvent would normally call this after all EventHandlers have
// had a shot but we don't want to wait.
if (widget_->GetFocusManager() &&
!widget_->GetFocusManager()->OnKeyEvent(*event)) {
event->StopPropagation();
return;
}
CefKeyEvent cef_event;
if (browser_util::GetCefKeyEvent(*event, cef_event) &&
window_impl_->OnKeyEvent(cef_event)) {
event->StopPropagation();
}
}
private:
// Members are guaranteed to outlive this object.
CefWindowImpl* window_impl_;
views::Widget* widget_;
// |window_| is the event target that is associated with this class.
aura::Window* window_;
DISALLOW_COPY_AND_ASSIGN(CefUnhandledKeyEventHandler);
};
#endif // defined(USE_AURA)
} // namespace
// static
@ -315,6 +369,12 @@ bool CefWindowImpl::CanWidgetClose() {
return true;
}
void CefWindowImpl::OnWindowClosing() {
#if defined(USE_AURA)
unhandled_key_event_handler_.reset();
#endif
}
void CefWindowImpl::OnWindowViewDeleted() {
CancelMenu();
@ -337,6 +397,27 @@ void CefWindowImpl::MenuClosed(CefRefPtr<CefMenuModelImpl> source) {
menu_runner_.reset(nullptr);
}
// Will only be called if CanHandleAccelerators() returns true.
bool CefWindowImpl::AcceleratorPressed(const ui::Accelerator& accelerator) {
for (const auto& entry : accelerator_map_) {
if (entry.second == accelerator)
return delegate()->OnAccelerator(this, entry.first);
}
return false;
}
bool CefWindowImpl::CanHandleAccelerators() const {
if (delegate() && widget_)
return widget_->IsActive();
return false;
}
bool CefWindowImpl::OnKeyEvent(const CefKeyEvent& event) {
if (delegate())
return delegate()->OnKeyEvent(this, event);
return false;
}
void CefWindowImpl::ShowMenu(views::MenuButton* menu_button,
CefRefPtr<CefMenuModel> menu_model,
const CefPoint& screen_point,
@ -474,6 +555,67 @@ void CefWindowImpl::SendMouseEvents(cef_mouse_button_type_t button,
ui_controls::SendMouseEvents(type, state);
}
void CefWindowImpl::SetAccelerator(int command_id,
int key_code,
bool shift_pressed,
bool ctrl_pressed,
bool alt_pressed) {
CEF_REQUIRE_VALID_RETURN_VOID();
if (!widget_)
return;
AcceleratorMap::const_iterator it = accelerator_map_.find(command_id);
if (it != accelerator_map_.end())
RemoveAccelerator(command_id);
int modifiers = 0;
if (shift_pressed)
modifiers |= ui::EF_SHIFT_DOWN;
if (ctrl_pressed)
modifiers |= ui::EF_CONTROL_DOWN;
if (alt_pressed)
modifiers |= ui::EF_ALT_DOWN;
ui::Accelerator accelerator(static_cast<ui::KeyboardCode>(key_code),
modifiers);
accelerator_map_.insert(std::make_pair(command_id, accelerator));
views::FocusManager* focus_manager = widget_->GetFocusManager();
DCHECK(focus_manager);
focus_manager->RegisterAccelerator(
accelerator, ui::AcceleratorManager::kNormalPriority, this);
}
void CefWindowImpl::RemoveAccelerator(int command_id) {
CEF_REQUIRE_VALID_RETURN_VOID();
if (!widget_)
return;
AcceleratorMap::iterator it = accelerator_map_.find(command_id);
if (it == accelerator_map_.end())
return;
ui::Accelerator accelerator = it->second;
accelerator_map_.erase(it);
views::FocusManager* focus_manager = widget_->GetFocusManager();
DCHECK(focus_manager);
focus_manager->UnregisterAccelerator(accelerator, this);
}
void CefWindowImpl::RemoveAllAccelerators() {
CEF_REQUIRE_VALID_RETURN_VOID();
if (!widget_)
return;
accelerator_map_.clear();
views::FocusManager* focus_manager = widget_->GetFocusManager();
DCHECK(focus_manager);
focus_manager->UnregisterAccelerators(this);
}
CefWindowImpl::CefWindowImpl(CefRefPtr<CefWindowDelegate> delegate)
: ParentClass(delegate),
widget_(nullptr),
@ -495,6 +637,11 @@ void CefWindowImpl::CreateWidget() {
widget_ = root_view()->GetWidget();
DCHECK(widget_);
#if defined(USE_AURA)
unhandled_key_event_handler_ =
base::MakeUnique<CefUnhandledKeyEventHandler>(this, widget_);
#endif
// The Widget and root View are owned by the native window. Therefore don't
// keep an owned reference.
std::unique_ptr<views::View> view_ptr = view_util::PassOwnership(this);

View File

@ -6,6 +6,8 @@
#define CEF_LIBCEF_BROWSER_VIEWS_WINDOW_IMPL_H_
#pragma once
#include <map>
#include "include/views/cef_window.h"
#include "include/views/cef_window_delegate.h"
@ -13,6 +15,7 @@
#include "libcef/browser/views/panel_impl.h"
#include "libcef/browser/views/window_view.h"
#include "ui/base/accelerators/accelerator.h"
#include "ui/views/controls/menu/menu_runner.h"
#include "ui/views/widget/widget.h"
@ -23,7 +26,8 @@ class MenuButton;
class CefWindowImpl :
public CefPanelImpl<CefWindowView, CefWindow, CefWindowDelegate>,
public CefWindowView::Delegate,
public CefMenuModelImpl::Observer {
public CefMenuModelImpl::Observer,
public ui::AcceleratorTarget {
public:
typedef CefPanelImpl<CefWindowView, CefWindow, CefWindowDelegate> ParentClass;
@ -70,6 +74,13 @@ class CefWindowImpl :
void SendMouseEvents(cef_mouse_button_type_t button,
bool mouse_down,
bool mouse_up) override;
void SetAccelerator(int command_id,
int key_code,
bool shift_pressed,
bool ctrl_pressed,
bool alt_pressed) override;
void RemoveAccelerator(int command_id) override;
void RemoveAllAccelerators() override;
// CefViewAdapter methods:
void Detach() override;
@ -91,6 +102,7 @@ class CefWindowImpl :
// CefWindowView::Delegate methods:
bool CanWidgetClose() override;
void OnWindowClosing() override;
void OnWindowViewDeleted() override;
// CefMenuModelImpl::Observer methods:
@ -101,6 +113,14 @@ class CefWindowImpl :
void GetDebugInfo(base::DictionaryValue* info,
bool include_children) override;
// ui::AcceleratorTarget methods:
bool AcceleratorPressed(const ui::Accelerator& accelerator) override;
bool CanHandleAccelerators() const override;
// Called for key events that have not been handled by other controls in the
// window. Returns true if the event was handled.
bool OnKeyEvent(const CefKeyEvent& event);
void ShowMenu(views::MenuButton* menu_button,
CefRefPtr<CefMenuModel> menu_model,
const CefPoint& screen_point,
@ -128,6 +148,15 @@ class CefWindowImpl :
CefRefPtr<CefMenuModelImpl> menu_model_;
std::unique_ptr<views::MenuRunner> menu_runner_;
// Map of command_id to accelerator.
typedef std::map<int, ui::Accelerator> AcceleratorMap;
AcceleratorMap accelerator_map_;
#if defined(USE_AURA)
// Native widget's handler to receive events after the event target.
std::unique_ptr<ui::EventHandler> unhandled_key_event_handler_;
#endif
IMPLEMENT_REFCOUNTING_DELETE_ON_UIT(CefWindowImpl);
DISALLOW_COPY_AND_ASSIGN(CefWindowImpl);
};

View File

@ -368,6 +368,10 @@ gfx::ImageSkia CefWindowView::GetWindowAppIcon() {
GetForced1xScaleRepresentation(GetDisplay().device_scale_factor());
}
void CefWindowView::WindowClosing() {
window_delegate_->OnWindowClosing();
}
views::View* CefWindowView::GetContentsView() {
// |this| will be the "Contents View" hosted by the Widget via ClientView and
// RootView.

View File

@ -29,6 +29,9 @@ class CefWindowView :
// Returns true to signal that the Widget can be closed.
virtual bool CanWidgetClose() = 0;
// Called when the underlying platform window is closing.
virtual void OnWindowClosing() = 0;
// Called when the WindowView is about to be deleted.
virtual void OnWindowViewDeleted() = 0;
@ -58,6 +61,7 @@ class CefWindowView :
base::string16 GetWindowTitle() const override;
gfx::ImageSkia GetWindowIcon() override;
gfx::ImageSkia GetWindowAppIcon() override;
void WindowClosing() override;
views::View* GetContentsView() override;
views::ClientView* CreateClientView(views::Widget* widget) override;
views::NonClientFrameView* CreateNonClientFrameView(

View File

@ -92,6 +92,19 @@ cef_browser_t* CEF_CALLBACK browser_view_get_browser(
return CefBrowserCppToC::Wrap(_retval);
}
void CEF_CALLBACK browser_view_set_prefer_accelerators(
struct _cef_browser_view_t* self, int prefer_accelerators) {
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
DCHECK(self);
if (!self)
return;
// Execute
CefBrowserViewCppToC::Get(self)->SetPreferAccelerators(
prefer_accelerators?true:false);
}
cef_browser_view_t* CEF_CALLBACK browser_view_as_browser_view(
struct _cef_view_t* self) {
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
@ -905,6 +918,7 @@ int CEF_CALLBACK browser_view_convert_point_from_view(struct _cef_view_t* self,
CefBrowserViewCppToC::CefBrowserViewCppToC() {
GetStruct()->get_browser = browser_view_get_browser;
GetStruct()->set_prefer_accelerators = browser_view_set_prefer_accelerators;
GetStruct()->base.as_browser_view = browser_view_as_browser_view;
GetStruct()->base.as_button = browser_view_as_button;
GetStruct()->base.as_panel = browser_view_as_panel;

View File

@ -518,6 +518,48 @@ void CEF_CALLBACK window_send_mouse_events(struct _cef_window_t* self,
mouse_up?true:false);
}
void CEF_CALLBACK window_set_accelerator(struct _cef_window_t* self,
int command_id, int key_code, int shift_pressed, int ctrl_pressed,
int alt_pressed) {
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
DCHECK(self);
if (!self)
return;
// Execute
CefWindowCppToC::Get(self)->SetAccelerator(
command_id,
key_code,
shift_pressed?true:false,
ctrl_pressed?true:false,
alt_pressed?true:false);
}
void CEF_CALLBACK window_remove_accelerator(struct _cef_window_t* self,
int command_id) {
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
DCHECK(self);
if (!self)
return;
// Execute
CefWindowCppToC::Get(self)->RemoveAccelerator(
command_id);
}
void CEF_CALLBACK window_remove_all_accelerators(struct _cef_window_t* self) {
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
DCHECK(self);
if (!self)
return;
// Execute
CefWindowCppToC::Get(self)->RemoveAllAccelerators();
}
struct _cef_window_t* CEF_CALLBACK window_as_window(struct _cef_panel_t* self) {
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
@ -1550,6 +1592,9 @@ CefWindowCppToC::CefWindowCppToC() {
GetStruct()->send_key_press = window_send_key_press;
GetStruct()->send_mouse_move = window_send_mouse_move;
GetStruct()->send_mouse_events = window_send_mouse_events;
GetStruct()->set_accelerator = window_set_accelerator;
GetStruct()->remove_accelerator = window_remove_accelerator;
GetStruct()->remove_all_accelerators = window_remove_all_accelerators;
GetStruct()->base.as_window = window_as_window;
GetStruct()->base.set_to_fill_layout = window_set_to_fill_layout;
GetStruct()->base.set_to_box_layout = window_set_to_box_layout;

View File

@ -153,6 +153,59 @@ int CEF_CALLBACK window_delegate_can_close(struct _cef_window_delegate_t* self,
return _retval;
}
int CEF_CALLBACK window_delegate_on_accelerator(
struct _cef_window_delegate_t* self, cef_window_t* window,
int command_id) {
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
DCHECK(self);
if (!self)
return 0;
// Verify param: window; type: refptr_diff
DCHECK(window);
if (!window)
return 0;
// Execute
bool _retval = CefWindowDelegateCppToC::Get(self)->OnAccelerator(
CefWindowCToCpp::Wrap(window),
command_id);
// Return type: bool
return _retval;
}
int CEF_CALLBACK window_delegate_on_key_event(
struct _cef_window_delegate_t* self, cef_window_t* window,
const struct _cef_key_event_t* event) {
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
DCHECK(self);
if (!self)
return 0;
// Verify param: window; type: refptr_diff
DCHECK(window);
if (!window)
return 0;
// Verify param: event; type: struct_byref_const
DCHECK(event);
if (!event)
return 0;
// Translate param: event; type: struct_byref_const
CefKeyEvent eventObj;
if (event)
eventObj.Set(*event, false);
// Execute
bool _retval = CefWindowDelegateCppToC::Get(self)->OnKeyEvent(
CefWindowCToCpp::Wrap(window),
eventObj);
// Return type: bool
return _retval;
}
cef_size_t CEF_CALLBACK window_delegate_get_preferred_size(
struct _cef_view_delegate_t* self, cef_view_t* view) {
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
@ -301,6 +354,8 @@ CefWindowDelegateCppToC::CefWindowDelegateCppToC() {
GetStruct()->can_maximize = window_delegate_can_maximize;
GetStruct()->can_minimize = window_delegate_can_minimize;
GetStruct()->can_close = window_delegate_can_close;
GetStruct()->on_accelerator = window_delegate_on_accelerator;
GetStruct()->on_key_event = window_delegate_on_key_event;
GetStruct()->base.base.get_preferred_size =
window_delegate_get_preferred_size;
GetStruct()->base.base.get_minimum_size = window_delegate_get_minimum_size;

View File

@ -81,6 +81,18 @@ CefRefPtr<CefBrowser> CefBrowserViewCToCpp::GetBrowser() {
return CefBrowserCToCpp::Wrap(_retval);
}
void CefBrowserViewCToCpp::SetPreferAccelerators(bool prefer_accelerators) {
cef_browser_view_t* _struct = GetStruct();
if (CEF_MEMBER_MISSING(_struct, set_prefer_accelerators))
return;
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
// Execute
_struct->set_prefer_accelerators(_struct,
prefer_accelerators);
}
CefRefPtr<CefBrowserView> CefBrowserViewCToCpp::AsBrowserView() {
cef_view_t* _struct = reinterpret_cast<cef_view_t*>(GetStruct());
if (CEF_MEMBER_MISSING(_struct, as_browser_view))

View File

@ -32,6 +32,7 @@ class CefBrowserViewCToCpp
// CefBrowserView methods.
CefRefPtr<CefBrowser> GetBrowser() OVERRIDE;
void SetPreferAccelerators(bool prefer_accelerators) OVERRIDE;
// CefView methods.
CefRefPtr<CefBrowserView> AsBrowserView() OVERRIDE;

View File

@ -505,6 +505,46 @@ void CefWindowCToCpp::SendMouseEvents(cef_mouse_button_type_t button,
mouse_up);
}
void CefWindowCToCpp::SetAccelerator(int command_id, int key_code,
bool shift_pressed, bool ctrl_pressed, bool alt_pressed) {
cef_window_t* _struct = GetStruct();
if (CEF_MEMBER_MISSING(_struct, set_accelerator))
return;
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
// Execute
_struct->set_accelerator(_struct,
command_id,
key_code,
shift_pressed,
ctrl_pressed,
alt_pressed);
}
void CefWindowCToCpp::RemoveAccelerator(int command_id) {
cef_window_t* _struct = GetStruct();
if (CEF_MEMBER_MISSING(_struct, remove_accelerator))
return;
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
// Execute
_struct->remove_accelerator(_struct,
command_id);
}
void CefWindowCToCpp::RemoveAllAccelerators() {
cef_window_t* _struct = GetStruct();
if (CEF_MEMBER_MISSING(_struct, remove_all_accelerators))
return;
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
// Execute
_struct->remove_all_accelerators(_struct);
}
CefRefPtr<CefWindow> CefWindowCToCpp::AsWindow() {
cef_panel_t* _struct = reinterpret_cast<cef_panel_t*>(GetStruct());
if (CEF_MEMBER_MISSING(_struct, as_window))

View File

@ -68,6 +68,10 @@ class CefWindowCToCpp
void SendMouseMove(int screen_x, int screen_y) OVERRIDE;
void SendMouseEvents(cef_mouse_button_type_t button, bool mouse_down,
bool mouse_up) OVERRIDE;
void SetAccelerator(int command_id, int key_code, bool shift_pressed,
bool ctrl_pressed, bool alt_pressed) OVERRIDE;
void RemoveAccelerator(int command_id) OVERRIDE;
void RemoveAllAccelerators() OVERRIDE;
// CefPanel methods.
CefRefPtr<CefWindow> AsWindow() OVERRIDE;

View File

@ -151,6 +151,50 @@ bool CefWindowDelegateCToCpp::CanClose(CefRefPtr<CefWindow> window) {
return _retval?true:false;
}
bool CefWindowDelegateCToCpp::OnAccelerator(CefRefPtr<CefWindow> window,
int command_id) {
cef_window_delegate_t* _struct = GetStruct();
if (CEF_MEMBER_MISSING(_struct, on_accelerator))
return false;
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
// Verify param: window; type: refptr_diff
DCHECK(window.get());
if (!window.get())
return false;
// Execute
int _retval = _struct->on_accelerator(_struct,
CefWindowCppToC::Wrap(window),
command_id);
// Return type: bool
return _retval?true:false;
}
bool CefWindowDelegateCToCpp::OnKeyEvent(CefRefPtr<CefWindow> window,
const CefKeyEvent& event) {
cef_window_delegate_t* _struct = GetStruct();
if (CEF_MEMBER_MISSING(_struct, on_key_event))
return false;
// AUTO-GENERATED CONTENT - DELETE THIS COMMENT BEFORE MODIFYING
// Verify param: window; type: refptr_diff
DCHECK(window.get());
if (!window.get())
return false;
// Execute
int _retval = _struct->on_key_event(_struct,
CefWindowCppToC::Wrap(window),
&event);
// Return type: bool
return _retval?true:false;
}
CefSize CefWindowDelegateCToCpp::GetPreferredSize(CefRefPtr<CefView> view) {
cef_view_delegate_t* _struct = reinterpret_cast<cef_view_delegate_t*>(
GetStruct());

View File

@ -40,6 +40,9 @@ class CefWindowDelegateCToCpp
bool CanMaximize(CefRefPtr<CefWindow> window) override;
bool CanMinimize(CefRefPtr<CefWindow> window) override;
bool CanClose(CefRefPtr<CefWindow> window) override;
bool OnAccelerator(CefRefPtr<CefWindow> window, int command_id) override;
bool OnKeyEvent(CefRefPtr<CefWindow> window,
const CefKeyEvent& event) override;
// CefPanelDelegate methods.

View File

@ -462,6 +462,12 @@ void ClientHandler::OnDraggableRegionsChanged(
NotifyDraggableRegions(regions);
}
void ClientHandler::OnTakeFocus(CefRefPtr<CefBrowser> browser, bool next) {
CEF_REQUIRE_UI_THREAD();
NotifyTakeFocus(next);
}
bool ClientHandler::OnRequestGeolocationPermission(
CefRefPtr<CefBrowser> browser,
const CefString& requesting_url,
@ -990,6 +996,18 @@ void ClientHandler::NotifyDraggableRegions(
delegate_->OnSetDraggableRegions(regions);
}
void ClientHandler::NotifyTakeFocus(bool next) {
if (!CURRENTLY_ON_MAIN_THREAD()) {
// Execute this method on the main thread.
MAIN_POST_CLOSURE(
base::Bind(&ClientHandler::NotifyTakeFocus, this, next));
return;
}
if (delegate_)
delegate_->OnTakeFocus(next);
}
void ClientHandler::BuildTestMenu(CefRefPtr<CefMenuModel> model) {
if (model->GetCount() > 0)
model->AddSeparator();

View File

@ -30,6 +30,7 @@ class ClientHandler : public CefClient,
public CefDisplayHandler,
public CefDownloadHandler,
public CefDragHandler,
public CefFocusHandler,
public CefGeolocationHandler,
public CefKeyboardHandler,
public CefLifeSpanHandler,
@ -70,6 +71,9 @@ class ClientHandler : public CefClient,
virtual void OnSetDraggableRegions(
const std::vector<CefDraggableRegion>& regions) = 0;
// Set focus to the next/previous control.
virtual void OnTakeFocus(bool next) {}
protected:
virtual ~Delegate() {}
};
@ -99,6 +103,9 @@ class ClientHandler : public CefClient,
CefRefPtr<CefDragHandler> GetDragHandler() OVERRIDE {
return this;
}
CefRefPtr<CefFocusHandler> GetFocusHandler() OVERRIDE {
return this;
}
CefRefPtr<CefGeolocationHandler> GetGeolocationHandler() OVERRIDE {
return this;
}
@ -168,11 +175,13 @@ class ClientHandler : public CefClient,
bool OnDragEnter(CefRefPtr<CefBrowser> browser,
CefRefPtr<CefDragData> dragData,
CefDragHandler::DragOperationsMask mask) OVERRIDE;
void OnDraggableRegionsChanged(
CefRefPtr<CefBrowser> browser,
const std::vector<CefDraggableRegion>& regions) OVERRIDE;
// CefFocusHandler methods
void OnTakeFocus(CefRefPtr<CefBrowser> browser, bool next) OVERRIDE;
// CefGeolocationHandler methods
bool OnRequestGeolocationPermission(
CefRefPtr<CefBrowser> browser,
@ -323,6 +332,7 @@ class ClientHandler : public CefClient,
bool canGoForward);
void NotifyDraggableRegions(
const std::vector<CefDraggableRegion>& regions);
void NotifyTakeFocus(bool next);
// Test context menu creation.
void BuildTestMenu(CefRefPtr<CefMenuModel> model);

View File

@ -329,6 +329,18 @@ void RootWindowViews::OnSetDraggableRegions(
window_->SetDraggableRegions(regions);
}
void RootWindowViews::OnTakeFocus(bool next) {
if (!CefCurrentlyOn(TID_UI)) {
// Execute this method on the UI thread.
CefPostTask(TID_UI,
base::Bind(&RootWindowViews::OnTakeFocus, this, next));
return;
}
if (window_)
window_->TakeFocus(next);
}
void RootWindowViews::CreateClientHandler(const std::string& url) {
DCHECK(!client_handler_);

View File

@ -73,6 +73,7 @@ class RootWindowViews : public RootWindow,
bool canGoForward) OVERRIDE;
void OnSetDraggableRegions(
const std::vector<CefDraggableRegion>& regions) OVERRIDE;
void OnTakeFocus(bool next) OVERRIDE;
private:
void CreateClientHandler(const std::string& url);

View File

@ -18,6 +18,7 @@
#if !defined(OS_WIN)
#define VK_RETURN 0x0D
#define VK_MENU 0x12 // ALT key.
#endif
namespace client {
@ -204,6 +205,21 @@ void ViewsWindow::SetDraggableRegions(
window_->SetDraggableRegions(window_regions);
}
void ViewsWindow::TakeFocus(bool next) {
CEF_REQUIRE_UI_THREAD();
if (!window_ || !with_controls_)
return;
if (next) {
// Focus is moving forwards (tab). Give focus to the URL textfield.
window_->GetViewForID(ID_URL_TEXTFIELD)->RequestFocus();
} else {
// Focus is moving backwards (tab+shift). Give focus to the menu button.
window_->GetViewForID(ID_MENU_BUTTON)->RequestFocus();
}
}
bool ViewsWindow::OnPopupBrowserViewCreated(
CefRefPtr<CefBrowserView> browser_view,
CefRefPtr<CefBrowserView> popup_browser_view,
@ -345,6 +361,9 @@ void ViewsWindow::OnWindowCreated(CefRefPtr<CefWindow> window) {
if (with_controls_) {
// Add the BrowserView and other controls to the Window.
AddControls();
// Add keyboard accelerators to the Window.
AddAccelerators();
} else {
// Add the BrowserView as the only child of the Window.
window_->AddChildView(browser_view_);
@ -386,6 +405,33 @@ bool ViewsWindow::IsFrameless(CefRefPtr<CefWindow> window) {
return frameless_;
}
bool ViewsWindow::OnAccelerator(CefRefPtr<CefWindow> window, int command_id) {
CEF_REQUIRE_UI_THREAD();
if (command_id == ID_QUIT) {
delegate_->OnExit();
return true;
}
return false;
}
bool ViewsWindow::OnKeyEvent(CefRefPtr<CefWindow> window,
const CefKeyEvent& event) {
CEF_REQUIRE_UI_THREAD();
if (!window_ || !with_controls_)
return false;
if (event.type == KEYEVENT_RAWKEYDOWN && event.windows_key_code == VK_MENU) {
// ALT key is pressed. Give focus to the menu button.
window_->GetViewForID(ID_MENU_BUTTON)->RequestFocus();
return true;
}
return false;
}
CefSize ViewsWindow::GetMinimumSize(CefRefPtr<CefView> view) {
CEF_REQUIRE_UI_THREAD();
@ -420,7 +466,7 @@ void ViewsWindow::CreateMenuModel() {
menu_model_ = CefMenuModel::CreateMenuModel(this);
// Create the test menu.
CefRefPtr<CefMenuModel> test_menu = menu_model_->AddSubMenu(0, "Tests");
CefRefPtr<CefMenuModel> test_menu = menu_model_->AddSubMenu(0, "&Tests");
test_menu->AddItem(ID_TESTS_GETSOURCE, "Get Source");
test_menu->AddItem(ID_TESTS_GETTEXT, "Get Text");
test_menu->AddItem(ID_TESTS_WINDOW_NEW, "New Window");
@ -436,7 +482,10 @@ void ViewsWindow::CreateMenuModel() {
test_menu->AddItem(ID_TESTS_PRINT_TO_PDF, "Print to PDF");
test_menu->AddItem(ID_TESTS_OTHER_TESTS, "Other Tests");
menu_model_->AddItem(ID_QUIT, "Exit");
menu_model_->AddItem(ID_QUIT, "E&xit");
// Show the accelerator shortcut text in the menu.
menu_model_->SetAcceleratorAt(1, 'X', false, false, true);
}
CefRefPtr<CefLabelButton> ViewsWindow::CreateBrowseButton(
@ -473,6 +522,8 @@ void ViewsWindow::AddControls() {
menu_button->SetImage(CEF_BUTTON_STATE_NORMAL, LoadImageIcon("menu_icon"));
// Override the default minimum size.
menu_button->SetMinimumSize(CefSize(0, 0));
// Menu button must be focusable for keyboard access to work.
menu_button->SetFocusable(true);
// Create the top panel.
CefRefPtr<CefPanel> top_panel = CefPanel::CreatePanel(NULL);
@ -524,6 +575,15 @@ void ViewsWindow::AddControls() {
minimum_window_size_ = CefSize(min_width, min_height);
}
void ViewsWindow::AddAccelerators() {
// Trigger accelerators without first forwarding to web content.
browser_view_->SetPreferAccelerators(true);
// Specify the accelerators to handle. OnAccelerator will be called when the
// accelerator is triggered.
window_->SetAccelerator(ID_QUIT, 'X', false, false, true);
}
void ViewsWindow::EnableView(int id, bool enable) {
if (!window_)
return;

View File

@ -83,6 +83,7 @@ class ViewsWindow : public CefBrowserViewDelegate,
bool canGoBack,
bool canGoForward);
void SetDraggableRegions(const std::vector<CefDraggableRegion>& regions);
void TakeFocus(bool next);
// CefBrowserViewDelegate methods:
bool OnPopupBrowserViewCreated(
@ -111,6 +112,9 @@ class ViewsWindow : public CefBrowserViewDelegate,
void OnWindowDestroyed(CefRefPtr<CefWindow> window) OVERRIDE;
bool IsFrameless(CefRefPtr<CefWindow> window) OVERRIDE;
bool CanClose(CefRefPtr<CefWindow> window) OVERRIDE;
bool OnAccelerator(CefRefPtr<CefWindow> window, int command_id) OVERRIDE;
bool OnKeyEvent(CefRefPtr<CefWindow> window,
const CefKeyEvent& event) OVERRIDE;
// CefViewDelegate methods:
CefSize GetMinimumSize(CefRefPtr<CefView> view) override;
@ -131,6 +135,9 @@ class ViewsWindow : public CefBrowserViewDelegate,
// Add controls to the Window.
void AddControls();
// Add keyboard accelerators to the Window.
void AddAccelerators();
// Enable or disable a view by |id|.
void EnableView(int id, bool enable);

View File

@ -250,10 +250,13 @@ void LabelButtonClick(CefRefPtr<CefWaitableEvent> event,
bool with_button_text,
bool with_button_image,
bool with_window_frame) {
TestWindowDelegate::RunTest(event,
TestWindowDelegate::Config config;
config.on_window_created =
base::Bind(RunLabelButtonClick, with_button_frame, with_button_text,
with_button_image),
!with_window_frame, false);
with_button_image);
config.frameless = !with_window_frame;
config.close_window = false;
TestWindowDelegate::RunTest(event, config);
}
void LabelButtonClickFramedWithTextWithImageFramedWindowImpl(
@ -465,10 +468,13 @@ void MenuButtonClick(CefRefPtr<CefWaitableEvent> event,
bool with_button_menu_marker,
bool with_button_image,
bool with_window_frame) {
TestWindowDelegate::RunTest(event,
TestWindowDelegate::Config config;
config.on_window_created =
base::Bind(RunMenuButtonClick, with_button_frame, with_button_text,
with_button_menu_marker, with_button_image),
!with_window_frame, false);
with_button_menu_marker, with_button_image);
config.frameless = !with_window_frame;
config.close_window = false;
TestWindowDelegate::RunTest(event, config);
}
void MenuButtonClickFramedWithTextWithMarkerWithImageFramedWindowImpl(

View File

@ -133,8 +133,9 @@ void RunScrollViewLayout(bool with_delegate,
void ScrollViewLayout(CefRefPtr<CefWaitableEvent> event,
bool with_delegate) {
TestWindowDelegate::RunTest(event,
base::Bind(RunScrollViewLayout, with_delegate), false);
TestWindowDelegate::Config config;
config.on_window_created = base::Bind(RunScrollViewLayout, with_delegate);
TestWindowDelegate::RunTest(event, config);
}
void ScrollViewLayoutWithDelegateImpl(CefRefPtr<CefWaitableEvent> event) {

View File

@ -23,13 +23,9 @@ const int TestWindowDelegate::kWSize = 400;
// static
void TestWindowDelegate::RunTest(CefRefPtr<CefWaitableEvent> event,
const WindowTest& window_test,
bool frameless,
bool close_window,
int window_size) {
const Config& config) {
CefWindow::CreateTopLevelWindow(
new TestWindowDelegate(event, window_test, frameless, close_window,
window_size));
new TestWindowDelegate(event, config));
}
void TestWindowDelegate::OnWindowCreated(CefRefPtr<CefWindow> window) {
@ -60,22 +56,22 @@ void TestWindowDelegate::OnWindowCreated(CefRefPtr<CefWindow> window) {
// Size will come from GetPreferredSize() on initial Window creation.
EXPECT_TRUE(got_get_preferred_size_);
CefRect client_bounds = window->GetClientAreaBoundsInScreen();
if (frameless_) {
EXPECT_EQ(window_size_, client_bounds.width);
EXPECT_EQ(window_size_, client_bounds.height);
if (config_.frameless) {
EXPECT_EQ(config_.window_size, client_bounds.width);
EXPECT_EQ(config_.window_size, client_bounds.height);
} else {
// Client area bounds calculation might have off-by-one errors on Windows
// due to non-client frame size being calculated internally in pixels and
// then converted to DIPs. See http://crbug.com/602692.
EXPECT_TRUE(abs(client_bounds.width - window_size_) <= 1);
EXPECT_TRUE(abs(client_bounds.height - window_size_) <= 1);
EXPECT_TRUE(abs(client_bounds.width - config_.window_size) <= 1);
EXPECT_TRUE(abs(client_bounds.height - config_.window_size) <= 1);
}
// Run the requested test.
if (!window_test_.is_null())
window_test_.Run(window);
// Run the callback.
if (!config_.on_window_created.is_null())
config_.on_window_created.Run(window);
if (close_window_) {
if (config_.close_window) {
// Close the window asynchronously.
CefPostTask(TID_UI,
base::Bind(&TestWindowDelegate::OnCloseWindow, this));
@ -97,6 +93,10 @@ void TestWindowDelegate::OnWindowDestroyed(CefRefPtr<CefWindow> window) {
EXPECT_FALSE(window->IsVisible());
EXPECT_FALSE(window->IsDrawn());
// Run the callback.
if (!config_.on_window_destroyed.is_null())
config_.on_window_destroyed.Run(window);
window_ = nullptr;
// Don't execute the timeout callback.
@ -104,24 +104,32 @@ void TestWindowDelegate::OnWindowDestroyed(CefRefPtr<CefWindow> window) {
}
bool TestWindowDelegate::IsFrameless(CefRefPtr<CefWindow> window) {
return frameless_;
return config_.frameless;
}
CefSize TestWindowDelegate::GetPreferredSize(CefRefPtr<CefView> view) {
got_get_preferred_size_ = true;
return CefSize(window_size_, window_size_);
return CefSize(config_.window_size, config_.window_size);
}
bool TestWindowDelegate::OnAccelerator(CefRefPtr<CefWindow> window,
int command_id) {
if (!config_.on_accelerator.is_null())
return config_.on_accelerator.Run(window_, command_id);
return false;
}
bool TestWindowDelegate::OnKeyEvent(CefRefPtr<CefWindow> window,
const CefKeyEvent& event) {
if (!config_.on_key_event.is_null())
return config_.on_key_event.Run(window_, event);
return false;
}
TestWindowDelegate::TestWindowDelegate(CefRefPtr<CefWaitableEvent> event,
const WindowTest& window_test,
bool frameless,
bool close_window,
int window_size)
const Config& config)
: event_(event),
window_test_(window_test),
frameless_(frameless),
close_window_(close_window),
window_size_(window_size),
config_(config),
weak_ptr_factory_(this) {
}

View File

@ -14,7 +14,21 @@ class TestWindowDelegate : public CefWindowDelegate {
static const int kWSize;
// Test execution callback.
typedef base::Callback<void(CefRefPtr<CefWindow>)> WindowTest;
typedef base::Callback<void(CefRefPtr<CefWindow>)> OnWindowCreatedCallback;
typedef base::Callback<void(CefRefPtr<CefWindow>)> OnWindowDestroyedCallback;
typedef base::Callback<bool(CefRefPtr<CefWindow>,int)> OnAcceleratorCallback;
typedef base::Callback<bool(CefRefPtr<CefWindow>,const CefKeyEvent&)>
OnKeyEventCallback;
struct Config {
OnWindowCreatedCallback on_window_created;
OnWindowDestroyedCallback on_window_destroyed;
OnAcceleratorCallback on_accelerator;
OnKeyEventCallback on_key_event;
bool frameless = false;
bool close_window = true;
int window_size = kWSize;
};
// Creates a Window with a new TestWindowDelegate instance and executes
// |window_test| after the Window is created. |event| will be signaled once
@ -23,33 +37,27 @@ class TestWindowDelegate : public CefWindowDelegate {
// immediately after |window_test| returns. Otherwise, the caller is
// responsible for closing the Window passed to |window_test|.
static void RunTest(CefRefPtr<CefWaitableEvent> event,
const WindowTest& window_test,
bool frameless = false,
bool close_window = true,
int window_size = kWSize);
const Config& config);
// CefWindowDelegate methods:
void OnWindowCreated(CefRefPtr<CefWindow> window) override;
void OnWindowDestroyed(CefRefPtr<CefWindow> window) override;
bool IsFrameless(CefRefPtr<CefWindow> window) override;
CefSize GetPreferredSize(CefRefPtr<CefView> view) override;
bool OnAccelerator(CefRefPtr<CefWindow> window, int command_id) override;
bool OnKeyEvent(CefRefPtr<CefWindow> window,
const CefKeyEvent& event) override;
private:
TestWindowDelegate(CefRefPtr<CefWaitableEvent> event,
const WindowTest& window_test,
bool frameless,
bool close_window,
int window_size);
const Config& config);
~TestWindowDelegate() override;
void OnCloseWindow();
void OnTimeoutWindow();
CefRefPtr<CefWaitableEvent> event_;
WindowTest window_test_;
bool frameless_;
bool close_window_;
int window_size_;
Config config_;
CefRefPtr<CefWindow> window_;

View File

@ -278,8 +278,10 @@ void RunTextfieldKeyEvent(CefRefPtr<CefWindow> window) {
}
void TextfieldKeyEventImpl(CefRefPtr<CefWaitableEvent> event) {
TestWindowDelegate::RunTest(event,
base::Bind(RunTextfieldKeyEvent), false, false);
TestWindowDelegate::Config config;
config.on_window_created = base::Bind(RunTextfieldKeyEvent);
config.close_window = false;
TestWindowDelegate::RunTest(event, config);
}
} // namespace

View File

@ -14,6 +14,10 @@
#define WINDOW_TEST_ASYNC(name) UI_THREAD_TEST_ASYNC(ViewsWindowTest, name)
#if !defined(OS_WIN)
#define VK_MENU 0x12 // ALT key.
#endif
namespace {
// Window state change delay in MS.
@ -33,11 +37,14 @@ void ExpectCloseRects(const CefRect& expected,
}
void WindowCreateImpl(CefRefPtr<CefWaitableEvent> event) {
TestWindowDelegate::RunTest(event, TestWindowDelegate::WindowTest(), false);
TestWindowDelegate::Config config;
TestWindowDelegate::RunTest(event, config);
}
void WindowCreateFramelessImpl(CefRefPtr<CefWaitableEvent> event) {
TestWindowDelegate::RunTest(event, TestWindowDelegate::WindowTest(), true);
TestWindowDelegate::Config config;
config.frameless = true;
TestWindowDelegate::RunTest(event, config);
}
void RunWindowShowHide(CefRefPtr<CefWindow> window) {
@ -52,11 +59,16 @@ void RunWindowShowHide(CefRefPtr<CefWindow> window) {
}
void WindowShowHideImpl(CefRefPtr<CefWaitableEvent> event) {
TestWindowDelegate::RunTest(event, base::Bind(RunWindowShowHide), false);
TestWindowDelegate::Config config;
config.on_window_created = base::Bind(RunWindowShowHide);
TestWindowDelegate::RunTest(event, config);
}
void WindowShowHideFramelessImpl(CefRefPtr<CefWaitableEvent> event) {
TestWindowDelegate::RunTest(event, base::Bind(RunWindowShowHide), true);
TestWindowDelegate::Config config;
config.on_window_created = base::Bind(RunWindowShowHide);
config.frameless = true;
TestWindowDelegate::RunTest(event, config);
}
const int kWPanel1ID = 1;
@ -180,11 +192,16 @@ void RunWindowLayoutAndCoords(CefRefPtr<CefWindow> window) {
}
void WindowLayoutAndCoordsImpl(CefRefPtr<CefWaitableEvent> event) {
TestWindowDelegate::RunTest(event, base::Bind(RunWindowLayoutAndCoords), false);
TestWindowDelegate::Config config;
config.on_window_created = base::Bind(RunWindowLayoutAndCoords);
TestWindowDelegate::RunTest(event, config);
}
void WindowLayoutAndCoordsFramelessImpl(CefRefPtr<CefWaitableEvent> event) {
TestWindowDelegate::RunTest(event, base::Bind(RunWindowLayoutAndCoords), true);
TestWindowDelegate::Config config;
config.on_window_created = base::Bind(RunWindowLayoutAndCoords);
config.frameless = true;
TestWindowDelegate::RunTest(event, config);
}
void VerifyRestore(CefRefPtr<CefWindow> window) {
@ -223,13 +240,18 @@ void RunWindowMaximize(CefRefPtr<CefWindow> window) {
}
void WindowMaximizeImpl(CefRefPtr<CefWaitableEvent> event) {
TestWindowDelegate::RunTest(event, base::Bind(RunWindowMaximize), false,
false);
TestWindowDelegate::Config config;
config.on_window_created = base::Bind(RunWindowMaximize);
config.close_window = false;
TestWindowDelegate::RunTest(event, config);
}
void WindowMaximizeFramelessImpl(CefRefPtr<CefWaitableEvent> event) {
TestWindowDelegate::RunTest(event, base::Bind(RunWindowMaximize), true,
false);
TestWindowDelegate::Config config;
config.on_window_created = base::Bind(RunWindowMaximize);
config.frameless = true;
config.close_window = false;
TestWindowDelegate::RunTest(event, config);
}
void VerifyMinimize(CefRefPtr<CefWindow> window) {
@ -260,13 +282,18 @@ void RunWindowMinimize(CefRefPtr<CefWindow> window) {
}
void WindowMinimizeImpl(CefRefPtr<CefWaitableEvent> event) {
TestWindowDelegate::RunTest(event, base::Bind(RunWindowMinimize), false,
false);
TestWindowDelegate::Config config;
config.on_window_created = base::Bind(RunWindowMinimize);
config.close_window = false;
TestWindowDelegate::RunTest(event, config);
}
void WindowMinimizeFramelessImpl(CefRefPtr<CefWaitableEvent> event) {
TestWindowDelegate::RunTest(event, base::Bind(RunWindowMinimize), true,
false);
TestWindowDelegate::Config config;
config.on_window_created = base::Bind(RunWindowMinimize);
config.frameless = true;
config.close_window = false;
TestWindowDelegate::RunTest(event, config);
}
void VerifyFullscreenExit(CefRefPtr<CefWindow> window) {
@ -307,13 +334,18 @@ void RunWindowFullscreen(CefRefPtr<CefWindow> window) {
}
void WindowFullscreenImpl(CefRefPtr<CefWaitableEvent> event) {
TestWindowDelegate::RunTest(event, base::Bind(RunWindowFullscreen), false,
false);
TestWindowDelegate::Config config;
config.on_window_created = base::Bind(RunWindowFullscreen);
config.close_window = false;
TestWindowDelegate::RunTest(event, config);
}
void WindowFullscreenFramelessImpl(CefRefPtr<CefWaitableEvent> event) {
TestWindowDelegate::RunTest(event, base::Bind(RunWindowFullscreen), true,
false);
TestWindowDelegate::Config config;
config.on_window_created = base::Bind(RunWindowFullscreen);
config.frameless = true;
config.close_window = false;
TestWindowDelegate::RunTest(event, config);
}
void RunWindowIcon(CefRefPtr<CefWindow> window) {
@ -333,11 +365,113 @@ void RunWindowIcon(CefRefPtr<CefWindow> window) {
}
void WindowIconImpl(CefRefPtr<CefWaitableEvent> event) {
TestWindowDelegate::RunTest(event, base::Bind(RunWindowIcon), false);
TestWindowDelegate::Config config;
config.on_window_created = base::Bind(RunWindowIcon);
TestWindowDelegate::RunTest(event, config);
}
void WindowIconFramelessImpl(CefRefPtr<CefWaitableEvent> event) {
TestWindowDelegate::RunTest(event, base::Bind(RunWindowIcon), true);
TestWindowDelegate::Config config;
config.on_window_created = base::Bind(RunWindowIcon);
config.frameless = true;
TestWindowDelegate::RunTest(event, config);
}
const int kChar = 'A';
const int kCloseWindowId = 2;
bool got_accelerator;
int got_key_event_alt_count;
bool got_key_event_char;
void TriggerAccelerator(CefRefPtr<CefWindow> window) {
window->SendKeyPress(kChar, EVENTFLAG_ALT_DOWN);
}
bool OnKeyEvent(CefRefPtr<CefWindow> window, const CefKeyEvent& event) {
if (event.type != KEYEVENT_RAWKEYDOWN)
return false;
if (event.windows_key_code == VK_MENU) {
// First we get the ALT key press in all cases.
EXPECT_FALSE(got_key_event_char);
if (got_key_event_alt_count == 0)
EXPECT_FALSE(got_accelerator);
else
EXPECT_TRUE(got_accelerator);
EXPECT_EQ(event.modifiers, EVENTFLAG_ALT_DOWN);
got_key_event_alt_count++;
} else if (event.windows_key_code == kChar) {
// Then we get the char key press with the ALT modifier if the accelerator
// isn't registered.
EXPECT_TRUE(got_accelerator);
EXPECT_EQ(got_key_event_alt_count, 2);
EXPECT_FALSE(got_key_event_char);
EXPECT_EQ(event.modifiers, EVENTFLAG_ALT_DOWN);
got_key_event_char = true;
// Call this method just to make sure it doesn't crash.
window->RemoveAllAccelerators();
// End the test by closing the Window.
window->Close();
return true;
}
return false;
}
bool OnAccelerator(CefRefPtr<CefWindow> window, int command_id) {
EXPECT_FALSE(got_accelerator);
EXPECT_EQ(got_key_event_alt_count, 1);
EXPECT_FALSE(got_key_event_char);
EXPECT_EQ(kCloseWindowId, command_id);
got_accelerator = true;
// Remove the accelerator.
window->RemoveAccelerator(kCloseWindowId);
// Now send the event without the accelerator registered. Should result in a
// call to OnKeyEvent.
TriggerAccelerator(window);
return true;
}
void RunWindowAccelerator(CefRefPtr<CefWindow> window) {
window->SetAccelerator(kCloseWindowId, kChar, false, false, true);
window->Show();
CefPostDelayedTask(TID_UI, base::Bind(TriggerAccelerator, window),
kStateDelayMS);
}
void VerifyWindowAccelerator(CefRefPtr<CefWindow> window) {
EXPECT_TRUE(got_accelerator);
EXPECT_EQ(got_key_event_alt_count, 2);
EXPECT_TRUE(got_key_event_char);
}
// Expected order of events:
// 1. OnKeyEvent for ALT key press.
// 2. OnAccelerator for ALT+Char key press (with accelerator registered).
// 3. OnKeyEvent for ALT key press.
// 4. OnKeyEvent for ALT+Char key press (without accelerator registered).
void WindowAcceleratorImpl(CefRefPtr<CefWaitableEvent> event) {
got_accelerator = false;
got_key_event_alt_count = 0;
got_key_event_char = false;
TestWindowDelegate::Config config;
config.on_window_created = base::Bind(RunWindowAccelerator);
config.on_window_destroyed = base::Bind(VerifyWindowAccelerator);
config.on_accelerator = base::Bind(OnAccelerator);
config.on_key_event = base::Bind(OnKeyEvent);
config.close_window = false;
TestWindowDelegate::RunTest(event, config);
}
} // namespace
@ -359,3 +493,4 @@ WINDOW_TEST_ASYNC(WindowFullscreen);
WINDOW_TEST_ASYNC(WindowFullscreenFrameless);
WINDOW_TEST_ASYNC(WindowIcon);
WINDOW_TEST_ASYNC(WindowIconFrameless);
WINDOW_TEST_ASYNC(WindowAccelerator);