mirror of
				https://bitbucket.org/chromiumembedded/cef
				synced 2025-06-05 21:39:12 +02:00 
			
		
		
		
	
		
			
				
	
	
		
			696 lines
		
	
	
		
			22 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			696 lines
		
	
	
		
			22 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
// Copyright 2017 The Chromium Embedded Framework Authors. Portions copyright
 | 
						|
// 2013 The Chromium Authors. All rights reserved. Use of this source code is
 | 
						|
// governed by a BSD-style license that can be found in the LICENSE file.
 | 
						|
 | 
						|
// This class implements our accessible proxy object that handles moving
 | 
						|
// data back and forth between MSAA clients and CefClient renderers.
 | 
						|
// Sample implementation based on ui\accessibility\ax_platform_node_win.h
 | 
						|
 | 
						|
#include "tests/cefclient/browser/osr_accessibility_node.h"
 | 
						|
 | 
						|
#if defined(CEF_USE_ATL)
 | 
						|
 | 
						|
#include <atlbase.h>
 | 
						|
#include <oleacc.h>
 | 
						|
#include <string>
 | 
						|
 | 
						|
#include "tests/cefclient/browser/osr_accessibility_helper.h"
 | 
						|
 | 
						|
namespace client {
 | 
						|
 | 
						|
// Return CO_E_OBJNOTCONNECTED for accessible objects thar still exists but the
 | 
						|
// window and/or object it references has been destroyed.
 | 
						|
#define DATACHECK(node) (node) ? S_OK : CO_E_OBJNOTCONNECTED
 | 
						|
#define VALID_CHILDID(varChild) ((varChild.vt == VT_I4))
 | 
						|
 | 
						|
namespace {
 | 
						|
 | 
						|
// Helper function to convert a rectangle from client coordinates to screen
 | 
						|
// coordinates.
 | 
						|
void ClientToScreen(HWND hwnd, LPRECT lpRect) {
 | 
						|
  if (lpRect) {
 | 
						|
    POINT ptTL = {lpRect->left, lpRect->top};
 | 
						|
    POINT ptBR = {lpRect->right, lpRect->bottom};
 | 
						|
    // Win32 API only provides the call for a point.
 | 
						|
    ClientToScreen(hwnd, &ptTL);
 | 
						|
    ClientToScreen(hwnd, &ptBR);
 | 
						|
    SetRect(lpRect, ptTL.x, ptTL.y, ptBR.x, ptBR.y);
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
// Helper function to convert to MSAARole
 | 
						|
int AxRoleToMSAARole(const std::string& role_string) {
 | 
						|
  if (role_string == "alert")
 | 
						|
    return ROLE_SYSTEM_ALERT;
 | 
						|
  if (role_string == "application")
 | 
						|
    return ROLE_SYSTEM_APPLICATION;
 | 
						|
  if (role_string == "buttonDropDown")
 | 
						|
    return ROLE_SYSTEM_BUTTONDROPDOWN;
 | 
						|
  if (role_string == "popUpButton")
 | 
						|
    return ROLE_SYSTEM_BUTTONMENU;
 | 
						|
  if (role_string == "checkBox")
 | 
						|
    return ROLE_SYSTEM_CHECKBUTTON;
 | 
						|
  if (role_string == "comboBox")
 | 
						|
    return ROLE_SYSTEM_COMBOBOX;
 | 
						|
  if (role_string == "dialog")
 | 
						|
    return ROLE_SYSTEM_DIALOG;
 | 
						|
  if (role_string == "genericContainer")
 | 
						|
    return ROLE_SYSTEM_GROUPING;
 | 
						|
  if (role_string == "group")
 | 
						|
    return ROLE_SYSTEM_GROUPING;
 | 
						|
  if (role_string == "image")
 | 
						|
    return ROLE_SYSTEM_GRAPHIC;
 | 
						|
  if (role_string == "link")
 | 
						|
    return ROLE_SYSTEM_LINK;
 | 
						|
  if (role_string == "locationBar")
 | 
						|
    return ROLE_SYSTEM_GROUPING;
 | 
						|
  if (role_string == "menuBar")
 | 
						|
    return ROLE_SYSTEM_MENUBAR;
 | 
						|
  if (role_string == "menuItem")
 | 
						|
    return ROLE_SYSTEM_MENUITEM;
 | 
						|
  if (role_string == "menuListPopup")
 | 
						|
    return ROLE_SYSTEM_MENUPOPUP;
 | 
						|
  if (role_string == "tree")
 | 
						|
    return ROLE_SYSTEM_OUTLINE;
 | 
						|
  if (role_string == "treeItem")
 | 
						|
    return ROLE_SYSTEM_OUTLINEITEM;
 | 
						|
  if (role_string == "tab")
 | 
						|
    return ROLE_SYSTEM_PAGETAB;
 | 
						|
  if (role_string == "tabList")
 | 
						|
    return ROLE_SYSTEM_PAGETABLIST;
 | 
						|
  if (role_string == "pane")
 | 
						|
    return ROLE_SYSTEM_PANE;
 | 
						|
  if (role_string == "progressIndicator")
 | 
						|
    return ROLE_SYSTEM_PROGRESSBAR;
 | 
						|
  if (role_string == "button")
 | 
						|
    return ROLE_SYSTEM_PUSHBUTTON;
 | 
						|
  if (role_string == "radioButton")
 | 
						|
    return ROLE_SYSTEM_RADIOBUTTON;
 | 
						|
  if (role_string == "scrollBar")
 | 
						|
    return ROLE_SYSTEM_SCROLLBAR;
 | 
						|
  if (role_string == "splitter")
 | 
						|
    return ROLE_SYSTEM_SEPARATOR;
 | 
						|
  if (role_string == "slider")
 | 
						|
    return ROLE_SYSTEM_SLIDER;
 | 
						|
  if (role_string == "staticText")
 | 
						|
    return ROLE_SYSTEM_STATICTEXT;
 | 
						|
  if (role_string == "textField")
 | 
						|
    return ROLE_SYSTEM_TEXT;
 | 
						|
  if (role_string == "titleBar")
 | 
						|
    return ROLE_SYSTEM_TITLEBAR;
 | 
						|
  if (role_string == "toolbar")
 | 
						|
    return ROLE_SYSTEM_TOOLBAR;
 | 
						|
  if (role_string == "webView")
 | 
						|
    return ROLE_SYSTEM_GROUPING;
 | 
						|
  if (role_string == "window")
 | 
						|
    return ROLE_SYSTEM_WINDOW;
 | 
						|
  if (role_string == "client")
 | 
						|
    return ROLE_SYSTEM_CLIENT;
 | 
						|
  // This is the default role for MSAA.
 | 
						|
  return ROLE_SYSTEM_CLIENT;
 | 
						|
}
 | 
						|
 | 
						|
static inline int MiddleX(const CefRect& rect) {
 | 
						|
  return rect.x + rect.width / 2;
 | 
						|
}
 | 
						|
 | 
						|
static inline int MiddleY(const CefRect& rect) {
 | 
						|
  return rect.y + rect.height / 2;
 | 
						|
}
 | 
						|
 | 
						|
}  // namespace
 | 
						|
 | 
						|
struct CefIAccessible : public IAccessible {
 | 
						|
 public:
 | 
						|
  // Implement IUnknown
 | 
						|
  STDMETHODIMP QueryInterface(REFIID riid, void** ppvObject) override;
 | 
						|
  STDMETHODIMP_(ULONG) AddRef() override;
 | 
						|
  STDMETHODIMP_(ULONG) Release() override;
 | 
						|
 | 
						|
  //
 | 
						|
  // IAccessible methods.
 | 
						|
  //
 | 
						|
  // Retrieves the child element or child object at a given point on the screen.
 | 
						|
  STDMETHODIMP accHitTest(LONG x_left, LONG y_top, VARIANT* child) override;
 | 
						|
 | 
						|
  // Performs the object's default action.
 | 
						|
  STDMETHODIMP accDoDefaultAction(VARIANT var_id) override;
 | 
						|
 | 
						|
  // Retrieves the specified object's current screen location.
 | 
						|
  STDMETHODIMP accLocation(LONG* x_left,
 | 
						|
                           LONG* y_top,
 | 
						|
                           LONG* width,
 | 
						|
                           LONG* height,
 | 
						|
                           VARIANT var_id) override;
 | 
						|
 | 
						|
  // Traverses to another UI element and retrieves the object.
 | 
						|
  STDMETHODIMP accNavigate(LONG nav_dir, VARIANT start, VARIANT* end) override;
 | 
						|
 | 
						|
  // Retrieves an IDispatch interface pointer for the specified child.
 | 
						|
  STDMETHODIMP get_accChild(VARIANT var_child, IDispatch** disp_child) override;
 | 
						|
 | 
						|
  // Retrieves the number of accessible children.
 | 
						|
  STDMETHODIMP get_accChildCount(LONG* child_count) override;
 | 
						|
 | 
						|
  // Retrieves a string that describes the object's default action.
 | 
						|
  STDMETHODIMP get_accDefaultAction(VARIANT var_id,
 | 
						|
                                    BSTR* default_action) override;
 | 
						|
 | 
						|
  // Retrieves the tooltip description.
 | 
						|
  STDMETHODIMP get_accDescription(VARIANT var_id, BSTR* desc) override;
 | 
						|
 | 
						|
  // Retrieves the object that has the keyboard focus.
 | 
						|
  STDMETHODIMP get_accFocus(VARIANT* focus_child) override;
 | 
						|
 | 
						|
  // Retrieves the specified object's shortcut.
 | 
						|
  STDMETHODIMP get_accKeyboardShortcut(VARIANT var_id,
 | 
						|
                                       BSTR* access_key) override;
 | 
						|
 | 
						|
  // Retrieves the name of the specified object.
 | 
						|
  STDMETHODIMP get_accName(VARIANT var_id, BSTR* name) override;
 | 
						|
 | 
						|
  // Retrieves the IDispatch interface of the object's parent.
 | 
						|
  STDMETHODIMP get_accParent(IDispatch** disp_parent) override;
 | 
						|
 | 
						|
  // Retrieves information describing the role of the specified object.
 | 
						|
  STDMETHODIMP get_accRole(VARIANT var_id, VARIANT* role) override;
 | 
						|
 | 
						|
  // Retrieves the current state of the specified object.
 | 
						|
  STDMETHODIMP get_accState(VARIANT var_id, VARIANT* state) override;
 | 
						|
 | 
						|
  // Gets the help string for the specified object.
 | 
						|
  STDMETHODIMP get_accHelp(VARIANT var_id, BSTR* help) override;
 | 
						|
 | 
						|
  // Retrieve or set the string value associated with the specified object.
 | 
						|
  // Setting the value is not typically used by screen readers, but it's
 | 
						|
  // used frequently by automation software.
 | 
						|
  STDMETHODIMP get_accValue(VARIANT var_id, BSTR* value) override;
 | 
						|
  STDMETHODIMP put_accValue(VARIANT var_id, BSTR new_value) override;
 | 
						|
 | 
						|
  // IAccessible methods not implemented.
 | 
						|
  STDMETHODIMP get_accSelection(VARIANT* selected) override;
 | 
						|
  STDMETHODIMP accSelect(LONG flags_sel, VARIANT var_id) override;
 | 
						|
  STDMETHODIMP get_accHelpTopic(BSTR* help_file,
 | 
						|
                                VARIANT var_id,
 | 
						|
                                LONG* topic_id) override;
 | 
						|
  STDMETHODIMP put_accName(VARIANT var_id, BSTR put_name) override;
 | 
						|
 | 
						|
  // Implement IDispatch
 | 
						|
  STDMETHODIMP GetTypeInfoCount(unsigned int FAR* pctinfo) override;
 | 
						|
  STDMETHODIMP GetTypeInfo(unsigned int iTInfo,
 | 
						|
                           LCID lcid,
 | 
						|
                           ITypeInfo FAR* FAR* ppTInfo) override;
 | 
						|
  STDMETHODIMP GetIDsOfNames(REFIID riid,
 | 
						|
                             OLECHAR FAR* FAR* rgszNames,
 | 
						|
                             unsigned int cNames,
 | 
						|
                             LCID lcid,
 | 
						|
                             DISPID FAR* rgDispId) override;
 | 
						|
  STDMETHODIMP Invoke(DISPID dispIdMember,
 | 
						|
                      REFIID riid,
 | 
						|
                      LCID lcid,
 | 
						|
                      WORD wFlags,
 | 
						|
                      DISPPARAMS FAR* pDispParams,
 | 
						|
                      VARIANT FAR* pVarResult,
 | 
						|
                      EXCEPINFO FAR* pExcepInfo,
 | 
						|
                      unsigned int FAR* puArgErr) override;
 | 
						|
 | 
						|
  CefIAccessible(OsrAXNode* node) : ref_count_(0), node_(node) {}
 | 
						|
 | 
						|
  // Remove the node reference when OsrAXNode is destroyed, so that
 | 
						|
  // MSAA clients get  CO_E_OBJNOTCONNECTED
 | 
						|
  void MarkDestroyed() { node_ = nullptr; }
 | 
						|
 | 
						|
 protected:
 | 
						|
  virtual ~CefIAccessible() {}
 | 
						|
 | 
						|
  // Ref Count
 | 
						|
  ULONG ref_count_;
 | 
						|
  // OsrAXNode* proxy object
 | 
						|
  OsrAXNode* node_;
 | 
						|
};
 | 
						|
 | 
						|
// Implement IUnknown
 | 
						|
// *********************
 | 
						|
 | 
						|
// Handles ref counting and querying for other supported interfaces.
 | 
						|
// We only support, IUnknown, IDispatch and IAccessible.
 | 
						|
STDMETHODIMP CefIAccessible::QueryInterface(REFIID riid, void** ppvObject) {
 | 
						|
  if (riid == IID_IAccessible)
 | 
						|
    *ppvObject = static_cast<IAccessible*>(this);
 | 
						|
  else if (riid == IID_IDispatch)
 | 
						|
    *ppvObject = static_cast<IDispatch*>(this);
 | 
						|
  else if (riid == IID_IUnknown)
 | 
						|
    *ppvObject = static_cast<IUnknown*>(this);
 | 
						|
  else
 | 
						|
    *ppvObject = nullptr;
 | 
						|
 | 
						|
  if (*ppvObject)
 | 
						|
    reinterpret_cast<IUnknown*>(*ppvObject)->AddRef();
 | 
						|
 | 
						|
  return (*ppvObject) ? S_OK : E_NOINTERFACE;
 | 
						|
}
 | 
						|
 | 
						|
// Increments COM objects refcount required by IUnknown for reference counting
 | 
						|
STDMETHODIMP_(ULONG) CefIAccessible::AddRef() {
 | 
						|
  return InterlockedIncrement((LONG volatile*)&ref_count_);
 | 
						|
}
 | 
						|
 | 
						|
STDMETHODIMP_(ULONG) CefIAccessible::Release() {
 | 
						|
  ULONG ulRefCnt = InterlockedDecrement((LONG volatile*)&ref_count_);
 | 
						|
  if (ulRefCnt == 0) {
 | 
						|
    // Remove reference from OsrAXNode
 | 
						|
    if (node_)
 | 
						|
      node_->Destroy();
 | 
						|
    delete this;
 | 
						|
  }
 | 
						|
 | 
						|
  return ulRefCnt;
 | 
						|
}
 | 
						|
 | 
						|
// Implement IAccessible
 | 
						|
// *********************
 | 
						|
 | 
						|
// Returns the parent IAccessible in the form of an IDispatch interface.
 | 
						|
STDMETHODIMP CefIAccessible::get_accParent(IDispatch** ppdispParent) {
 | 
						|
  HRESULT retCode = DATACHECK(node_);
 | 
						|
  if (SUCCEEDED(retCode)) {
 | 
						|
    if (ppdispParent) {
 | 
						|
      CefNativeAccessible* parent = node_->GetParentAccessibleObject();
 | 
						|
      if (!parent) {
 | 
						|
        // Find our parent window
 | 
						|
        HWND hWnd = ::GetParent(node_->GetWindowHandle());
 | 
						|
        // if we have a window attempt to get its IAccessible pointer
 | 
						|
        if (hWnd) {
 | 
						|
          AccessibleObjectFromWindow(hWnd, (DWORD)OBJID_CLIENT, IID_IAccessible,
 | 
						|
                                     (void**)(&parent));
 | 
						|
        }
 | 
						|
      }
 | 
						|
 | 
						|
      if (parent)
 | 
						|
        parent->AddRef();
 | 
						|
      *ppdispParent = parent;
 | 
						|
      retCode = (*ppdispParent) ? S_OK : S_FALSE;
 | 
						|
    }
 | 
						|
  } else {
 | 
						|
    retCode = E_INVALIDARG;
 | 
						|
  }
 | 
						|
  return retCode;
 | 
						|
}
 | 
						|
 | 
						|
// Returns the number of children we have for this element.
 | 
						|
STDMETHODIMP CefIAccessible::get_accChildCount(long* pcountChildren) {
 | 
						|
  HRESULT retCode = DATACHECK(node_);
 | 
						|
  if (SUCCEEDED(retCode) && pcountChildren) {
 | 
						|
    // Get Child node count for this from Accessibility tree
 | 
						|
    *pcountChildren = node_->GetChildCount();
 | 
						|
  } else {
 | 
						|
    retCode = E_INVALIDARG;
 | 
						|
  }
 | 
						|
  return retCode;
 | 
						|
}
 | 
						|
 | 
						|
// Returns a child IAccessible object.
 | 
						|
STDMETHODIMP CefIAccessible::get_accChild(VARIANT varChild,
 | 
						|
                                          IDispatch** ppdispChild) {
 | 
						|
  HRESULT retCode = DATACHECK(node_);
 | 
						|
  if (SUCCEEDED(retCode)) {
 | 
						|
    int numChilds = node_->GetChildCount();
 | 
						|
    // Mark Leaf node if there are no child
 | 
						|
    if (numChilds <= 0) {
 | 
						|
      *ppdispChild = nullptr;
 | 
						|
      return S_FALSE;
 | 
						|
    } else {
 | 
						|
      if (ppdispChild && VALID_CHILDID(varChild)) {
 | 
						|
        if (varChild.lVal == CHILDID_SELF) {
 | 
						|
          *ppdispChild = this;
 | 
						|
        } else {
 | 
						|
          // Convert to 0 based index and get Child Node.
 | 
						|
          OsrAXNode* child = node_->ChildAtIndex(varChild.lVal - 1);
 | 
						|
          // Fallback to focused node
 | 
						|
          if (!child)
 | 
						|
            child = node_->GetAccessibilityHelper()->GetFocusedNode();
 | 
						|
 | 
						|
          *ppdispChild = child->GetNativeAccessibleObject(node_);
 | 
						|
        }
 | 
						|
        if (*ppdispChild == nullptr)
 | 
						|
          retCode = S_FALSE;
 | 
						|
        else
 | 
						|
          (*ppdispChild)->AddRef();
 | 
						|
      }
 | 
						|
    }
 | 
						|
  }
 | 
						|
  return retCode;
 | 
						|
}
 | 
						|
 | 
						|
// Check and returns the accessible name for element from accessibility tree
 | 
						|
STDMETHODIMP CefIAccessible::get_accName(VARIANT varChild, BSTR* pszName) {
 | 
						|
  HRESULT retCode = DATACHECK(node_);
 | 
						|
  if (SUCCEEDED(retCode)) {
 | 
						|
    if (pszName && VALID_CHILDID(varChild)) {
 | 
						|
      std::wstring name = node_->AxName();
 | 
						|
      CComBSTR bstrResult(name.c_str());
 | 
						|
      *pszName = bstrResult.Detach();
 | 
						|
    }
 | 
						|
  } else {
 | 
						|
    retCode = E_INVALIDARG;
 | 
						|
  }
 | 
						|
  return retCode;
 | 
						|
}
 | 
						|
 | 
						|
// Check and returns the value for element from accessibility tree
 | 
						|
STDMETHODIMP CefIAccessible::get_accValue(VARIANT varChild, BSTR* pszValue) {
 | 
						|
  HRESULT retCode = DATACHECK(node_);
 | 
						|
  if (SUCCEEDED(retCode)) {
 | 
						|
    if (pszValue && VALID_CHILDID(varChild)) {
 | 
						|
      std::wstring name = node_->AxValue();
 | 
						|
      CComBSTR bstrResult(name.c_str());
 | 
						|
      *pszValue = bstrResult.Detach();
 | 
						|
    }
 | 
						|
  } else {
 | 
						|
    retCode = E_INVALIDARG;
 | 
						|
  }
 | 
						|
  return retCode;
 | 
						|
}
 | 
						|
 | 
						|
// Check and returns the description for element from accessibility tree
 | 
						|
STDMETHODIMP CefIAccessible::get_accDescription(VARIANT varChild,
 | 
						|
                                                BSTR* pszDescription) {
 | 
						|
  HRESULT retCode = DATACHECK(node_);
 | 
						|
  if (SUCCEEDED(retCode)) {
 | 
						|
    if (pszDescription && VALID_CHILDID(varChild)) {
 | 
						|
      std::wstring name = node_->AxDescription();
 | 
						|
      CComBSTR bstrResult(name.c_str());
 | 
						|
      *pszDescription = bstrResult.Detach();
 | 
						|
    }
 | 
						|
  } else {
 | 
						|
    retCode = E_INVALIDARG;
 | 
						|
  }
 | 
						|
  return retCode;
 | 
						|
}
 | 
						|
 | 
						|
// Check and returns the MSAA Role for element from accessibility tree
 | 
						|
STDMETHODIMP CefIAccessible::get_accRole(VARIANT varChild, VARIANT* pvarRole) {
 | 
						|
  HRESULT retCode = DATACHECK(node_);
 | 
						|
  if (SUCCEEDED(retCode)) {
 | 
						|
    // Get the accessibilty role and Map to MSAA Role
 | 
						|
    if (pvarRole) {
 | 
						|
      pvarRole->vt = VT_I4;
 | 
						|
      pvarRole->lVal = AxRoleToMSAARole(node_->AxRole());
 | 
						|
    } else {
 | 
						|
      retCode = E_INVALIDARG;
 | 
						|
    }
 | 
						|
  }
 | 
						|
  return retCode;
 | 
						|
}
 | 
						|
 | 
						|
// Check and returns Accessibility State for element from accessibility tree
 | 
						|
STDMETHODIMP CefIAccessible::get_accState(VARIANT varChild,
 | 
						|
                                          VARIANT* pvarState) {
 | 
						|
  HRESULT retCode = DATACHECK(node_);
 | 
						|
  if (SUCCEEDED(retCode)) {
 | 
						|
    if (pvarState) {
 | 
						|
      pvarState->vt = VT_I4;
 | 
						|
      pvarState->lVal =
 | 
						|
          (GetFocus() == node_->GetWindowHandle()) ? STATE_SYSTEM_FOCUSED : 0;
 | 
						|
      pvarState->lVal |= STATE_SYSTEM_PRESSED;
 | 
						|
      pvarState->lVal |= STATE_SYSTEM_FOCUSABLE;
 | 
						|
 | 
						|
      // For child
 | 
						|
      if (varChild.lVal == CHILDID_SELF) {
 | 
						|
        DWORD dwStyle = GetWindowLong(node_->GetWindowHandle(), GWL_STYLE);
 | 
						|
        pvarState->lVal |=
 | 
						|
            ((dwStyle & WS_VISIBLE) == 0) ? STATE_SYSTEM_INVISIBLE : 0;
 | 
						|
        pvarState->lVal |=
 | 
						|
            ((dwStyle & WS_DISABLED) > 0) ? STATE_SYSTEM_UNAVAILABLE : 0;
 | 
						|
      }
 | 
						|
    } else {
 | 
						|
      retCode = E_INVALIDARG;
 | 
						|
    }
 | 
						|
  }
 | 
						|
  return retCode;
 | 
						|
}
 | 
						|
 | 
						|
// Check and returns Accessibility Shortcut if any for element
 | 
						|
STDMETHODIMP CefIAccessible::get_accKeyboardShortcut(
 | 
						|
    VARIANT varChild,
 | 
						|
    BSTR* pszKeyboardShortcut) {
 | 
						|
  HRESULT retCode = DATACHECK(node_);
 | 
						|
  if (SUCCEEDED(retCode)) {
 | 
						|
    if (pszKeyboardShortcut && VALID_CHILDID(varChild))
 | 
						|
      *pszKeyboardShortcut = ::SysAllocString(L"None");
 | 
						|
    else
 | 
						|
      retCode = E_INVALIDARG;
 | 
						|
  }
 | 
						|
  return retCode;
 | 
						|
}
 | 
						|
 | 
						|
// Return focused element from the accessibility tree
 | 
						|
STDMETHODIMP CefIAccessible::get_accFocus(VARIANT* pFocusChild) {
 | 
						|
  HRESULT retCode = DATACHECK(node_);
 | 
						|
  if (SUCCEEDED(retCode)) {
 | 
						|
    OsrAXNode* focusedNode = node_->GetAccessibilityHelper()->GetFocusedNode();
 | 
						|
    CefNativeAccessible* nativeObj = nullptr;
 | 
						|
    if (focusedNode)
 | 
						|
      nativeObj = focusedNode->GetNativeAccessibleObject(nullptr);
 | 
						|
 | 
						|
    if (nativeObj) {
 | 
						|
      if (nativeObj == this) {
 | 
						|
        pFocusChild->vt = VT_I4;
 | 
						|
        pFocusChild->lVal = CHILDID_SELF;
 | 
						|
      } else {
 | 
						|
        pFocusChild->vt = VT_DISPATCH;
 | 
						|
        pFocusChild->pdispVal = nativeObj;
 | 
						|
        pFocusChild->pdispVal->AddRef();
 | 
						|
      }
 | 
						|
    } else {
 | 
						|
      pFocusChild->vt = VT_EMPTY;
 | 
						|
    }
 | 
						|
  }
 | 
						|
  return retCode;
 | 
						|
}
 | 
						|
 | 
						|
// Return a selection list for multiple selection items.
 | 
						|
STDMETHODIMP CefIAccessible::get_accSelection(VARIANT* pvarChildren) {
 | 
						|
  HRESULT retCode = DATACHECK(node_);
 | 
						|
  if (SUCCEEDED(retCode)) {
 | 
						|
    if (pvarChildren)
 | 
						|
      pvarChildren->vt = VT_EMPTY;
 | 
						|
    else
 | 
						|
      retCode = E_INVALIDARG;
 | 
						|
  }
 | 
						|
  return retCode;
 | 
						|
}
 | 
						|
 | 
						|
// Return a string description of the default action of our element, eg. push
 | 
						|
STDMETHODIMP CefIAccessible::get_accDefaultAction(VARIANT varChild,
 | 
						|
                                                  BSTR* pszDefaultAction) {
 | 
						|
  HRESULT retCode = DATACHECK(node_);
 | 
						|
  if (SUCCEEDED(retCode)) {
 | 
						|
    if (pszDefaultAction && VALID_CHILDID(varChild))
 | 
						|
      *pszDefaultAction = ::SysAllocString(L"Push");
 | 
						|
    else
 | 
						|
      retCode = E_INVALIDARG;
 | 
						|
  }
 | 
						|
  return retCode;
 | 
						|
}
 | 
						|
 | 
						|
// child item selectionor for an item to take focus.
 | 
						|
STDMETHODIMP CefIAccessible::accSelect(long flagsSelect, VARIANT varChild) {
 | 
						|
  HRESULT retCode = DATACHECK(node_);
 | 
						|
  if (SUCCEEDED(retCode)) {
 | 
						|
    if (VALID_CHILDID(varChild)) {
 | 
						|
      HWND hwnd = node_->GetWindowHandle();
 | 
						|
      // we only support SELFLAG_TAKEFOCUS.
 | 
						|
      if (((flagsSelect & SELFLAG_TAKEFOCUS) > 0) && (GetFocus() == hwnd)) {
 | 
						|
        RECT rcWnd;
 | 
						|
        GetClientRect(hwnd, &rcWnd);
 | 
						|
        InvalidateRect(hwnd, &rcWnd, FALSE);
 | 
						|
      } else {
 | 
						|
        retCode = S_FALSE;
 | 
						|
      }
 | 
						|
    } else {
 | 
						|
      retCode = E_INVALIDARG;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  return retCode;
 | 
						|
}
 | 
						|
 | 
						|
// Returns back the screen coordinates of our element or one of its childs
 | 
						|
STDMETHODIMP CefIAccessible::accLocation(long* pxLeft,
 | 
						|
                                         long* pyTop,
 | 
						|
                                         long* pcxWidth,
 | 
						|
                                         long* pcyHeight,
 | 
						|
                                         VARIANT varChild) {
 | 
						|
  HRESULT retCode = DATACHECK(node_);
 | 
						|
  if (SUCCEEDED(retCode)) {
 | 
						|
    if (pxLeft && pyTop && pcxWidth && pcyHeight && VALID_CHILDID(varChild)) {
 | 
						|
      CefRect loc = node_->AxLocation();
 | 
						|
      RECT rcItem = {loc.x, loc.y, loc.x + loc.width, loc.y + loc.height};
 | 
						|
      HWND hwnd = node_->GetWindowHandle();
 | 
						|
      ClientToScreen(hwnd, &rcItem);
 | 
						|
 | 
						|
      *pxLeft = rcItem.left;
 | 
						|
      *pyTop = rcItem.top;
 | 
						|
      *pcxWidth = rcItem.right - rcItem.left;
 | 
						|
      *pcyHeight = rcItem.bottom - rcItem.top;
 | 
						|
    } else {
 | 
						|
      retCode = E_INVALIDARG;
 | 
						|
    }
 | 
						|
  }
 | 
						|
  return retCode;
 | 
						|
}
 | 
						|
 | 
						|
// Allow clients to move the keyboard focus within the control
 | 
						|
// Deprecated
 | 
						|
STDMETHODIMP CefIAccessible::accNavigate(long navDir,
 | 
						|
                                         VARIANT varStart,
 | 
						|
                                         VARIANT* pvarEndUpAt) {
 | 
						|
  return E_NOTIMPL;
 | 
						|
}
 | 
						|
 | 
						|
// Check if the coordinates provided are within our element or child items.
 | 
						|
STDMETHODIMP CefIAccessible::accHitTest(long xLeft,
 | 
						|
                                        long yTop,
 | 
						|
                                        VARIANT* pvarChild) {
 | 
						|
  HRESULT retCode = DATACHECK(node_);
 | 
						|
  if (SUCCEEDED(retCode)) {
 | 
						|
    if (pvarChild) {
 | 
						|
      pvarChild->vt = VT_EMPTY;
 | 
						|
 | 
						|
      CefRect loc = node_->AxLocation();
 | 
						|
      RECT rcItem = {loc.x, loc.y, loc.x + loc.width, loc.y + loc.height};
 | 
						|
      POINT pt = {xLeft, yTop};
 | 
						|
 | 
						|
      ClientToScreen(node_->GetWindowHandle(), &rcItem);
 | 
						|
 | 
						|
      if (PtInRect(&rcItem, pt)) {
 | 
						|
        pvarChild->vt = VT_I4;
 | 
						|
        pvarChild->lVal = 1;
 | 
						|
      }
 | 
						|
    } else {
 | 
						|
      retCode = E_INVALIDARG;
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  return retCode;
 | 
						|
}
 | 
						|
 | 
						|
// Forces the default action of our element. In simplest cases, send a click.
 | 
						|
STDMETHODIMP CefIAccessible::accDoDefaultAction(VARIANT varChild) {
 | 
						|
  HRESULT retCode = DATACHECK(node_);
 | 
						|
  if (SUCCEEDED(retCode) && VALID_CHILDID(varChild)) {
 | 
						|
    // doing our default action for out button is to simply click the button.
 | 
						|
    CefRefPtr<CefBrowser> browser = node_->GetBrowser();
 | 
						|
    if (browser) {
 | 
						|
      CefMouseEvent mouse_event;
 | 
						|
      const CefRect& rect = node_->AxLocation();
 | 
						|
      mouse_event.x = MiddleX(rect);
 | 
						|
      mouse_event.y = MiddleY(rect);
 | 
						|
 | 
						|
      mouse_event.modifiers = 0;
 | 
						|
      browser->GetHost()->SendMouseClickEvent(mouse_event, MBT_LEFT, false, 1);
 | 
						|
      browser->GetHost()->SendMouseClickEvent(mouse_event, MBT_LEFT, true, 1);
 | 
						|
    }
 | 
						|
  } else {
 | 
						|
    retCode = E_INVALIDARG;
 | 
						|
  }
 | 
						|
 | 
						|
  return retCode;
 | 
						|
}
 | 
						|
 | 
						|
// Set the name for an element in the accessibility tree
 | 
						|
STDMETHODIMP CefIAccessible::put_accName(VARIANT varChild, BSTR szName) {
 | 
						|
  return E_NOTIMPL;
 | 
						|
}
 | 
						|
 | 
						|
// Set the value for an element in the accessibility tree
 | 
						|
STDMETHODIMP CefIAccessible::put_accValue(VARIANT varChild, BSTR szValue) {
 | 
						|
  return E_NOTIMPL;
 | 
						|
}
 | 
						|
 | 
						|
// Return E_NOTIMPL as no help file/ topic
 | 
						|
STDMETHODIMP CefIAccessible::get_accHelp(VARIANT varChild, BSTR* pszHelp) {
 | 
						|
  return E_NOTIMPL;
 | 
						|
}
 | 
						|
 | 
						|
STDMETHODIMP CefIAccessible::get_accHelpTopic(BSTR* pszHelpFile,
 | 
						|
                                              VARIANT varChild,
 | 
						|
                                              long* pidTopic) {
 | 
						|
  return E_NOTIMPL;
 | 
						|
}
 | 
						|
 | 
						|
// IDispatch - We are not going to return E_NOTIMPL from IDispatch methods and
 | 
						|
// let Active Accessibility implement the IAccessible interface for them.
 | 
						|
STDMETHODIMP CefIAccessible::GetTypeInfoCount(unsigned int FAR* pctinfo) {
 | 
						|
  return E_NOTIMPL;
 | 
						|
}
 | 
						|
 | 
						|
STDMETHODIMP CefIAccessible::GetTypeInfo(unsigned int iTInfo,
 | 
						|
                                         LCID lcid,
 | 
						|
                                         ITypeInfo FAR* FAR* ppTInfo) {
 | 
						|
  return E_NOTIMPL;
 | 
						|
}
 | 
						|
 | 
						|
STDMETHODIMP CefIAccessible::GetIDsOfNames(REFIID riid,
 | 
						|
                                           OLECHAR FAR* FAR* rgszNames,
 | 
						|
                                           unsigned int cNames,
 | 
						|
                                           LCID lcid,
 | 
						|
                                           DISPID FAR* rgDispId) {
 | 
						|
  return E_NOTIMPL;
 | 
						|
}
 | 
						|
 | 
						|
STDMETHODIMP CefIAccessible::Invoke(DISPID dispIdMember,
 | 
						|
                                    REFIID riid,
 | 
						|
                                    LCID lcid,
 | 
						|
                                    WORD wFlags,
 | 
						|
                                    DISPPARAMS FAR* pDispParams,
 | 
						|
                                    VARIANT FAR* pVarResult,
 | 
						|
                                    EXCEPINFO FAR* pExcepInfo,
 | 
						|
                                    unsigned int FAR* puArgErr) {
 | 
						|
  return E_NOTIMPL;
 | 
						|
}
 | 
						|
 | 
						|
void OsrAXNode::NotifyAccessibilityEvent(std::string event_type) const {
 | 
						|
  if (event_type == "focus") {
 | 
						|
    // Notify Screen Reader of focus change
 | 
						|
    ::NotifyWinEvent(EVENT_OBJECT_FOCUS, GetWindowHandle(), OBJID_CLIENT,
 | 
						|
                     node_id_);
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
void OsrAXNode::Destroy() {
 | 
						|
  CefIAccessible* ptr = static_cast<CefIAccessible*>(platform_accessibility_);
 | 
						|
  if (ptr)
 | 
						|
    ptr->MarkDestroyed();
 | 
						|
  platform_accessibility_ = nullptr;
 | 
						|
}
 | 
						|
 | 
						|
// Create and return NSAccessibility Implementation Object for Window
 | 
						|
CefNativeAccessible* OsrAXNode::GetNativeAccessibleObject(OsrAXNode* parent) {
 | 
						|
  if (!platform_accessibility_) {
 | 
						|
    platform_accessibility_ = new CefIAccessible(this);
 | 
						|
    platform_accessibility_->AddRef();
 | 
						|
    SetParent(parent);
 | 
						|
  }
 | 
						|
  return platform_accessibility_;
 | 
						|
}
 | 
						|
 | 
						|
}  // namespace client
 | 
						|
 | 
						|
#else  // !defined(CEF_USE_ATL)
 | 
						|
 | 
						|
namespace client {
 | 
						|
 | 
						|
void OsrAXNode::NotifyAccessibilityEvent(std::string event_type) const {}
 | 
						|
 | 
						|
void OsrAXNode::Destroy() {}
 | 
						|
 | 
						|
CefNativeAccessible* OsrAXNode::GetNativeAccessibleObject(OsrAXNode* parent) {
 | 
						|
  return nullptr;
 | 
						|
}
 | 
						|
 | 
						|
}  // namespace client
 | 
						|
 | 
						|
#endif  // !defined(CEF_USE_ATL)
 |