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