chromiumembedded / cef

Chromium Embedded Framework (CEF). A simple framework for embedding Chromium-based browsers in other applications.
https://bitbucket.org/chromiumembedded/cef/
Other
3.38k stars 467 forks source link

cefsimple: browser doesn't receive input focus on launch #3819

Closed aquilarubra closed 2 weeks ago

aquilarubra commented 4 weeks ago

Describe the bug I am trying to modify cefsimple example and set focus on the browser when the app is first launched. I found out that it does not work, unless I explicitly click somewhere in the browser.

To Reproduce Steps to reproduce the behavior:

  1. Implement OnPreKeyEvent. In my case, I was trying to prevent accelerators keys. Example (you can add a cout here, and you will see it is never triggered at app first launch, meaning that the browser did not receive focus):

    bool SimpleHandler::OnPreKeyEvent(CefRefPtr browser, const CefKeyEvent& event, CefEventHandle os_event, bool* is_keyboard_shortcut) { if (event.type != KEYEVENT_RAWKEYDOWN && event.type != KEYEVENT_KEYDOWN) return false;

    // Check for modifiers bool ctrl = (event.modifiers & EVENTFLAG_CONTROL_DOWN) != 0; bool shift = (event.modifiers & EVENTFLAG_SHIFT_DOWN) != 0; bool cmd = (event.modifiers & EVENTFLAG_COMMAND_DOWN) != 0; // For macOS //bool alt = (event.modifiers & EVENTFLAG_ALT_DOWN) != 0;

    // Helper lambda to check for ctrl on Windows/Linux or cmd on macOS auto ctrlOrCmd = [ctrl, cmd]() {

    if defined(OS_MAC)

    return cmd;

    else

    return ctrl;

    endif

    };

    // Block F1, F7, F12 (DevTools) if (event.native_key_code == 0xffc9 || // Linux F12 event.windows_key_code == VK_F12 || // Windows F12 event.native_key_code == 0x7B || // macOS F12 event.native_key_code == 0xffbe || // Linux F1 event.windows_key_code == VK_F1 || // Windows F1 event.native_key_code == 0x7A || // macOS F1 event.native_key_code == 0xffc4 || // Linux F7 event.windows_key_code == VK_F7 || // Windows F7 event.native_key_code == 0x76) { // macOS F7 return true; }

    // Block any combination where Ctrl or Cmd is pressed if (ctrlOrCmd()) { return true; }

    return false; }

  2. Set focus wherever appropriate, to window, browser_view, and browser.

Example: in SimpleWindowDelegate, browserview->RequestFocus(); Implement OnBeforeResourceLoad with browser->GetHost()->SetFocus(true); Implement OnLoadEnd with browser->GetHost()->SetFocus(true); Implement delayed focus to the browser in OnWindowCreated; Implement CefFocusHandler and OnFocusedNodeChanged (it won't get fired at app first launch).

  1. Launch the app and press F12, or CTRL+P, etc. If the focus was set, it should have no effect, but instead the accelerator keys still work, until one clicks somewhere inside the browser; then, the browser component correctly receive focus and the app behaves as expected.

Expected behavior Cefbrowser should receive focus at app startup.

Versions (please complete the following information):

Additional context I only tested cefsimple with the url "https://www.google.com".

I cannot reproduce on Google Chrome, because it's not possible to determine which component is having focus at first launch.

I also noticed that, once the browser receives focus, OnFocusedNodeChanged correctly triggers when I click inside the browser. But When I click outside the app, OnTakeFocus never fires up. Also, CefWindow's RemoveAllAccelerators does nothing, always in respect to app's startup. So it must be some general issue with focus.

magreenblatt commented 2 weeks ago

The BrowserView should receive focus when the cefsimple app is launched due to the RequestFocus call. For example, when loading google.com you should see a blinking cursor on the search field.

When I click outside the app, OnTakeFocus never fires up

This may only be called when focus moves to a different element in the same window, not when the window itself loses focus.

CefWindow's RemoveAllAccelerators does nothing

This may not remove accelerators registered internally by Chrome.

magreenblatt commented 2 weeks ago

For example, when loading google.com you should see a blinking cursor on the search field.

This doesn't work with cefsimple or cefclient on Windows or macOS either (tested M131). The window does have focus as indicated by pressing the TAB key to move between different elements. With cefclient the address bar gets focus first when pressing the TAB key.

With Google Chrome (launching with the URL in the shortcut on Windows) the search field gets initial focus as expected.

magreenblatt commented 2 weeks ago

This doesn't work with cefsimple or cefclient on Windows or macOS either (tested M131).

This works as expected with --use-alloy-style

magreenblatt commented 2 weeks ago

It looks like the call to RequestFocus in OnWindowCreated is a no-op. With Alloy style initial focus is assigned via:

* thread #1, name = 'CrBrowserMain', queue = 'com.apple.main-thread', stop reason = breakpoint 1.1
  * frame #0: 0x00000003d4f0a9c0 Chromium Embedded Framework`views::FocusManager::SetFocusedViewWithReason(this=0x0000010401fec1c0, view=0x0000010400186800, reason=kDirectFocusChange) at focus_manager.cc:296:3
    frame #1: 0x00000003d4f0ba58 Chromium Embedded Framework`views::FocusManager::SetFocusedView(this=0x0000010401fec1c0, view=0x0000010400186800) at focus_manager.cc:354:3
    frame #2: 0x00000003d4fbee9c Chromium Embedded Framework`views::View::RequestFocus(this=0x0000010400186800) at view.cc:1986:22
    frame #3: 0x00000003b72213b4 Chromium Embedded Framework`CefBrowserPlatformDelegateViews::SetFocus(this=0x0000010401a5dbc0, setFocus=true) at browser_platform_delegate_views.cc:165:33
    frame #4: 0x00000003b6f426f0 Chromium Embedded Framework`AlloyBrowserHostImpl::OnSetFocus(this=0x00000104002ad200, source=FOCUS_SOURCE_NAVIGATION) at alloy_browser_host_impl.cc:650:25
    frame #5: 0x00000003b6fa1390 Chromium Embedded Framework`CefBrowserHostBase::LoadMainFrameURL(this=0x00000104002ad200, params=0x000000016fdfbfb8) at browser_host_base.cc:1234:5
    frame #6: 0x00000003b6f3e8a4 Chromium Embedded Framework`AlloyBrowserHostImpl::Create(create_params=0x0000010400177c80) at alloy_browser_host_impl.cc:149:14
magreenblatt commented 2 weeks ago

Part of the problem is that View::RequestFocus calls IsFocusable, which returns false because View::GetFocusBehavior returns FocusBehavior::NEVER (the View in this case is a ChromeBrowserView). This is the default value for View::focus_behavior_. We need to explicitly give focus to the child views::WebView instead.