1
0
Fork 0
mirror of https://github.com/juce-framework/JUCE.git synced 2026-01-10 23:44:24 +00:00

WebBrowserComponent: Windows: Add accessibility integration

This commit is contained in:
attila 2023-04-17 10:21:48 +02:00 committed by Attila Szarvas
parent 6ef45eb20c
commit 7657efd227
12 changed files with 381 additions and 29 deletions

View file

@ -28,6 +28,63 @@ namespace juce
AccessibilityHandler* AccessibilityHandler::currentlyFocusedHandler = nullptr;
class NativeChildHandler
{
public:
static NativeChildHandler& getInstance()
{
static NativeChildHandler instance;
return instance;
}
void* getNativeChild (Component& component) const
{
if (auto it = nativeChildForComponent.find (&component);
it != nativeChildForComponent.end())
{
return it->second;
}
return nullptr;
}
Component* getComponent (void* nativeChild) const
{
if (auto it = componentForNativeChild.find (nativeChild);
it != componentForNativeChild.end())
{
return it->second;
}
return nullptr;
}
void setNativeChild (Component& component, void* nativeChild)
{
clearComponent (component);
if (nativeChild != nullptr)
{
nativeChildForComponent[&component] = nativeChild;
componentForNativeChild[nativeChild] = &component;
}
}
private:
NativeChildHandler() = default;
void clearComponent (Component& component)
{
if (auto* nativeChild = getNativeChild (component))
componentForNativeChild.erase (nativeChild);
nativeChildForComponent.erase (&component);
}
std::map<void*, Component*> componentForNativeChild;
std::map<Component*, void*> nativeChildForComponent;
};
AccessibilityHandler::AccessibilityHandler (Component& comp,
AccessibilityRole accessibilityRole,
AccessibilityActions accessibilityActions,
@ -322,6 +379,21 @@ std::unique_ptr<AccessibilityHandler::AccessibilityNativeImpl> AccessibilityHand
#endif
}
void* AccessibilityHandler::getNativeChildForComponent (Component& component)
{
return NativeChildHandler::getInstance().getNativeChild (component);
}
Component* AccessibilityHandler::getComponentForNativeChild (void* nativeChild)
{
return NativeChildHandler::getInstance().getComponent (nativeChild);
}
void AccessibilityHandler::setNativeChildForComponent (Component& component, void* nativeChild)
{
NativeChildHandler::getInstance().setNativeChild (component, nativeChild);
}
#if ! JUCE_NATIVE_ACCESSIBILITY_INCLUDED
void AccessibilityHandler::notifyAccessibilityEvent (AccessibilityEvent) const {}
void AccessibilityHandler::postAnnouncement (const String&, AnnouncementPriority) {}

View file

@ -291,6 +291,26 @@ public:
AccessibilityNativeHandle* getNativeImplementation() const;
/** @internal */
std::type_index getTypeIndex() const { return typeIndex; }
/** @internal */
static void clearCurrentlyFocusedHandler() { currentlyFocusedHandler = nullptr; }
/** @internal
The following functions provide the means to associate JUCE Components with OS specific
types that provide their own accessibility mechanisms. This way accessibility navigation
can move from a JUCE Component to a native, embedded window and back.
These functions assume that the concrete types behind the void* are
- Windows: HWND
- MacOS: NSView*
- iOS: UIView*
- Android: GlobalRef that points to an android.view.View
*/
static void* getNativeChildForComponent (Component& component);
/** @internal */
static void setNativeChildForComponent (Component& component, void* nativeChild);
/** @internal */
static Component* getComponentForNativeChild (void* nativeChild);
private:
//==============================================================================

View file

@ -2182,7 +2182,7 @@ void Component::internalMouseDown (MouseInputSource source,
if (! flags.dontFocusOnMouseClickFlag)
{
grabKeyboardFocusInternal (focusChangedByMouseClick, true);
grabKeyboardFocusInternal (focusChangedByMouseClick, true, FocusChangeDirection::unknown);
if (checker.shouldBailOut())
return;
@ -2435,17 +2435,20 @@ void Component::internalBroughtToFront()
//==============================================================================
void Component::focusGained (FocusChangeType) {}
void Component::focusGainedWithDirection (FocusChangeType, FocusChangeDirection) {}
void Component::focusLost (FocusChangeType) {}
void Component::focusOfChildComponentChanged (FocusChangeType) {}
void Component::internalKeyboardFocusGain (FocusChangeType cause)
{
internalKeyboardFocusGain (cause, WeakReference<Component> (this));
internalKeyboardFocusGain (cause, WeakReference<Component> (this), FocusChangeDirection::unknown);
}
void Component::internalKeyboardFocusGain (FocusChangeType cause,
const WeakReference<Component>& safePointer)
const WeakReference<Component>& safePointer,
FocusChangeDirection direction)
{
focusGainedWithDirection (cause, direction);
focusGained (cause);
if (safePointer == nullptr)
@ -2585,7 +2588,7 @@ std::unique_ptr<ComponentTraverser> Component::createKeyboardFocusTraverser()
return parentComponent->createKeyboardFocusTraverser();
}
void Component::takeKeyboardFocus (FocusChangeType cause)
void Component::takeKeyboardFocus (FocusChangeType cause, FocusChangeDirection direction)
{
if (currentlyFocusedComponent == this)
return;
@ -2614,11 +2617,11 @@ void Component::takeKeyboardFocus (FocusChangeType cause)
componentLosingFocus->internalKeyboardFocusLoss (cause);
if (currentlyFocusedComponent == this)
internalKeyboardFocusGain (cause, safePointer);
internalKeyboardFocusGain (cause, safePointer, direction);
}
}
void Component::grabKeyboardFocusInternal (FocusChangeType cause, bool canTryParent)
void Component::grabKeyboardFocusInternal (FocusChangeType cause, bool canTryParent, FocusChangeDirection direction)
{
if (! isShowing())
return;
@ -2626,7 +2629,7 @@ void Component::grabKeyboardFocusInternal (FocusChangeType cause, bool canTryPar
if (flags.wantsKeyboardFocusFlag
&& (isEnabled() || parentComponent == nullptr))
{
takeKeyboardFocus (cause);
takeKeyboardFocus (cause, direction);
return;
}
@ -2637,7 +2640,7 @@ void Component::grabKeyboardFocusInternal (FocusChangeType cause, bool canTryPar
{
if (auto* defaultComp = traverser->getDefaultComponent (this))
{
defaultComp->grabKeyboardFocusInternal (cause, false);
defaultComp->grabKeyboardFocusInternal (cause, false, direction);
return;
}
}
@ -2645,7 +2648,7 @@ void Component::grabKeyboardFocusInternal (FocusChangeType cause, bool canTryPar
// if no children want it and we're allowed to try our parent comp,
// then pass up to parent, which will try our siblings.
if (canTryParent && parentComponent != nullptr)
parentComponent->grabKeyboardFocusInternal (cause, true);
parentComponent->grabKeyboardFocusInternal (cause, true, direction);
}
void Component::grabKeyboardFocus()
@ -2654,7 +2657,7 @@ void Component::grabKeyboardFocus()
// thread, you'll need to use a MessageManagerLock object to make sure it's thread-safe.
JUCE_ASSERT_MESSAGE_MANAGER_IS_LOCKED
grabKeyboardFocusInternal (focusChangedDirectly, true);
grabKeyboardFocusInternal (focusChangedDirectly, true, FocusChangeDirection::unknown);
// A component can only be focused when it's actually on the screen!
// If this fails then you're probably trying to grab the focus before you've
@ -2730,7 +2733,10 @@ void Component::moveKeyboardFocusToSibling (bool moveToNext)
return;
}
nextComp->grabKeyboardFocusInternal (focusChangedByTabKey, true);
nextComp->grabKeyboardFocusInternal (focusChangedByTabKey,
true,
moveToNext ? FocusChangeDirection::forward
: FocusChangeDirection::backward);
return;
}
}

View file

@ -1891,11 +1891,28 @@ public:
focusChangedDirectly /**< Means that the focus was changed by a call to grabKeyboardFocus(). */
};
/** Enumeration used by the focusGainedWithDirection() method. */
enum class FocusChangeDirection
{
unknown,
forward,
backward
};
/** Called to indicate that this component has just acquired the keyboard focus.
@see focusLost, setWantsKeyboardFocus, getCurrentlyFocusedComponent, hasKeyboardFocus
*/
virtual void focusGained (FocusChangeType cause);
/** Called to indicate that this component has just acquired the keyboard focus.
This function is called every time focusGained() is called but it has an additional change
direction parameter.
@see focusLost, setWantsKeyboardFocus, getCurrentlyFocusedComponent, hasKeyboardFocus
*/
virtual void focusGainedWithDirection (FocusChangeType cause, FocusChangeDirection direction);
/** Called to indicate that this component has just lost the keyboard focus.
@see focusGained, setWantsKeyboardFocus, getCurrentlyFocusedComponent, hasKeyboardFocus
*/
@ -2614,7 +2631,7 @@ private:
void internalMouseWheel (MouseInputSource, Point<float>, Time, const MouseWheelDetails&);
void internalMagnifyGesture (MouseInputSource, Point<float>, Time, float);
void internalBroughtToFront();
void internalKeyboardFocusGain (FocusChangeType, const WeakReference<Component>&);
void internalKeyboardFocusGain (FocusChangeType, const WeakReference<Component>&, FocusChangeDirection);
void internalKeyboardFocusGain (FocusChangeType);
void internalKeyboardFocusLoss (FocusChangeType);
void internalChildKeyboardFocusChange (FocusChangeType, const WeakReference<Component>&);
@ -2632,8 +2649,8 @@ private:
void sendMovedResizedMessagesIfPending();
void repaintParent();
void sendFakeMouseMove() const;
void takeKeyboardFocus (FocusChangeType);
void grabKeyboardFocusInternal (FocusChangeType, bool canTryParent);
void takeKeyboardFocus (FocusChangeType, FocusChangeDirection);
void grabKeyboardFocusInternal (FocusChangeType, bool canTryParent, FocusChangeDirection);
void giveAwayKeyboardFocusInternal (bool sendFocusLossEvent);
void sendEnablementChangeMessage();
void sendVisibilityChangeMessage();

View file

@ -166,10 +166,15 @@ JUCE_COMRESULT AccessibilityNativeHandle::get_HostRawElementProvider (IRawElemen
{
return withCheckedComArgs (pRetVal, *this, [&]
{
if (isFragmentRoot())
if (auto* wrapper = WindowsUIAWrapper::getInstanceWithoutCreating())
if (auto* wrapper = WindowsUIAWrapper::getInstanceWithoutCreating())
{
if (isFragmentRoot())
return wrapper->hostProviderFromHwnd ((HWND) accessibilityHandler.getComponent().getWindowHandle(), pRetVal);
if (auto* embeddedWindow = static_cast<HWND> (AccessibilityHandler::getNativeChildForComponent (accessibilityHandler.getComponent())))
return wrapper->hostProviderFromHwnd (embeddedWindow, pRetVal);
}
return S_OK;
});
}
@ -180,6 +185,10 @@ JUCE_COMRESULT AccessibilityNativeHandle::get_ProviderOptions (ProviderOptions*
return E_INVALIDARG;
*options = (ProviderOptions) (ProviderOptions_ServerSideProvider | ProviderOptions_UseComThreading);
if (AccessibilityHandler::getNativeChildForComponent (accessibilityHandler.getComponent()) != nullptr)
*options |= ProviderOptions_OverrideProvider;
return S_OK;
}
@ -618,6 +627,18 @@ JUCE_COMRESULT AccessibilityNativeHandle::GetFocus (ComTypes::IRawElementProvide
});
}
JUCE_COMRESULT AccessibilityNativeHandle::GetOverrideProviderForHwnd (HWND hwnd, IRawElementProviderSimple** pRetVal)
{
return withCheckedComArgs (pRetVal, *this, [&]
{
if (auto* component = AccessibilityHandler::getComponentForNativeChild (hwnd))
if (auto* handler = component->getAccessibilityHandler())
handler->getNativeImplementation()->QueryInterface (IID_PPV_ARGS (pRetVal));
return S_OK;
});
}
//==============================================================================
String AccessibilityNativeHandle::getElementName() const
{

View file

@ -27,6 +27,7 @@ namespace juce
{
class AccessibilityNativeHandle : public ComBaseClassHelper<IRawElementProviderSimple,
IRawElementProviderHwndOverride,
ComTypes::IRawElementProviderFragment,
ComTypes::IRawElementProviderFragmentRoot>
{
@ -58,6 +59,8 @@ public:
JUCE_COMRESULT ElementProviderFromPoint (double x, double y, ComTypes::IRawElementProviderFragment** pRetVal) override;
JUCE_COMRESULT GetFocus (ComTypes::IRawElementProviderFragment** pRetVal) override;
JUCE_COMRESULT GetOverrideProviderForHwnd (HWND hwnd, IRawElementProviderSimple** pRetVal) override;
private:
//==============================================================================
String getElementName() const;

View file

@ -4147,6 +4147,21 @@ private:
//==============================================================================
case WM_SETFOCUS:
/* When the HWND receives Focus from the system it sends a
UIA_AutomationFocusChangedEventId notification redirecting the focus to the HWND
itself. This is a built-in behaviour of the HWND.
This means that whichever JUCE managed provider was active before the entire
window lost and then regained the focus, loses its focused state, and the
window's root element will become focused under which all JUCE managed providers
can be found.
This needs to be reflected on currentlyFocusedHandler so that the JUCE
accessibility mechanisms can detect that the root window got the focus, and send
another FocusChanged event to the system to redirect focus to a JUCE managed
provider if necessary.
*/
AccessibilityHandler::clearCurrentlyFocusedHandler();
updateKeyModifiers();
handleFocusGain();
break;

View file

@ -264,12 +264,17 @@ public:
/** @internal */
void visibilityChanged() override;
/** @internal */
void focusGained (FocusChangeType) override;
void focusGainedWithDirection (FocusChangeType, FocusChangeDirection) override;
/** @internal */
class Pimpl;
private:
std::unique_ptr<AccessibilityHandler> createAccessibilityHandler() override
{
return std::make_unique<AccessibilityHandler> (*this, AccessibilityRole::group);
}
//==============================================================================
std::unique_ptr<Pimpl> browser;
bool blankPageShown = false, unloadPageWhenHidden;

View file

@ -676,7 +676,7 @@ void WebBrowserComponent::visibilityChanged()
checkWindowAssociation();
}
void WebBrowserComponent::focusGained (FocusChangeType)
void WebBrowserComponent::focusGainedWithDirection (FocusChangeType, FocusChangeDirection)
{
}

View file

@ -1036,7 +1036,7 @@ void WebBrowserComponent::visibilityChanged()
checkWindowAssociation();
}
void WebBrowserComponent::focusGained (FocusChangeType)
void WebBrowserComponent::focusGainedWithDirection (FocusChangeType, FocusChangeDirection)
{
}

View file

@ -724,7 +724,7 @@ void WebBrowserComponent::visibilityChanged()
checkWindowAssociation();
}
void WebBrowserComponent::focusGained (FocusChangeType)
void WebBrowserComponent::focusGainedWithDirection (FocusChangeType, FocusChangeDirection)
{
}

View file

@ -351,11 +351,56 @@ private:
#if JUCE_USE_WIN_WEBVIEW2
#include <winuser.h>
using namespace Microsoft::WRL;
static std::vector<HWND> getDirectChildWindows (HWND hwnd)
{
std::vector<HWND> result;
const auto getNextChildWindow = [hwnd, &result]
{
return FindWindowExA (hwnd, result.empty() ? nullptr : result.back(), nullptr, nullptr);
};
for (auto* next = getNextChildWindow(); next != nullptr; next = getNextChildWindow())
result.push_back (next);
return result;
}
static void forEachChildWindowRecursive (HWND hwnd, std::function<bool (HWND)> callback)
{
// EnumChildWindows itself provides the recursion
EnumChildWindows (hwnd,
[] (HWND hwnd, LPARAM lParam)
{
auto* callbackPtr = reinterpret_cast<std::function<bool (HWND)>*> (lParam);
return (*callbackPtr) (hwnd) ? TRUE : FALSE;
},
reinterpret_cast<LPARAM> (&callback));
}
static bool anyChildWindow (HWND hwnd, std::function<bool (HWND)> predicate)
{
auto result = false;
forEachChildWindowRecursive (hwnd,
[&predicate, &result] (auto* child)
{
result = predicate (child);
const auto keepGoing = ! result;
return keepGoing;
});
return result;
}
class WebView2 : public InternalWebViewType,
public Component,
public ComponentMovementWatcher
public ComponentMovementWatcher,
private AsyncUpdater
{
public:
WebView2 (WebBrowserComponent& o, const WebBrowserComponent::Options& prefs)
@ -372,6 +417,26 @@ public:
owner.addAndMakeVisible (this);
}
void focusGainedWithDirection (FocusChangeType, FocusChangeDirection direction) override
{
if (inMoveFocusRequested)
return;
const auto moveFocusReason = [&]
{
if (direction == FocusChangeDirection::backward)
return COREWEBVIEW2_MOVE_FOCUS_REASON_PREVIOUS;
if (direction == FocusChangeDirection::forward)
return COREWEBVIEW2_MOVE_FOCUS_REASON_NEXT;
return COREWEBVIEW2_MOVE_FOCUS_REASON_PROGRAMMATIC;
}();
if (webViewController != nullptr)
webViewController->MoveFocus (moveFocusReason);
}
~WebView2() override
{
removeEventHandlers();
@ -389,7 +454,9 @@ public:
bool hasBrowserBeenCreated() override
{
return webView != nullptr || isCreating;
return webView != nullptr
|| webView2ConstructionHelper.webView2BeingCreated == this
|| webView2ConstructionHelper.viewsWaitingForCreation.contains (this);
}
void goToURL (const String& url, const StringArray* headers, const MemoryBlock* postData) override
@ -462,6 +529,11 @@ public:
owner.visibilityChanged();
}
std::unique_ptr<AccessibilityHandler> createAccessibilityHandler() override
{
return std::make_unique<AccessibilityHandler> (*this, AccessibilityRole::group);
}
//==============================================================================
struct WebViewHandle
{
@ -470,7 +542,7 @@ public:
ComSmartPtr<ICoreWebView2Environment> environment;
};
static std::optional<WebViewHandle> createWebViewHandle(const WebBrowserComponent::Options::WinWebView2& options)
static std::optional<WebViewHandle> createWebViewHandle (const WebBrowserComponent::Options::WinWebView2& options)
{
using CreateWebViewEnvironmentWithOptionsFunc = HRESULT (*) (PCWSTR, PCWSTR,
ICoreWebView2EnvironmentOptions*,
@ -645,6 +717,45 @@ private:
return S_OK;
}).Get(), &webResourceRequestedToken);
}
if (webViewController != nullptr)
{
webViewController->add_MoveFocusRequested (Callback<ICoreWebView2MoveFocusRequestedEventHandler> (
[this] (ICoreWebView2Controller*, ICoreWebView2MoveFocusRequestedEventArgs* args) -> HRESULT
{
ScopedValueSetter scope { inMoveFocusRequested, true };
auto* comp = [&]() -> Component*
{
auto* c = owner.getParentComponent();
if (c == nullptr)
return nullptr;
const auto traverser = c->createFocusTraverser();
if (COREWEBVIEW2_MOVE_FOCUS_REASON reason;
args->get_Reason (&reason) == S_OK && reason == COREWEBVIEW2_MOVE_FOCUS_REASON_PREVIOUS)
{
// The previous Component to the embedded WebView2 Component is the
// WebBrowserComponent. Here we want to skip that and jump to the
// Component that comes before it.
return traverser->getPreviousComponent (&owner);
}
// The Component that comes immediately after the WebBrowserComponent is the
// embedded WebView2. We want to jump to the Component that comes after that.
return traverser->getNextComponent (this);
}();
if (comp != nullptr)
comp->getAccessibilityHandler()->grabFocus();
else
giveAwayKeyboardFocus();
return S_OK;
}).Get(), &moveFocusRequestedToken);
}
}
void removeEventHandlers()
@ -669,6 +780,12 @@ private:
webView->remove_WebResourceRequested (webResourceRequestedToken);
}
}
if (webViewController != nullptr)
{
if (moveFocusRequestedToken.value != 0)
webViewController->remove_MoveFocusRequested (moveFocusRequestedToken);
}
}
void setWebViewPreferences()
@ -710,7 +827,18 @@ private:
{
if (auto* peer = getPeer())
{
isCreating = true;
// We enforce the serial creation of WebView2 instances so that our HWND association
// logic can work. Multiple HWNDs can belong to the same browser process, so the only
// way to identify which belongs to which WebView2 is to associate them with each other
// in the order of creation.
if (webView2ConstructionHelper.webView2BeingCreated != nullptr)
{
webView2ConstructionHelper.viewsWaitingForCreation.insert (this);
return;
}
webView2ConstructionHelper.viewsWaitingForCreation.erase (this);
webView2ConstructionHelper.webView2BeingCreated = this;
WeakReference<WebView2> weakThis (this);
@ -720,7 +848,7 @@ private:
{
if (weakThis != nullptr)
{
weakThis->isCreating = false;
webView2ConstructionHelper.webView2BeingCreated = nullptr;
if (controller != nullptr)
{
@ -729,6 +857,40 @@ private:
if (weakThis->webView != nullptr)
{
if (UINT32 browserProcessId;
weakThis->webView->get_BrowserProcessId (&browserProcessId) == S_OK)
{
auto* self = weakThis.get();
auto* webView2WindowHandle = static_cast<HWND> (self->getWindowHandle());
// There is no WebView2 API for getting the HWND hosting
// the WebView2 content. So we iterate over all child
// windows of the JUCE peer HWND, and try to figure out
// which one belongs to a WebView2. What we are looking for
// is a window that has a child window that belongs to the
// browserProcessId.
const auto directChildWindows = getDirectChildWindows (webView2WindowHandle);
for (auto* childWindow : directChildWindows)
{
if (! self->webView2ConstructionHelper.associatedWebViewNativeWindows.contains (childWindow))
{
if (anyChildWindow (childWindow,
[browserProcessId] (auto* childOfChild)
{
if (DWORD procId; GetWindowThreadProcessId (childOfChild, &procId) != 0)
return (UINT32) procId == browserProcessId;
return false;
}))
{
webView2ConstructionHelper.associatedWebViewNativeWindows.insert (childWindow);
AccessibilityHandler::setNativeChildForComponent (*self, childWindow);
}
}
}
}
weakThis->addEventHandlers();
weakThis->setWebViewPreferences();
weakThis->componentMovedOrResized (true, true);
@ -737,6 +899,9 @@ private:
weakThis->webView->Navigate (weakThis->urlRequest.url.toWideCharPointer());
}
}
if (! weakThis->webView2ConstructionHelper.viewsWaitingForCreation.empty())
(*weakThis->webView2ConstructionHelper.viewsWaitingForCreation.begin())->triggerAsyncUpdate();
}
return S_OK;
@ -746,6 +911,11 @@ private:
void closeWebView()
{
if (auto* webViewNativeWindow = AccessibilityHandler::getNativeChildForComponent (*this))
webView2ConstructionHelper.associatedWebViewNativeWindows.erase (webViewNativeWindow);
AccessibilityHandler::setNativeChildForComponent (*this, nullptr);
if (webViewController != nullptr)
{
webViewController->Close();
@ -756,6 +926,12 @@ private:
webViewHandle.environment = nullptr;
}
//==============================================================================
void handleAsyncUpdate() override
{
createWebView();
}
//==============================================================================
void setControlBounds (Rectangle<int> newBounds) const
{
@ -790,7 +966,10 @@ private:
newWindowRequestedToken { 0 },
windowCloseRequestedToken { 0 },
navigationCompletedToken { 0 },
webResourceRequestedToken { 0 };
webResourceRequestedToken { 0 },
moveFocusRequestedToken { 0 };
bool inMoveFocusRequested = false;
struct URLRequest
{
@ -801,7 +980,14 @@ private:
URLRequest urlRequest;
bool isCreating = false;
struct WebView2ConstructionHelper
{
WebView2* webView2BeingCreated;
std::set<WebView2*> viewsWaitingForCreation;
std::set<void*> associatedWebViewNativeWindows;
};
inline static WebView2ConstructionHelper webView2ConstructionHelper;
//==============================================================================
JUCE_DECLARE_WEAK_REFERENCEABLE (WebView2)
@ -969,9 +1155,16 @@ void WebBrowserComponent::visibilityChanged()
checkWindowAssociation();
}
void WebBrowserComponent::focusGained (FocusChangeType)
void WebBrowserComponent::focusGainedWithDirection (FocusChangeType type, FocusChangeDirection dir)
{
browser->getInternalWebView().focusGained();
ignoreUnused (type, dir);
#if JUCE_USE_WIN_WEBVIEW2
if (auto* webView2 = dynamic_cast<WebView2*> (&browser->getInternalWebView()))
webView2->focusGainedWithDirection (type, dir);
else
#endif
browser->getInternalWebView().focusGained();
}
void WebBrowserComponent::clearCookies()