https://git.reactos.org/?p=reactos.git;a=commitdiff;h=c0020b68219c438d47f80f9580d82710ab514f26
commit c0020b68219c438d47f80f9580d82710ab514f26 Author: Katayama Hirofumi MZ <katayama.hirofumi...@gmail.com> AuthorDate: Sun Jan 28 11:35:44 2024 +0900 Commit: GitHub <nore...@github.com> CommitDate: Sun Jan 28 11:35:44 2024 +0900 [MSUTB] Add CTipbarAccessible (#6417) Supporting Language Bar... JIRA issue: CORE-19363 - Implement CTipbarAccessible class. - Add delay link to oleacc.dll. --- dll/win32/msutb/CMakeLists.txt | 2 +- dll/win32/msutb/msutb.cpp | 628 ++++++++++++++++++++++++++++++++++++++++- dll/win32/msutb/precomp.h | 1 + 3 files changed, 619 insertions(+), 12 deletions(-) diff --git a/dll/win32/msutb/CMakeLists.txt b/dll/win32/msutb/CMakeLists.txt index dd79a30d8c5..978742390a4 100644 --- a/dll/win32/msutb/CMakeLists.txt +++ b/dll/win32/msutb/CMakeLists.txt @@ -15,5 +15,5 @@ set_module_type(msutb win32dll) add_dependencies(msutb msctf psdk) target_link_libraries(msutb wine uuid atl_classes) add_importlibs(msutb user32 gdi32 advapi32 msvcrt kernel32 ntdll) -add_delay_importlibs(msutb comctl32 msctf ole32 oleaut32 shell32) +add_delay_importlibs(msutb comctl32 msctf ole32 oleacc oleaut32 shell32) add_cd_file(TARGET msutb DESTINATION reactos/system32 FOR all) diff --git a/dll/win32/msutb/msutb.cpp b/dll/win32/msutb/msutb.cpp index 605fc6130d4..6ab8eb45b21 100644 --- a/dll/win32/msutb/msutb.cpp +++ b/dll/win32/msutb/msutb.cpp @@ -2,7 +2,7 @@ * PROJECT: ReactOS msutb.dll * LICENSE: LGPL-2.1-or-later (https://spdx.org/licenses/LGPL-2.1-or-later) * PURPOSE: Language Bar (Tipbar) - * COPYRIGHT: Copyright 2023 Katayama Hirofumi MZ <katayama.hirofumi...@gmail.com> + * COPYRIGHT: Copyright 2023-2024 Katayama Hirofumi MZ <katayama.hirofumi...@gmail.com> */ #include "precomp.h" @@ -14,6 +14,7 @@ UINT g_wmTaskbarCreated = 0; UINT g_uACP = CP_ACP; DWORD g_dwOSInfo = 0; CRITICAL_SECTION g_cs; +LONG g_DllRefCount = 0; EXTERN_C void __cxa_pure_virtual(void) { @@ -31,12 +32,13 @@ END_OBJECT_MAP() CMsUtbModule gModule; class CCicLibMenuItem; +class CTipbarAccItem; /***********************************************************************/ class CCicLibMenu : public ITfMenu { -public: +protected: CicArray<CCicLibMenuItem*> m_MenuItems; LONG m_cRefs; @@ -63,7 +65,7 @@ public: class CCicLibMenuItem { -public: +protected: DWORD m_uId; DWORD m_dwFlags; HBITMAP m_hbmp; @@ -88,6 +90,92 @@ public: /***********************************************************************/ +class CTipbarAccessible : public IAccessible +{ +protected: + LONG m_cRefs; + HWND m_hWnd; + IAccessible *m_pStdAccessible; + ITypeInfo *m_pTypeInfo; + BOOL m_bInitialized; + CicArray<CTipbarAccItem*> m_AccItems; + LONG m_cSelection; + +public: + CTipbarAccessible(CTipbarAccItem *pItem); + virtual ~CTipbarAccessible(); + + HRESULT Initialize(); + + BOOL AddAccItem(CTipbarAccItem *pItem); + HRESULT RemoveAccItem(CTipbarAccItem *pItem); + void ClearAccItems(); + CTipbarAccItem *AccItemFromID(INT iItem); + INT GetIDOfItem(CTipbarAccItem *pTarget); + + LONG_PTR CreateRefToAccObj(WPARAM wParam); + BOOL DoDefaultActionReal(INT nID); + void NotifyWinEvent(DWORD event, CTipbarAccItem *pItem); + void SetWindow(HWND hWnd); + + // IUnknown methods + STDMETHOD(QueryInterface)(REFIID riid, void **ppvObject); + STDMETHOD_(ULONG, AddRef)(); + STDMETHOD_(ULONG, Release)(); + + // IDispatch methods + STDMETHOD(GetTypeInfoCount)(UINT *pctinfo); + STDMETHOD(GetTypeInfo)( + UINT iTInfo, + LCID lcid, + ITypeInfo **ppTInfo); + STDMETHOD(GetIDsOfNames)( + REFIID riid, + LPOLESTR *rgszNames, + UINT cNames, + LCID lcid, + DISPID *rgDispId); + STDMETHOD(Invoke)( + DISPID dispIdMember, + REFIID riid, + LCID lcid, + WORD wFlags, + DISPPARAMS *pDispParams, + VARIANT *pVarResult, + EXCEPINFO *pExcepInfo, + UINT *puArgErr); + + // IAccessible methods + STDMETHOD(get_accParent)(IDispatch **ppdispParent); + STDMETHOD(get_accChildCount)(LONG *pcountChildren); + STDMETHOD(get_accChild)(VARIANT varChildID, IDispatch **ppdispChild); + STDMETHOD(get_accName)(VARIANT varID, BSTR *pszName); + STDMETHOD(get_accValue)(VARIANT varID, BSTR *pszValue); + STDMETHOD(get_accDescription)(VARIANT varID, BSTR *description); + STDMETHOD(get_accRole)(VARIANT varID, VARIANT *role); + STDMETHOD(get_accState)(VARIANT varID, VARIANT *state); + STDMETHOD(get_accHelp)(VARIANT varID, BSTR *help); + STDMETHOD(get_accHelpTopic)(BSTR *helpfile, VARIANT varID, LONG *pidTopic); + STDMETHOD(get_accKeyboardShortcut)(VARIANT varID, BSTR *shortcut); + STDMETHOD(get_accFocus)(VARIANT *pvarID); + STDMETHOD(get_accSelection)(VARIANT *pvarID); + STDMETHOD(get_accDefaultAction)(VARIANT varID, BSTR *action); + STDMETHOD(accSelect)(LONG flagsSelect, VARIANT varID); + STDMETHOD(accLocation)( + LONG *left, + LONG *top, + LONG *width, + LONG *height, + VARIANT varID); + STDMETHOD(accNavigate)(LONG dir, VARIANT varStart, VARIANT *pvarEnd); + STDMETHOD(accHitTest)(LONG left, LONG top, VARIANT *pvarID); + STDMETHOD(accDoDefaultAction)(VARIANT varID); + STDMETHOD(put_accName)(VARIANT varID, BSTR name); + STDMETHOD(put_accValue)(VARIANT varID, BSTR value); +}; + +/***********************************************************************/ + class CTipbarAccItem { public: @@ -98,9 +186,9 @@ public: { return SysAllocString(L""); } - STDMETHOD(UnknownMethod1)() // FIXME: Name + STDMETHOD_(BSTR, GetAccValue)() { - return S_OK; + return NULL; } STDMETHOD_(INT, GetAccRole)() { @@ -114,17 +202,17 @@ public: { *lprc = { 0, 0, 0, 0 }; } - STDMETHOD(UnknownMethod2)() // FIXME: Name + STDMETHOD_(BSTR, GetAccDefaultAction)() { - return S_OK; + return NULL; } - STDMETHOD(UnknownMethod3)() // FIXME: Name + STDMETHOD(DoAccDefaultAction)() { return S_OK; } - STDMETHOD(UnknownMethod4)() // FIXME: Name + STDMETHOD_(BOOL, DoAccDefaultActionReal)() { - return S_OK; + return FALSE; } }; @@ -361,6 +449,524 @@ HBITMAP CCicLibMenuItem::CreateBitmap(HANDLE hBitmap) return hbmMem; } +/*********************************************************************** + * CTipbarAccessible + */ + +CTipbarAccessible::CTipbarAccessible(CTipbarAccItem *pItem) +{ + m_cRefs = 1; + m_hWnd = NULL; + m_pTypeInfo = NULL; + m_pStdAccessible = NULL; + m_bInitialized = FALSE; + m_cSelection = 1; + m_AccItems.Add(pItem); + ++g_DllRefCount; +} + +CTipbarAccessible::~CTipbarAccessible() +{ + m_pTypeInfo = m_pTypeInfo; + if (m_pTypeInfo) + { + m_pTypeInfo->Release(); + m_pTypeInfo = NULL; + } + if (m_pStdAccessible) + { + m_pStdAccessible->Release(); + m_pStdAccessible = NULL; + } + --g_DllRefCount; +} + +HRESULT CTipbarAccessible::Initialize() +{ + m_bInitialized = TRUE; + + HRESULT hr = ::CreateStdAccessibleObject(m_hWnd, OBJID_CLIENT, IID_IAccessible, + (void **)&m_pStdAccessible); + if (FAILED(hr)) + return hr; + + ITypeLib *pTypeLib; + hr = ::LoadRegTypeLib(LIBID_Accessibility, 1, 0, 0, &pTypeLib); + if (FAILED(hr)) + hr = ::LoadTypeLib(L"OLEACC.DLL", &pTypeLib); + + if (SUCCEEDED(hr)) + { + hr = pTypeLib->GetTypeInfoOfGuid(IID_IAccessible, &m_pTypeInfo); + pTypeLib->Release(); + } + + return hr; +} + +BOOL CTipbarAccessible::AddAccItem(CTipbarAccItem *pItem) +{ + return m_AccItems.Add(pItem); +} + +HRESULT CTipbarAccessible::RemoveAccItem(CTipbarAccItem *pItem) +{ + for (size_t iItem = 0; iItem < m_AccItems.size(); ++iItem) + { + if (m_AccItems[iItem] == pItem) + { + m_AccItems.Remove(iItem, 1); + break; + } + } + return S_OK; +} + +void CTipbarAccessible::ClearAccItems() +{ + m_AccItems.clear(); +} + +CTipbarAccItem *CTipbarAccessible::AccItemFromID(INT iItem) +{ + if (iItem < 0 || (INT)m_AccItems.size() <= iItem) + return NULL; + return m_AccItems[iItem]; +} + +INT CTipbarAccessible::GetIDOfItem(CTipbarAccItem *pTarget) +{ + for (size_t iItem = 0; iItem < m_AccItems.size(); ++iItem) + { + if (pTarget == m_AccItems[iItem]) + return (INT)iItem; + } + return -1; +} + +LONG_PTR CTipbarAccessible::CreateRefToAccObj(WPARAM wParam) +{ + return ::LresultFromObject(IID_IAccessible, wParam, this); +} + +BOOL CTipbarAccessible::DoDefaultActionReal(INT nID) +{ + CTipbarAccItem *pItem = AccItemFromID(nID); + if (!pItem) + return FALSE; + return pItem->DoAccDefaultActionReal(); +} + +void CTipbarAccessible::NotifyWinEvent(DWORD event, CTipbarAccItem *pItem) +{ + INT nID = GetIDOfItem(pItem); + if (nID < 0) + return; + + ::NotifyWinEvent(event, m_hWnd, -4, nID); +} + +void CTipbarAccessible::SetWindow(HWND hWnd) +{ + m_hWnd = hWnd; +} + +STDMETHODIMP CTipbarAccessible::QueryInterface( + REFIID riid, + void **ppvObject) +{ + if (IsEqualIID(riid, IID_IUnknown) || + IsEqualIID(riid, IID_IDispatch) || + IsEqualIID(riid, IID_IAccessible)) + { + *ppvObject = this; + AddRef(); + return S_OK; + } + return E_NOINTERFACE; +} + +STDMETHODIMP_(ULONG) CTipbarAccessible::AddRef() +{ + return ::InterlockedIncrement(&m_cRefs); +} + +STDMETHODIMP_(ULONG) CTipbarAccessible::Release() +{ + LONG count = ::InterlockedDecrement(&m_cRefs); + if (count == 0) + { + delete this; + return 0; + } + return count; +} + +STDMETHODIMP CTipbarAccessible::GetTypeInfoCount(UINT *pctinfo) +{ + if (!pctinfo) + return E_INVALIDARG; + *pctinfo = (m_pTypeInfo == NULL); + return S_OK; +} + +STDMETHODIMP CTipbarAccessible::GetTypeInfo( + UINT iTInfo, + LCID lcid, + ITypeInfo **ppTInfo) +{ + if (!ppTInfo) + return E_INVALIDARG; + *ppTInfo = NULL; + if (iTInfo != 0) + return TYPE_E_ELEMENTNOTFOUND; + if (!m_pTypeInfo) + return E_NOTIMPL; + *ppTInfo = m_pTypeInfo; + m_pTypeInfo->AddRef(); + return S_OK; +} + +STDMETHODIMP CTipbarAccessible::GetIDsOfNames( + REFIID riid, + LPOLESTR *rgszNames, + UINT cNames, + LCID lcid, + DISPID *rgDispId) +{ + if (!m_pTypeInfo) + return E_NOTIMPL; + return m_pTypeInfo->GetIDsOfNames(rgszNames, cNames, rgDispId); +} + +STDMETHODIMP CTipbarAccessible::Invoke( + DISPID dispIdMember, + REFIID riid, + LCID lcid, + WORD wFlags, + DISPPARAMS *pDispParams, + VARIANT *pVarResult, + EXCEPINFO *pExcepInfo, + UINT *puArgErr) +{ + if (!m_pTypeInfo) + return E_NOTIMPL; + return m_pTypeInfo->Invoke(this, + dispIdMember, + wFlags, + pDispParams, + pVarResult, + pExcepInfo, + puArgErr); +} + +STDMETHODIMP CTipbarAccessible::get_accParent(IDispatch **ppdispParent) +{ + return m_pStdAccessible->get_accParent(ppdispParent); +} + +STDMETHODIMP CTipbarAccessible::get_accChildCount(LONG *pcountChildren) +{ + if (!pcountChildren) + return E_INVALIDARG; + INT cItems = (INT)m_AccItems.size(); + if (!cItems) + return E_FAIL; + *pcountChildren = cItems - 1; + return S_OK; +} + +STDMETHODIMP CTipbarAccessible::get_accChild( + VARIANT varChildID, + IDispatch **ppdispChild) +{ + if (!ppdispChild) + return E_INVALIDARG; + *ppdispChild = NULL; + return S_FALSE; +} + +STDMETHODIMP CTipbarAccessible::get_accName( + VARIANT varID, + BSTR *pszName) +{ + if (!pszName) + return E_INVALIDARG; + CTipbarAccItem *pItem = AccItemFromID(V_I4(&varID)); + if (!pItem) + return E_INVALIDARG; + *pszName = pItem->GetAccName(); + if (!*pszName) + return DISP_E_MEMBERNOTFOUND; + return S_OK; +} + +STDMETHODIMP CTipbarAccessible::get_accValue( + VARIANT varID, + BSTR *pszValue) +{ + if (!pszValue) + return E_INVALIDARG; + CTipbarAccItem *pItem = AccItemFromID(V_I4(&varID)); + if (!pItem) + return E_INVALIDARG; + *pszValue = pItem->GetAccValue(); + if (!*pszValue) + return DISP_E_MEMBERNOTFOUND; + return S_OK; +} + +STDMETHODIMP CTipbarAccessible::get_accDescription( + VARIANT varID, + BSTR *description) +{ + if (!description) + return E_INVALIDARG; + return m_pStdAccessible->get_accDescription(varID, description); +} + +STDMETHODIMP CTipbarAccessible::get_accRole( + VARIANT varID, + VARIANT *role) +{ + if (!role) + return E_INVALIDARG; + CTipbarAccItem *pItem = AccItemFromID(V_I4(&varID)); + if (!pItem) + return E_INVALIDARG; + V_VT(role) = VT_I4; + V_I4(role) = pItem->GetAccRole(); + return S_OK; +} + +STDMETHODIMP CTipbarAccessible::get_accState( + VARIANT varID, + VARIANT *state) +{ + if (!state) + return E_INVALIDARG; + CTipbarAccItem *pItem = AccItemFromID(V_I4(&varID)); + if (!pItem) + return E_INVALIDARG; + V_VT(state) = VT_I4; + V_I4(state) = pItem->GetAccState(); + return S_OK; +} + +STDMETHODIMP CTipbarAccessible::get_accHelp(VARIANT varID, BSTR *help) +{ + return DISP_E_MEMBERNOTFOUND; +} + +STDMETHODIMP CTipbarAccessible::get_accHelpTopic( + BSTR *helpfile, + VARIANT varID, + LONG *pidTopic) +{ + return DISP_E_MEMBERNOTFOUND; +} + +STDMETHODIMP CTipbarAccessible::get_accKeyboardShortcut(VARIANT varID, BSTR *shortcut) +{ + return DISP_E_MEMBERNOTFOUND; +} + +STDMETHODIMP CTipbarAccessible::get_accFocus(VARIANT *pvarID) +{ + if (!pvarID) + return E_INVALIDARG; + V_VT(pvarID) = VT_EMPTY; + return S_FALSE; +} + +STDMETHODIMP CTipbarAccessible::get_accSelection(VARIANT *pvarID) +{ + if (!pvarID) + return E_INVALIDARG; + + V_VT(pvarID) = VT_EMPTY; + + INT cItems = (INT)m_AccItems.size(); + if (cItems < m_cSelection) + return S_FALSE; + + if (cItems > m_cSelection) + { + V_VT(pvarID) = VT_I4; + V_I4(pvarID) = m_cSelection; + } + + return S_OK; +} + +STDMETHODIMP CTipbarAccessible::get_accDefaultAction( + VARIANT varID, + BSTR *action) +{ + if (!action) + return E_INVALIDARG; + *action = NULL; + + if (V_VT(&varID) != VT_I4) + return E_INVALIDARG; + + CTipbarAccItem *pItem = AccItemFromID(V_I4(&varID)); + if (!pItem) + return DISP_E_MEMBERNOTFOUND; + *action = pItem->GetAccDefaultAction(); + if (!*action) + return S_FALSE; + return S_OK; +} + +STDMETHODIMP CTipbarAccessible::accSelect( + LONG flagsSelect, + VARIANT varID) +{ + if ((flagsSelect & SELFLAG_ADDSELECTION) && (flagsSelect & SELFLAG_REMOVESELECTION)) + return E_INVALIDARG; + if (flagsSelect & (SELFLAG_TAKEFOCUS | SELFLAG_ADDSELECTION | SELFLAG_EXTENDSELECTION)) + return S_FALSE; + if (flagsSelect & SELFLAG_REMOVESELECTION) + return S_OK; + if (V_VT(&varID) != VT_I4) + return E_INVALIDARG; + if (flagsSelect & SELFLAG_TAKESELECTION) + { + m_cSelection = V_I4(&varID); + return S_OK; + } + return S_FALSE; +} + +STDMETHODIMP CTipbarAccessible::accLocation( + LONG *left, + LONG *top, + LONG *width, + LONG *height, + VARIANT varID) +{ + if (!left || !top || !width || !height) + return E_INVALIDARG; + + if (!V_I4(&varID)) + return m_pStdAccessible->accLocation(left, top, width, height, varID); + + RECT rc; + CTipbarAccItem *pItem = AccItemFromID(V_I4(&varID)); + pItem->GetAccLocation(&rc); + + *left = rc.left; + *top = rc.top; + *width = rc.right - rc.left; + *height = rc.bottom - rc.top; + return S_OK; +} + +STDMETHODIMP CTipbarAccessible::accNavigate( + LONG dir, + VARIANT varStart, + VARIANT *pvarEnd) +{ + if (m_AccItems.size() <= 1) + { + V_VT(pvarEnd) = VT_EMPTY; + return S_OK; + } + + switch (dir) + { + case NAVDIR_UP: + case NAVDIR_LEFT: + case NAVDIR_PREVIOUS: + V_VT(pvarEnd) = VT_I4; + V_I4(pvarEnd) = V_I4(&varStart) - 1; + if (V_I4(&varStart) - 1 <= 0) + V_I4(pvarEnd) = (INT)(m_AccItems.size() - 1); + return S_OK; + + case NAVDIR_DOWN: + case NAVDIR_RIGHT: + case NAVDIR_NEXT: + V_VT(pvarEnd) = VT_I4; + V_I4(pvarEnd) = V_I4(&varStart) + 1; + if ((INT)m_AccItems.size() <= V_I4(&varStart) + 1) + V_I4(pvarEnd) = 1; + return S_OK; + + case NAVDIR_FIRSTCHILD: + V_VT(pvarEnd) = VT_I4; + V_I4(pvarEnd) = 1; + return S_OK; + + case NAVDIR_LASTCHILD: + V_VT(pvarEnd) = VT_I4; + V_I4(pvarEnd) = (INT)(m_AccItems.size() - 1); + return S_OK; + + default: + break; + } + + V_VT(pvarEnd) = VT_EMPTY; + return S_OK; +} + +STDMETHODIMP CTipbarAccessible::accHitTest(LONG left, LONG top, VARIANT *pvarID) +{ + if (!pvarID) + return E_INVALIDARG; + POINT Point = { left, top }; + RECT Rect; + ::ScreenToClient(m_hWnd, &Point); + ::GetClientRect(m_hWnd, &Rect); + + if (!::PtInRect(&Rect, Point)) + { + V_VT(pvarID) = VT_EMPTY; + return S_OK; + } + + V_VT(pvarID) = VT_I4; + V_I4(pvarID) = 0; + + for (size_t iItem = 1; iItem < m_AccItems.size(); ++iItem) + { + CTipbarAccItem *pItem = m_AccItems[iItem]; + if (pItem) + { + pItem->GetAccLocation(&Rect); + if (::PtInRect(&Rect, Point)) + { + V_I4(pvarID) = iItem; + break; + } + } + } + + return S_OK; +} + +STDMETHODIMP CTipbarAccessible::accDoDefaultAction(VARIANT varID) +{ + if (V_VT(&varID) != VT_I4) + return E_INVALIDARG; + CTipbarAccItem *pItem = AccItemFromID(V_I4(&varID)); + if (!pItem) + return DISP_E_MEMBERNOTFOUND; + return pItem->DoAccDefaultAction() == 0; +} + +STDMETHODIMP CTipbarAccessible::put_accName(VARIANT varID, BSTR name) +{ + return S_FALSE; +} + +STDMETHODIMP CTipbarAccessible::put_accValue(VARIANT varID, BSTR value) +{ + return S_FALSE; +} + /*********************************************************************** * CTrayIconItem */ @@ -509,7 +1115,7 @@ STDAPI DllUnregisterServer(VOID) STDAPI DllCanUnloadNow(VOID) { TRACE("()\n"); - return gModule.DllCanUnloadNow(); + return gModule.DllCanUnloadNow() && (g_DllRefCount == 0); } /*********************************************************************** diff --git a/dll/win32/msutb/precomp.h b/dll/win32/msutb/precomp.h index d4579a7511b..7e880a30d57 100644 --- a/dll/win32/msutb/precomp.h +++ b/dll/win32/msutb/precomp.h @@ -14,6 +14,7 @@ #define INITGUID #include <windows.h> +#include <oleacc.h> #include <imm.h> #include <ddk/immdev.h> #include <cguid.h>