Skip to content

Commit fb08b49

Browse files
No commit message
1 parent fef4e93 commit fb08b49

File tree

1 file changed

+146
-0
lines changed

1 file changed

+146
-0
lines changed

Public/DefaultFocusHandler.cs

Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
// Copyright © 2014 The CefSharp Authors. All rights reserved.
2+
//
3+
// Use of this source code is governed by a BSD-style license that can be found in the LICENSE file.
4+
5+
namespace CefSharp.WinForms.Internals
6+
{
7+
/// <summary>
8+
/// Default implementation of <see cref="IFocusHandler" />
9+
/// for the WinForms implementation
10+
/// </summary>
11+
/// <seealso cref="CefSharp.IFocusHandler" />
12+
public class DefaultFocusHandler : IFocusHandler
13+
{
14+
private bool initialFocusOnNavigation;
15+
/// <summary>
16+
/// Called when the browser component has received focus.
17+
/// </summary>
18+
/// <param name="chromiumWebBrowser">the ChromiumWebBrowser control</param>
19+
/// <param name="browser">the browser object</param>
20+
/// <remarks>Try to avoid needing to override this logic in a subclass. The implementation in
21+
/// DefaultFocusHandler relies on very detailed behavior of how WinForms and
22+
/// Windows interact during window activation.</remarks>
23+
public virtual void OnGotFocus(IWebBrowser chromiumWebBrowser, IBrowser browser)
24+
{
25+
//We don't deal with popups as they're rendered by default entirely by CEF
26+
//For print dialogs the browser will be null, we don't want to deal with that either.
27+
if (browser == null || browser.IsPopup)
28+
{
29+
return;
30+
}
31+
32+
var winFormsChromiumWebBrowser = (ChromiumWebBrowser)chromiumWebBrowser;
33+
// During application activation, CEF receives a WM_SETFOCUS
34+
// message from Windows because it is the top window
35+
// on the CEF UI thread.
36+
//
37+
// If the WinForm ChromiumWebBrowser control is the
38+
// current .ActiveControl before app activation
39+
// then we MUST NOT try to reactivate the WinForm
40+
// control during activation because that will
41+
// start a race condition between reactivating
42+
// the CEF control AND having another control
43+
// that should be the new .ActiveControl.
44+
//
45+
// For example:
46+
// * CEF control has focus, and thus ChromiumWebBrowser
47+
// is the current .ActiveControl
48+
// * Alt-Tab to another application
49+
// * Click a non CEF control in the WinForms application.
50+
// * This begins the Windows activation process.
51+
// * The WM_ACTIVATE process on the WinForm UI thread
52+
// will update .ActiveControl to the clicked control.
53+
// The clicked control will receive WM_SETFOCUS as well.
54+
// (i.e. OnGotFocus)
55+
// If the ChromiumWebBrowser was the previous .ActiveControl,
56+
// then we set .Activating = true.
57+
// * The WM_ACTIVATE process on the CEF thread will
58+
// send WM_SETFOCUS to CEF thus staring the race of
59+
// which will end first, the WndProc WM_ACTIVATE process
60+
// on the WinForm UI thread or the WM_ACTIVATE process
61+
// on the CEF UI thread.
62+
// * CEF will then call this method on the CEF UI thread
63+
// due to WM_SETFOCUS.
64+
// * This method will clear the activation state (if any)
65+
// on the ChromiumWebBrowser control, due to the race
66+
// condition the WinForm UI thread cannot.
67+
if (winFormsChromiumWebBrowser.IsActivating)
68+
{
69+
winFormsChromiumWebBrowser.IsActivating = false;
70+
}
71+
else
72+
{
73+
// Otherwise, we're not being activated
74+
// so we must activate the ChromiumWebBrowser control
75+
// for WinForms focus tracking.
76+
winFormsChromiumWebBrowser.InvokeOnUiThreadIfRequired(() =>
77+
{
78+
winFormsChromiumWebBrowser.Activate();
79+
});
80+
}
81+
}
82+
83+
/// <summary>
84+
/// Called when the browser component is requesting focus.
85+
/// </summary>
86+
/// <param name="chromiumWebBrowser">the ChromiumWebBrowser control</param>
87+
/// <param name="browser">the browser object</param>
88+
/// <param name="source">Indicates where the focus request is originating from.</param>
89+
/// <returns>Return false to allow the focus to be set or true to cancel setting the focus.</returns>
90+
public virtual bool OnSetFocus(IWebBrowser chromiumWebBrowser, IBrowser browser, CefFocusSource source)
91+
{
92+
//We don't deal with popups as they're rendered by default entirely by CEF
93+
if (browser.IsPopup)
94+
{
95+
return false;
96+
}
97+
98+
var focusSourceNavigation = source == CefFocusSource.FocusSourceNavigation;
99+
100+
var winFormsBrowser = (ChromiumWebBrowser)chromiumWebBrowser;
101+
102+
//The default behaviour when browser is activated by default
103+
//This was the default prior to version 73
104+
if (winFormsBrowser.ActivateBrowserOnCreation)
105+
{
106+
// Do not let the browser take focus when a Load method has been called
107+
return focusSourceNavigation;
108+
}
109+
110+
//For the very first navigation we let the browser
111+
//take focus so touch screens work correctly.
112+
//See https://github.com/cefsharp/CefSharp/issues/2776
113+
if (!initialFocusOnNavigation && focusSourceNavigation)
114+
{
115+
initialFocusOnNavigation = true;
116+
117+
return false;
118+
}
119+
120+
// Do not let the browser take focus when a Load method has been called
121+
return focusSourceNavigation;
122+
}
123+
124+
/// <summary>
125+
/// Called when the browser component is about to lose focus.
126+
/// For instance, if focus was on the last HTML element and the user pressed the TAB key.
127+
/// </summary>
128+
/// <param name="chromiumWebBrowser">the ChromiumWebBrowser control</param>
129+
/// <param name="browser">the browser object</param>
130+
/// <param name="next">Will be true if the browser is giving focus to the next component
131+
/// and false if the browser is giving focus to the previous component.</param>
132+
public virtual void OnTakeFocus(IWebBrowser chromiumWebBrowser, IBrowser browser, bool next)
133+
{
134+
//We don't deal with popups as they're rendered by default entirely by CEF
135+
if (browser.IsPopup)
136+
{
137+
return;
138+
}
139+
140+
var winFormsChromiumWebBrowser = (ChromiumWebBrowser)chromiumWebBrowser;
141+
142+
// NOTE: OnTakeFocus means leaving focus / not taking focus
143+
winFormsChromiumWebBrowser.InvokeOnUiThreadIfRequired(() => winFormsChromiumWebBrowser.SelectNextControl(next));
144+
}
145+
}
146+
}

0 commit comments

Comments
 (0)