Improvements in scan popup functionality.

1. Add search word under cursor through IAccessibleEx interface and UI Automation technology.
2. Reorganize GoldenDict main program and scan libraries interaction to reduce influence to other programs.
3. Fix crash in scan libraries in IE9 protected mode.
This commit is contained in:
Abs62 2011-07-09 23:26:30 +04:00
parent 74e7a41548
commit a8589b39bf
24 changed files with 1259 additions and 73 deletions

View file

@ -102,6 +102,9 @@ Preferences::Preferences():
scanPopupModifiers( 0 ),
scanPopupAltMode( false ),
scanPopupAltModeSecs( 3 ),
scanPopupUseUIAutomation( false ),
scanPopupUseIAccessibleEx( false ),
scanPopupUseGDMessage( false ),
pronounceOnLoadMain( false ),
pronounceOnLoadPopup( false ),
#ifdef Q_WS_WIN
@ -597,6 +600,9 @@ Class load() throw( exError )
c.preferences.scanPopupAltMode = ( preferences.namedItem( "scanPopupAltMode" ).toElement().text() == "1" );
if ( !preferences.namedItem( "scanPopupAltModeSecs" ).isNull() )
c.preferences.scanPopupAltModeSecs = preferences.namedItem( "scanPopupAltModeSecs" ).toElement().text().toUInt();
c.preferences.scanPopupUseUIAutomation = ( preferences.namedItem( "scanPopupUseUIAutomation" ).toElement().text() == "1" );
c.preferences.scanPopupUseIAccessibleEx = ( preferences.namedItem( "scanPopupUseIAccessibleEx" ).toElement().text() == "1" );
c.preferences.scanPopupUseGDMessage = ( preferences.namedItem( "scanPopupUseGDMessage" ).toElement().text() == "1" );
c.preferences.pronounceOnLoadMain = ( preferences.namedItem( "pronounceOnLoadMain" ).toElement().text() == "1" );
c.preferences.pronounceOnLoadPopup = ( preferences.namedItem( "pronounceOnLoadPopup" ).toElement().text() == "1" );
@ -1106,6 +1112,18 @@ void save( Class const & c ) throw( exError )
opt.appendChild( dd.createTextNode( QString::number( c.preferences.scanPopupAltModeSecs ) ) );
preferences.appendChild( opt );
opt = dd.createElement( "scanPopupUseUIAutomation" );
opt.appendChild( dd.createTextNode( c.preferences.scanPopupUseUIAutomation ? "1":"0" ) );
preferences.appendChild( opt );
opt = dd.createElement( "scanPopupUseIAccessibleEx" );
opt.appendChild( dd.createTextNode( c.preferences.scanPopupUseIAccessibleEx ? "1":"0" ) );
preferences.appendChild( opt );
opt = dd.createElement( "scanPopupUseGDMessage" );
opt.appendChild( dd.createTextNode( c.preferences.scanPopupUseGDMessage ? "1":"0" ) );
preferences.appendChild( opt );
opt = dd.createElement( "pronounceOnLoadMain" );
opt.appendChild( dd.createTextNode( c.preferences.pronounceOnLoadMain ? "1" : "0" ) );
preferences.appendChild( opt );

View file

@ -159,6 +159,9 @@ struct Preferences
unsigned long scanPopupModifiers; // Combination of KeyboardState::Modifier
bool scanPopupAltMode; // When you press modifier shortly after the selection
unsigned scanPopupAltModeSecs;
bool scanPopupUseUIAutomation;
bool scanPopupUseIAccessibleEx;
bool scanPopupUseGDMessage;
// Whether the word should be pronounced on page load, in main window/popup
bool pronounceOnLoadMain, pronounceOnLoadPopup;

View file

@ -37,7 +37,10 @@ win32 {
LIBS += -liconv \
-lwsock32 \
-lwinmm \
-lpsapi
-lpsapi \
-lole32 \
-loleaut32 \
-ladvapi32
LIBS += -lvorbisfile \
-lvorbis \
-logg \
@ -255,8 +258,12 @@ SOURCES += folding.cc \
maintabwidget.cc \
mainstatusbar.cc
win32 {
SOURCES += mouseover_win32/ThTypes.c
HEADERS += mouseover_win32/ThTypes.h
SOURCES += mouseover_win32/ThTypes.c \
wordbyauto.cc \
guids.c
HEADERS += mouseover_win32/ThTypes.h \
wordbyauto.hh \
uiauto.hh
}
RESOURCES += resources.qrc \
flags.qrc

9
guids.c Normal file
View file

@ -0,0 +1,9 @@
#define INITGUID
#include <basetyps.h>
DEFINE_GUID(IID_IUIAutomation, 0x30cbe57d, 0xd9d0, 0x452a, 0xab, 0x13, 0x7a, 0xc5, 0xac, 0x48, 0x25, 0xee);
DEFINE_GUID(CLSID_CUIAutomation, 0xff48dba4, 0x60ef, 0x4201, 0xaa, 0x87, 0x54, 0x10, 0x3e, 0xef, 0x59, 0x4e);
DEFINE_GUID(IID_IUIAutomationElement, 0xd22108aa, 0x8ac5, 0x49a5, 0x83, 0x7b, 0x37, 0xbb, 0xb3, 0xd7, 0x59, 0x1e);
DEFINE_GUID(IID_IUIAutomationTextPattern, 0x32eba289, 0x3583, 0x42c9, 0x9c, 0x59, 0x3b, 0x6d, 0x9a, 0x1e, 0x9b, 0x6a);
DEFINE_GUID(IID_IUIAutomationTextRange, 0xa543cc6a, 0xf4ae, 0x494b, 0x82, 0x39, 0xc8, 0x14, 0x48, 0x11, 0x87, 0xa8);
DEFINE_GUID(IID_IUIAutomationTreeWalker, 0x4042c624, 0x389c, 0x4afc, 0xa6, 0x30, 0x9d, 0xf8, 0x54, 0xa5, 0x41, 0xfc);

View file

@ -5,7 +5,13 @@
#include <algorithm>
#ifdef Q_OS_WIN32
#undef WINVER
#define WINVER 0x0500
#include <sddl.h>
#include <accctrl.h>
#include <aclapi.h>
#include "mouseover_win32/ThTypes.h"
#include "wordbyauto.hh"
#endif
MouseOver & MouseOver::instance()
@ -18,12 +24,71 @@ MouseOver & MouseOver::instance()
#ifdef Q_OS_WIN32
const UINT WM_MY_SHOW_TRANSLATION = WM_USER + 301;
static wchar_t className[] = L"GoldenDictMouseover";
typedef BOOL WINAPI ( *ChangeWindowMessageFilterFunc )( UINT, DWORD );
#ifndef CHANGEFILTERSTRUCT
typedef struct tagCHANGEFILTERSTRUCT {
DWORD cbSize;
DWORD ExtStatus;
} CHANGEFILTERSTRUCT, *PCHANGEFILTERSTRUCT;
#endif
typedef BOOL WINAPI ( *ChangeWindowMessageFilterExFunc )( HWND, UINT, DWORD, PCHANGEFILTERSTRUCT );
#endif // Q_OS_WIN32
#ifdef Q_OS_WIN32
extern "C" BOOL WINAPI ConvertStringSecurityDescriptorToSecurityDescriptorW(
LPCWSTR StringSecurityDescriptor,
DWORD StringSDRevision,
PSECURITY_DESCRIPTOR *SecurityDescriptor,
PULONG SecurityDescriptorSize );
static void SetLowLabelToGDSynchroObjects()
{
// The LABEL_SECURITY_INFORMATION SDDL SACL to be set for low integrity
#define LOW_INTEGRITY_SDDL_SACL_W L"S:(ML;;NW;;;LW)"
DWORD dwErr = ERROR_SUCCESS;
PSECURITY_DESCRIPTOR pSD = NULL;
PACL pSacl = NULL; // not allocated
BOOL fSaclPresent = FALSE;
BOOL fSaclDefaulted = FALSE;
LPCWSTR pwszMapFileName = L"GoldenDictTextOutHookSharedMem";
LPCWSTR pwszSpyMutexName = L"GoldenDictTextOutSpyMutex";
LPCWSTR pwszHookMutexName = L"GoldenDictTextOutHookMutex";
if( ConvertStringSecurityDescriptorToSecurityDescriptorW( LOW_INTEGRITY_SDDL_SACL_W, 1 /* SDDL_REVISION_1 */, &pSD, NULL ) )
{
if( GetSecurityDescriptorSacl(pSD, &fSaclPresent, &pSacl, &fSaclDefaulted))
{
// Note that psidOwner, psidGroup, and pDacl are
// all NULL and set the new LABEL_SECURITY_INFORMATION
dwErr = SetNamedSecurityInfoW( (LPWSTR)pwszMapFileName,
SE_KERNEL_OBJECT, LABEL_SECURITY_INFORMATION, NULL, NULL, NULL, pSacl);
dwErr = SetNamedSecurityInfoW( (LPWSTR)pwszSpyMutexName,
SE_KERNEL_OBJECT, LABEL_SECURITY_INFORMATION, NULL, NULL, NULL, pSacl);
dwErr = SetNamedSecurityInfoW( (LPWSTR)pwszHookMutexName,
SE_KERNEL_OBJECT, LABEL_SECURITY_INFORMATION, NULL, NULL, NULL, pSacl);
}
LocalFree(pSD);
}
}
#endif // Q_OS_WIN32
MouseOver::MouseOver()
{
#ifdef Q_OS_WIN32
HMODULE hm;
ChangeWindowMessageFilterFunc changeWindowMessageFilterFunc = NULL;
ChangeWindowMessageFilterExFunc changeWindowMessageFilterExFunc = NULL;
mouseOverEnabled = false;
ThTypes_Init();
@ -37,17 +102,17 @@ MouseOver::MouseOver()
wcex.cbSize = sizeof( WNDCLASSEX );
wcex.style = 0;
wcex.lpfnWndProc = ( WNDPROC ) eventHandler;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = GetModuleHandle( 0 );
wcex.hIcon = NULL;
wcex.hCursor = NULL,
wcex.hbrBackground = NULL;
wcex.lpszMenuName = NULL;
wcex.lpszClassName = className;
wcex.hIconSm = NULL;
wcex.style = 0;
wcex.lpfnWndProc = ( WNDPROC ) eventHandler;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = GetModuleHandle( 0 );
wcex.hIcon = NULL;
wcex.hCursor = NULL,
wcex.hbrBackground = NULL;
wcex.lpszMenuName = NULL;
wcex.lpszClassName = className;
wcex.hIconSm = NULL;
RegisterClassEx( &wcex );
@ -58,6 +123,23 @@ MouseOver::MouseOver()
if ( spyDll )
activateSpyFn = ( ActivateSpyFn ) GetProcAddress( spyDll, "ActivateTextOutSpying" );
// Allow messages from low intehrity process - for Vista and Win7
hm = GetModuleHandle( __TEXT("user32.dll"));
if ( hm != NULL ) {
changeWindowMessageFilterExFunc = (ChangeWindowMessageFilterExFunc)GetProcAddress( hm, "ChangeWindowMessageFilterEx" );
if( changeWindowMessageFilterExFunc ) {
CHANGEFILTERSTRUCT cfs = { sizeof( CHANGEFILTERSTRUCT ), 0 };
changeWindowMessageFilterExFunc( GlobalData->ServerWND, WM_MY_SHOW_TRANSLATION, 1 /* MSGFLT_ALLOW */, &cfs );
} else {
changeWindowMessageFilterFunc = (ChangeWindowMessageFilterFunc)GetProcAddress( hm, "ChangeWindowMessageFilter" );
if( changeWindowMessageFilterFunc )
changeWindowMessageFilterFunc( WM_MY_SHOW_TRANSLATION, 1 /* MSGFLT_ADD */ );
}
}
//Allow object access from low intehrity process - for Vista and Win7
SetLowLabelToGDSynchroObjects();
#endif
}
@ -90,46 +172,72 @@ LRESULT CALLBACK MouseOver::eventHandler( HWND hwnd, UINT msg,
{
if ( msg == WM_MY_SHOW_TRANSLATION )
{
// Don't handle word without necessity
/// Don't handle word without necessity
bool bNeed = false;
emit instance().askNeedWord( &bNeed );
if( !bNeed ) return 0;
bool bNeedHandle = false;
emit instance().askNeedWord( &bNeedHandle );
if( !bNeedHandle ) return 0;
if( wparam != 0) { //Ask for methods of word retrieving
LRESULT ret = GD_FLAG_METHOD_STANDARD;
emit instance().askUseGDMessage( &bNeed );
if( bNeed )
ret |= GD_FLAG_METHOD_GD_MESSAGE;
emit instance().askUseIAccessibleEx( &bNeed );
if( bNeed )
ret |= GD_FLAG_METHOD_IACCESSIBLEEX;
emit instance().askUseUIAutomation( &bNeed );
if( bNeed )
ret |= GD_FLAG_METHOD_UI_AUTOMATION;
return ret;
}
int wordSeqPos;
int wordSeqPos = 0;
QString wordSeq;
// Is the string in utf8 or in locale encoding?
gd::wchar testBuf[ 256 ];
long result = Utf8::decode( GlobalData->CurMod.MatchedWord,
strlen( GlobalData->CurMod.MatchedWord ),
testBuf );
if ( result >= 0 )
if( GlobalData->CurMod.WordLen == 0)
{
// It seems to be
QString begin = QString::fromUtf8( GlobalData->CurMod.MatchedWord,
GlobalData->CurMod.BeginPos ).normalized( QString::NormalizationForm_C );
QString end = QString::fromUtf8( GlobalData->CurMod.MatchedWord +
GlobalData->CurMod.BeginPos ).normalized( QString::NormalizationForm_C );
wordSeq = begin + end;
wordSeqPos = begin.size();
emit instance().askUseUIAutomation( &bNeed );
if( !bNeed ) return 0;
POINT pt = GlobalData->CurMod.Pt;
WCHAR *pwstr = gdGetWordAtPointByAutomation( pt );
if( pwstr == NULL ) return 0;
wordSeq = QString::fromWCharArray( pwstr );
}
else
{
// It's not, so interpret it as in local encoding
QString begin = QString::fromLocal8Bit( GlobalData->CurMod.MatchedWord,
GlobalData->CurMod.BeginPos ).normalized( QString::NormalizationForm_C );
QString end = QString::fromLocal8Bit( GlobalData->CurMod.MatchedWord +
GlobalData->CurMod.BeginPos ).normalized( QString::NormalizationForm_C );
// Is the string in utf8 or in locale encoding?
wordSeq = begin + end;
wordSeqPos = begin.size();
gd::wchar testBuf[ 256 ];
long result = Utf8::decode( GlobalData->CurMod.MatchedWord,
strlen( GlobalData->CurMod.MatchedWord ),
testBuf );
if ( result >= 0 )
{
// It seems to be
QString begin = QString::fromUtf8( GlobalData->CurMod.MatchedWord,
GlobalData->CurMod.BeginPos ).normalized( QString::NormalizationForm_C );
QString end = QString::fromUtf8( GlobalData->CurMod.MatchedWord +
GlobalData->CurMod.BeginPos ).normalized( QString::NormalizationForm_C );
wordSeq = begin + end;
wordSeqPos = begin.size();
}
else
{
// It's not, so interpret it as in local encoding
QString begin = QString::fromLocal8Bit( GlobalData->CurMod.MatchedWord,
GlobalData->CurMod.BeginPos ).normalized( QString::NormalizationForm_C );
QString end = QString::fromLocal8Bit( GlobalData->CurMod.MatchedWord +
GlobalData->CurMod.BeginPos ).normalized( QString::NormalizationForm_C );
wordSeq = begin + end;
wordSeqPos = begin.size();
}
}
// Now locate the word inside the sequence
@ -139,7 +247,7 @@ LRESULT CALLBACK MouseOver::eventHandler( HWND hwnd, UINT msg,
if ( wordSeq[ wordSeqPos ].isSpace() )
{
// Currently we ignore such cases
return DefWindowProc( hwnd, msg, wparam, lparam );
return 0;
}
else
if ( !wordSeq[ wordSeqPos ].isLetterOrNumber() )
@ -163,7 +271,7 @@ LRESULT CALLBACK MouseOver::eventHandler( HWND hwnd, UINT msg,
if ( end - begin == 1 )
{
// Well, turns out it was just a single non-letter char, discard it
return DefWindowProc( hwnd, msg, wparam, lparam );
return 0;
}
word = wordSeq.mid( begin, end - begin );
@ -203,6 +311,7 @@ LRESULT CALLBACK MouseOver::eventHandler( HWND hwnd, UINT msg,
}
emit instance().hovered( word );
return 0;
}
return DefWindowProc( hwnd, msg, wparam, lparam );

View file

@ -33,8 +33,19 @@ signals:
/// Emitted when there was some text under cursor which was hovered over.
void hovered( QString const & );
#ifdef Q_OS_WIN32
/// Ask for need to handle word under cursor
void askNeedWord( bool * );
/// Ask for use UI Automation interfaces to get word under cursor
void askUseUIAutomation( bool * );
/// Ask for use IAccessibleEx interface to get word under cursor
void askUseIAccessibleEx( bool * );
/// Ask for use GD message to get word under cursor
void askUseGDMessage( bool * );
#endif
private:

View file

@ -0,0 +1,108 @@
#include <windows.h>
#include <wtypes.h>
#include "ThTypes.h"
#include "IAccExInt.h"
#include "GetWordByIAccEx.h"
GetPhysicalCursorPosFunc getPhysicalCursorPosFunc;
BOOL FindGetPhysicalCursorPos()
{
HMODULE hm;
getPhysicalCursorPosFunc = NULL;
hm = GetModuleHandle( "user32.dll" );
if( hm != NULL ) {
getPhysicalCursorPosFunc = (GetPhysicalCursorPosFunc)GetProcAddress( hm, "GetPhysicalCursorPos" );
}
return( getPhysicalCursorPosFunc != NULL );
}
HRESULT GetParentAccessibleObject( IAccessible* pAcc, IAccessible** ppAccParent )
{
IDispatch* pDispatch = NULL;
*ppAccParent = NULL;
if ( pAcc == NULL )
return E_INVALIDARG;
HRESULT hr = pAcc->get_accParent( &pDispatch );
if ( ( hr == S_OK ) && ( pDispatch != NULL ) ) {
hr = pDispatch->QueryInterface( IID_IAccessible, (void**)ppAccParent );
pDispatch->Release();
}
return hr;
}
BOOL getWordByAccEx( POINT pt )
{
HRESULT hr;
IAccessible *pAcc, *pAccParent;
ITextProvider *pText;
ITextRangeProvider *pTextRange;
VARIANT var;
long idChild;
BSTR bstr = NULL;
int n;
UiaPoint upt;
POINT ppt = { 0, 0 };
if( getPhysicalCursorPosFunc != NULL ) {
getPhysicalCursorPosFunc( &ppt );
} else {
ppt = pt;
}
upt.x = ppt.x;
upt.y = ppt.y;
pAcc = NULL;
hr = AccessibleObjectFromPoint( ppt, &pAcc, &var );
idChild = var.lVal;
if( hr != S_OK || pAcc == NULL) {
VariantClear( &var );
return FALSE;
}
pText = NULL;
while( pAcc != NULL) {
hr = GetPatternFromIAccessible( pAcc, 0, UIA_TextPatternId, IID_ITextProvider, (void **)&pText );
if( hr == S_OK && pText != NULL )
break;
pAccParent = NULL;
hr = GetParentAccessibleObject( pAcc, &pAccParent );
pAcc->Release();
pAcc = pAccParent;
}
if( pAcc == NULL )
return FALSE;
pAcc->Release();
pTextRange = NULL;
hr = pText->RangeFromPoint( upt, &pTextRange );
if( hr != S_OK || pTextRange == NULL ) {
pText->Release();
return FALSE;
}
hr = pTextRange->ExpandToEnclosingUnit( TextUnit_Word );
if( hr == S_OK) {
bstr = NULL;
hr = pTextRange->GetText( 255, &bstr );
if (hr == S_OK) {
n = SysStringLen( bstr );
if( n != 0 ) {
n = WideCharToMultiByte( CP_UTF8, 0, (LPCWSTR)bstr, n, GlobalData->CurMod.MatchedWord, sizeof( GlobalData->CurMod.MatchedWord ) - 1, NULL, NULL );
GlobalData->CurMod.WordLen = n;
GlobalData->CurMod.MatchedWord[n] = 0;
}
SysFreeString( bstr );
}
}
pTextRange->Release();
pText->Release();
return TRUE;
}

View file

@ -0,0 +1,19 @@
#ifndef __GetWordByIAccEx_H_DEFINED_
#define __GetWordByIAccEx_H_DEFINED_
#ifdef __cplusplus
extern "C" {
#endif
typedef BOOL (*GetPhysicalCursorPosFunc)(LPPOINT);
extern GetPhysicalCursorPosFunc getPhysicalCursorPosFunc;
BOOL FindGetPhysicalCursorPos();
BOOL getWordByAccEx( POINT pt );
#ifdef __cplusplus
}
#endif
#endif

View file

@ -87,8 +87,10 @@ static BOOL HookImportFunction(HMODULE hModule, LPCSTR szImportModule, LPCSTR sz
MEMORY_BASIC_INFORMATION mbi_thunk;
DWORD dwOldProtect;
VirtualQuery(pRealThunk, &mbi_thunk, sizeof(MEMORY_BASIC_INFORMATION));
VirtualProtect(mbi_thunk.BaseAddress, mbi_thunk.RegionSize, PAGE_READWRITE, &mbi_thunk.Protect);
if( !VirtualQuery(pRealThunk, &mbi_thunk, sizeof(MEMORY_BASIC_INFORMATION)) )
return FALSE;
if( !VirtualProtect(mbi_thunk.BaseAddress, mbi_thunk.RegionSize, PAGE_READWRITE, &mbi_thunk.Protect) )
return FALSE;
if (paOrigFuncs)
*paOrigFuncs = (PROC)pRealThunk->u1.Function;
pRealThunk->u1.Function = (DWORD)paHookFuncs;

90
mouseover_win32/IAccEx.cc Normal file
View file

@ -0,0 +1,90 @@
#include <windows.h>
#include <winable.h>
#include "IAccExInt.h"
HRESULT GetIAccessibleExFromIAccessible( IAccessible *pAcc, long idChild, IAccessibleEx **ppaex )
{
*ppaex = NULL;
IAccessibleEx *paex;
IServiceProvider *pSp = NULL;
//char s[500];
HRESULT hr = pAcc->QueryInterface( IID_IServiceProvider, (void **)&pSp );
/*
wsprintf(s,"GD:QueryInterface (IServiceProvider) return hr=%08X, ptr=%p\n", hr, pSp);
OutputDebugString(s);
*/
if( hr != S_OK ) return hr;
if( pSp == NULL ) return E_NOINTERFACE;
paex = NULL;
hr = pSp->QueryService( IID_IAccessibleEx, IID_IAccessibleEx, (void **)&paex );
pSp->Release();
/*
wsprintf(s,"GD:QueryService (IAccessibleEx) return hr=%08X, ptr=%p\n", hr, paex);
OutputDebugString(s);
*/
if( hr != S_OK ) return hr;
if( paex == NULL ) return E_NOINTERFACE;
if(idChild == CHILDID_SELF) {
*ppaex = paex;
} else {
IAccessibleEx *paexChild = NULL;
hr = paex->GetObjectForChild( idChild, &paexChild );
/*
wsprintf(s,"GD: GetObjectForChild return hr=%08X, ptr=%p (ChildID=%i)\n", hr, paexChild, idChild);
OutputDebugString(s);
*/
paex->Release();
if( hr != S_OK ) return hr;
if(paexChild == NULL) return E_NOINTERFACE;
*ppaex = paexChild;
}
return S_OK;
}
HRESULT GetIRawElementProviderFromIAccessible( IAccessible * pAcc, long idChild, IRawElementProviderSimple **ppEl )
{
*ppEl = NULL;
IAccessibleEx *paex;
//char s[500];
HRESULT hr = GetIAccessibleExFromIAccessible( pAcc, idChild, &paex );
if( hr != S_OK ) return hr;
hr = paex->QueryInterface( IID_IRawElementProviderSimple, (void **)ppEl );
/*
wsprintf(s,"GD:QueryInterface (IRawElementProviderSimple) return hr=%08X, ptr=%p\n", hr, ppEl);
OutputDebugString(s);
*/
paex->Release();
return hr;
}
HRESULT GetPatternFromIAccessible( IAccessible * pAcc, long idChild, PATTERNID patternId, REFIID iid, void **ppv )
{
IRawElementProviderSimple * pel;
//char s[500];
HRESULT hr = GetIRawElementProviderFromIAccessible( pAcc, idChild, &pel );
if( hr != S_OK ) return hr;
if( pel == NULL ) return E_NOINTERFACE;
IUnknown * pPatternObject = NULL;
hr = pel->GetPatternProvider( patternId, &pPatternObject );
/*
wsprintf(s,"GD:GetPatternProvider return hr=%08X, ptr=%p\n", hr, pPatternObject);
OutputDebugString(s);
*/
pel->Release();
if( hr != S_OK ) return hr;
if( pPatternObject == NULL ) return E_NOINTERFACE;
*ppv = NULL;
hr = pPatternObject->QueryInterface( iid, ppv );
/*
wsprintf(s,"GD:QueryInterface (TextPattern) return hr=%08X, ptr=%p\n", hr, ppv);
OutputDebugString(s);
*/
pPatternObject->Release();
if( *ppv == NULL ) return E_NOINTERFACE;
return hr;
}

157
mouseover_win32/IAccExInt.h Normal file
View file

@ -0,0 +1,157 @@
#ifndef __UIAUTO_HH_INCLUDED__
#define __UIAUTO_HH_INCLUDED__
//#include <objbase.h>
#include <unknwn.h>
#include <oaidl.h>
#include <oleacc.h>
#include <servprov.h>
#ifdef __cplusplus
extern "C" {
#endif
EXTERN_C const IID IID_IAccessibleEx;
EXTERN_C const IID IID_IRawElementProviderSimple;
EXTERN_C const IID IID_ITextProvider;
EXTERN_C const IID IID_ITextRangeProvider;
typedef interface IAccessibleEx IAccessibleEx;
typedef interface IRawElementProviderSimple IRawElementProviderSimple;
typedef interface ITextProvider ITextProvider;
typedef interface ITextRangeProvider ITextRangeProvider;
typedef int PROPERTYID;
typedef int PATTERNID;
typedef int TEXTATTRIBUTEID;
struct UiaPoint
{
double x;
double y;
};
enum ProviderOptions
{
ProviderOptions_ClientSideProvider = 0x1,
ProviderOptions_ServerSideProvider = 0x2,
ProviderOptions_NonClientAreaProvider = 0x4,
ProviderOptions_OverrideProvider = 0x8,
ProviderOptions_ProviderOwnsSetFocus = 0x10,
ProviderOptions_UseComThreading = 0x20
};
enum SupportedTextSelection
{
SupportedTextSelection_None = 0,
SupportedTextSelection_Single = 1,
SupportedTextSelection_Multiple = 2
};
enum TextUnit
{
TextUnit_Character = 0,
TextUnit_Format = 1,
TextUnit_Word = 2,
TextUnit_Line = 3,
TextUnit_Paragraph = 4,
TextUnit_Page = 5,
TextUnit_Document = 6
};
enum TextPatternRangeEndpoint
{
TextPatternRangeEndpoint_Start = 0,
TextPatternRangeEndpoint_End = 1
};
/* UIA_PatternIds */
const long UIA_InvokePatternId = 10000;
const long UIA_SelectionPatternId = 10001;
const long UIA_ValuePatternId = 10002;
const long UIA_RangeValuePatternId = 10003;
const long UIA_ScrollPatternId = 10004;
const long UIA_ExpandCollapsePatternId = 10005;
const long UIA_GridPatternId = 10006;
const long UIA_GridItemPatternId = 10007;
const long UIA_MultipleViewPatternId = 10008;
const long UIA_WindowPatternId = 10009;
const long UIA_SelectionItemPatternId = 10010;
const long UIA_DockPatternId = 10011;
const long UIA_TablePatternId = 10012;
const long UIA_TableItemPatternId = 10013;
const long UIA_TextPatternId = 10014;
const long UIA_TogglePatternId = 10015;
const long UIA_TransformPatternId = 10016;
const long UIA_ScrollItemPatternId = 10017;
const long UIA_LegacyIAccessiblePatternId = 10018;
const long UIA_ItemContainerPatternId = 10019;
const long UIA_VirtualizedItemPatternId = 10020;
const long UIA_SynchronizedInputPatternId = 10021;
#define INTERFACE ITextProvider
DECLARE_INTERFACE_(ITextProvider, IUnknown)
{
STDMETHOD(GetSelection)(THIS_ SAFEARRAY **) PURE;
STDMETHOD(GetVisibleRanges)(THIS_ SAFEARRAY **) PURE;
STDMETHOD(RangeFromChild)(THIS_ IRawElementProviderSimple *, ITextRangeProvider **) PURE;
STDMETHOD(RangeFromPoint)(THIS_ struct UiaPoint, ITextRangeProvider **pRetVal) PURE;
STDMETHOD(get_DocumentRange)(THIS_ ITextRangeProvider **) PURE;
STDMETHOD(get_SupportedTextSelection)(THIS_ enum SupportedTextSelection *) PURE;
};
#undef INTERFACE
#define INTERFACE ITextRangeProvider
DECLARE_INTERFACE_(ITextRangeProvider, IUnknown)
{
STDMETHOD(Clone)(THIS_ ITextRangeProvider **) PURE;
STDMETHOD(Compare)(THIS_ ITextRangeProvider *, BOOL *) PURE;
STDMETHOD(CompareEndpoints)(THIS_ enum TextPatternRangeEndpoint, ITextRangeProvider *, enum TextPatternRangeEndpoint, int *) PURE;
STDMETHOD(ExpandToEnclosingUnit)(THIS_ enum TextUnit) PURE;
STDMETHOD(FindAttribute)(THIS_ TEXTATTRIBUTEID, VARIANT, BOOL, ITextRangeProvider **) PURE;
STDMETHOD(FindText)(THIS_ BSTR, BOOL, BOOL, ITextRangeProvider **) PURE;
STDMETHOD(GetAttributeValue)(THIS_ TEXTATTRIBUTEID, VARIANT *) PURE;
STDMETHOD(GetBoundingRectangles)(THIS_ SAFEARRAY **) PURE;
STDMETHOD(GetEnclosingElement)(THIS_ IRawElementProviderSimple **) PURE;
STDMETHOD(GetText)(THIS_ int, BSTR *) PURE;
STDMETHOD(Move)(THIS_ enum TextUnit, int, int *) PURE;
STDMETHOD(MoveEndpointByUnit)(THIS_ enum TextPatternRangeEndpoint, enum TextUnit, int *) PURE;
STDMETHOD(MoveEndpointByRange)(THIS_ enum TextPatternRangeEndpoint, ITextRangeProvider *, enum TextPatternRangeEndpoint) PURE;
STDMETHOD(Select)(THIS) PURE;
STDMETHOD(AddToSelection)(THIS) PURE;
STDMETHOD(RemoveFromSelection)(THIS) PURE;
STDMETHOD(ScrollIntoView)(THIS_ BOOL) PURE;
STDMETHOD(GetChildren)(THIS_ SAFEARRAY **) PURE;
};
#undef INTERFACE
#define INTERFACE IRawElementProviderSimple
DECLARE_INTERFACE_(IRawElementProviderSimple, IUnknown)
{
STDMETHOD(get_ProviderOptions)(THIS_ enum ProviderOptions *) PURE;
STDMETHOD(GetPatternProvider)(THIS_ PATTERNID, IUnknown **) PURE;
STDMETHOD(GetPropertyValue)(THIS_ PROPERTYID, VARIANT *) PURE;
STDMETHOD(get_HostRawElementProvider)(THIS_ IRawElementProviderSimple **) PURE;
};
#undef INTERFACE
#define INTERFACE IAccessibleEx
DECLARE_INTERFACE_(IAccessibleEx, IUnknown)
{
STDMETHOD(GetObjectForChild)(THIS_ long, IAccessibleEx **) PURE;
STDMETHOD(GetIAccessiblePair)(THIS_ IAccessible **, long *) PURE;
STDMETHOD(GetRuntimeId)(THIS_ SAFEARRAY **) PURE;
STDMETHOD(ConvertReturnedElement)(THIS_ IRawElementProviderSimple *, IAccessibleEx **) PURE;
};
#undef INTERFACE
HRESULT GetIAccessibleExFromIAccessible( IAccessible *pAcc, long idChild, IAccessibleEx **ppaex );
HRESULT GetIRawElementProviderFromIAccessible( IAccessible * pAcc, long idChild, IRawElementProviderSimple **ppEl );
HRESULT GetPatternFromIAccessible( IAccessible * pAcc, long idChild, PATTERNID patternId, REFIID iid, void **ppv );
#ifdef __cplusplus
}
#endif
#endif // UIAUTO_HH

View file

@ -1,4 +1,5 @@
GCC:=i686-pc-mingw32-gcc.exe -W -Wall -s -O2
GCC:=gcc.exe -W -Wall -s -O2
GPP:=g++.exe -W -Wall -s -O2
.PHONY: all clean
@ -16,6 +17,15 @@ HookImportFunction.o: HookImportFunction.c
GetWord.o: GetWord.c
$(GCC) -c $<
IAccEx.o: IAccEx.cc
$(GPP) -c $<
GetWordByIAccEx.o: GetWordByIAccEx.cc
$(GPP) -c $<
guids.o: guids.c
$(GCC) -c $<
GdTextOutHook.dll libGdTextOutHook.a: TextOutHook.o HookImportFunction.o GetWord.o
$(GCC) -shared -o GdTextOutHook.dll $^ -lgdi32 -Wl,--out-implib,libGdTextOutHook.a
@ -25,5 +35,5 @@ TextOutSpy.o: TextOutSpy.c
ThTypes.o: ThTypes.c
$(GCC) -c $<
GdTextOutSpy.dll libGdTextOutSpy.a: TextOutSpy.o ThTypes.o
$(GCC) -shared -o GdTextOutSpy.dll $^ -lgdi32 -Wl,--out-implib,libGdTextOutSpy.a
GdTextOutSpy.dll libGdTextOutSpy.a: TextOutSpy.o ThTypes.o IAccEx.o guids.o GetWordByIAccEx.o
$(GPP) -shared -o GdTextOutSpy.dll $^ -lgdi32 -luuid -loleacc -loleaut32 -Wl,--out-implib,libGdTextOutSpy.a

View file

@ -525,9 +525,9 @@ DWORD wso;
case DLL_PROCESS_ATTACH:
if(hHookMutex==0) {
hHookMutex = CreateMutex(NULL, FALSE, "GoldenDictTextOutHookMutex");
if(hHookMutex==0) return(FALSE);
if(hHookMutex==0)
return(FALSE);
}
//ThTypes_Init();
InstallTextOutHooks();
break;
@ -541,7 +541,6 @@ DWORD wso;
hHookMutex=0;
}
}
//Thtypes_End();
break;
case DLL_THREAD_ATTACH:

View file

@ -1,13 +1,14 @@
#include "TextOutSpy.h"
#include "ThTypes.h"
#include "GDDataTranfer.h"
#include "GetWordByIAccEx.h"
const int MOUSEOVER_INTERVAL = 300;
const int REQUEST_MESSAGE_INTERVAL = 500;
const int WM_MY_SHOW_TRANSLATION = WM_USER + 301;
HINSTANCE g_hInstance = NULL;
HANDLE hSynhroMutex = 0;
HANDLE hSynhroMutex = 0, hHookMutex = 0;
HINSTANCE hGetWordLib = 0;
UINT_PTR TimerID = 0;
typedef void (*GetWordProc_t)(TCurrentMode *);
@ -29,9 +30,29 @@ HWND WndParent,WndChild;
static void SendWordToServer()
{
DWORD SendMsgAnswer;
if(uGdAskMessage) {
LRESULT lr;
DWORD SendMsgAnswer, flags;
LRESULT lr;
if (hGetWordLib == 0) {
hGetWordLib = LoadLibrary(GlobalData->LibName);
if (hGetWordLib) {
GetWordProc = (GetWordProc_t)GetProcAddress(hGetWordLib, "__gdGetWord");
}
else {
hGetWordLib = (HINSTANCE)-1;
}
}
// Ask for needing to retrieve word - WPARAM = 1
lr = SendMessageTimeout(GlobalData->ServerWND, WM_MY_SHOW_TRANSLATION, 1, 0, SMTO_ABORTIFHUNG, MOUSEOVER_INTERVAL, &SendMsgAnswer);
if( lr == 0 || SendMsgAnswer == 0) //No answer or no needing
return;
GlobalData->CurMod.MatchedWord[0] = 0;
GlobalData->CurMod.WordLen = 0;
GlobalData->CurMod.BeginPos = 0;
flags = SendMsgAnswer;
if( ( flags & GD_FLAG_METHOD_GD_MESSAGE ) != 0 && uGdAskMessage != 0 ) {
int n;
gds.dwSize = sizeof(gds);
gds.cwData = Buffer;
@ -51,23 +72,28 @@ DWORD SendMsgAnswer;
return;
}
}
if (hGetWordLib == 0) {
hGetWordLib = LoadLibrary(GlobalData->LibName);
if (hGetWordLib) {
GetWordProc = (GetWordProc_t)GetProcAddress(hGetWordLib, "__gdGetWord");
}
else {
hGetWordLib = (HINSTANCE)-1;
}
}
if (GetWordProc) {
if( ( flags & GD_FLAG_METHOD_STANDARD ) != 0 && GetWordProc != 0 ) {
GlobalData->CurMod.WND = GlobalData->LastWND;
GlobalData->CurMod.Pt = GlobalData->LastPt;
GetWordProc(&(GlobalData->CurMod));
if (GlobalData->CurMod.WordLen > 0) {
SendMessageTimeout(GlobalData->ServerWND, WM_MY_SHOW_TRANSLATION, 0, 0, SMTO_ABORTIFHUNG, MOUSEOVER_INTERVAL, &SendMsgAnswer);
return;
}
}
if( ( flags & GD_FLAG_METHOD_IACCESSIBLEEX ) != 0 ) {
getWordByAccEx( GlobalData->LastPt );
if (GlobalData->CurMod.WordLen > 0) {
SendMessageTimeout(GlobalData->ServerWND, WM_MY_SHOW_TRANSLATION, 0, 0, SMTO_ABORTIFHUNG, MOUSEOVER_INTERVAL, &SendMsgAnswer);
return;
}
}
if( ( flags & GD_FLAG_METHOD_UI_AUTOMATION ) != 0 ) {
PostMessage( GlobalData->ServerWND, WM_MY_SHOW_TRANSLATION, 0, 0 );
}
}
void CALLBACK TimerFunc(HWND hWnd,UINT nMsg,UINT nTimerid,DWORD dwTime)
@ -86,6 +112,7 @@ DWORD wso;
LRESULT CALLBACK MouseHookProc(int nCode, WPARAM wParam, LPARAM lParam)
{
DWORD wso;
if ((nCode == HC_ACTION) && ((wParam == WM_MOUSEMOVE) || (wParam == WM_NCMOUSEMOVE)) && (GlobalData != NULL)) {
wso = WaitForSingleObject(hSynhroMutex, 0);
if (wso == WAIT_OBJECT_0 || wso == WAIT_ABANDONED) {
@ -163,12 +190,18 @@ BOOL APIENTRY DllMain (HINSTANCE hInst /* Library instance handle. */ ,
{
case DLL_PROCESS_ATTACH:
g_hInstance = hInst;
if(hHookMutex==0) {
hHookMutex = CreateMutex(NULL, FALSE, "GoldenDictTextOutHookMutex");
}
if(hSynhroMutex==0) {
hSynhroMutex = CreateMutex(NULL, FALSE, "GoldenDictTextOutSpyMutex");
if(hSynhroMutex==0) return(FALSE);
if(hSynhroMutex==0) {
return(FALSE);
}
}
ThTypes_Init();
uGdAskMessage = RegisterWindowMessage(GD_MESSAGE_NAME);
FindGetPhysicalCursorPos();
break;
case DLL_PROCESS_DETACH:
@ -190,6 +223,14 @@ BOOL APIENTRY DllMain (HINSTANCE hInst /* Library instance handle. */ ,
if ((hGetWordLib != 0)&&(hGetWordLib != (HINSTANCE)(-1))) {
FreeLibrary(hGetWordLib);
}
if(hHookMutex) {
DWORD wso = WaitForSingleObject(hHookMutex, 5000);
if (wso == WAIT_OBJECT_0 || wso == WAIT_ABANDONED) {
ReleaseMutex(hHookMutex);
CloseHandle(hHookMutex);
hHookMutex=0;
}
}
Thtypes_End();
break;

View file

@ -5,8 +5,12 @@ TGlobalDLLData *GlobalData = NULL;
void ThTypes_Init()
{
if (!MMFHandle)
if (!MMFHandle) {
MMFHandle = CreateFileMappingA(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, sizeof(TGlobalDLLData), "GoldenDictTextOutHookSharedMem");
}
if (!MMFHandle) {
MMFHandle = OpenFileMappingA(FILE_MAP_READ | FILE_MAP_WRITE, 0, "GoldenDictTextOutHookSharedMem");
}
if (!GlobalData && MMFHandle != NULL)
GlobalData = MapViewOfFile(MMFHandle, FILE_MAP_ALL_ACCESS, 0, 0, 0);
}

View file

@ -3,6 +3,11 @@
#include <windows.h>
#define GD_FLAG_METHOD_STANDARD 0x00000001
#define GD_FLAG_METHOD_GD_MESSAGE 0x00000002
#define GD_FLAG_METHOD_IACCESSIBLEEX 0x00000004
#define GD_FLAG_METHOD_UI_AUTOMATION 0x00000008
#ifdef __cplusplus
extern "C"
{

8
mouseover_win32/guids.c Normal file
View file

@ -0,0 +1,8 @@
#define INITGUID
#include <basetyps.h>
DEFINE_GUID(IID_IAccessibleEx, 0xf8b80ada, 0x2c44, 0x48d0, 0x89, 0xbe, 0x5f, 0xf2, 0x3c, 0x9c, 0xd8, 0x75);
DEFINE_GUID(IID_IRawElementProviderSimple, 0xd6dd68d1, 0x86fd, 0x4332, 0x86, 0x66, 0x9a, 0xbe, 0xde, 0xa2, 0xd2, 0x4c);
DEFINE_GUID(IID_ITextProvider, 0x3589c92c, 0x63f3, 0x4367, 0x99, 0xbb, 0xad, 0xa6, 0x53, 0xb7, 0x7c, 0xf2);
DEFINE_GUID(IID_ITextRangeProvider, 0x5347ad7b, 0xc355, 0x46f8, 0xaf, 0xf5, 0x90, 0x90, 0x33, 0x58, 0x2f, 0x63);

View file

@ -118,6 +118,9 @@ Preferences::Preferences( QWidget * parent, Config::Preferences const & p ):
ui.scanPopupAltMode->setChecked( p.scanPopupAltMode );
ui.scanPopupAltModeSecs->setValue( p.scanPopupAltModeSecs );
ui.scanPopupUseUIAutomation->setChecked( p.scanPopupUseUIAutomation );
ui.scanPopupUseIAccessibleEx->setChecked( p.scanPopupUseIAccessibleEx );
ui.scanPopupUseGDMessage->setChecked( p.scanPopupUseGDMessage );
// Different platforms have different keys available
@ -130,6 +133,11 @@ Preferences::Preferences( QWidget * parent, Config::Preferences const & p ):
ui.rightCtrl->hide();
ui.leftShift->hide();
ui.rightShift->hide();
// This settings is Windows-specific
ui.scanPopupUseUIAutomation->hide();
ui.scanPopupUseIAccessibleEx->hide();
ui.scanPopupUseGDMessage->hide();
#endif
// Sound
@ -224,6 +232,9 @@ Config::Preferences Preferences::getPreferences()
p.scanPopupAltMode = ui.scanPopupAltMode->isChecked();
p.scanPopupAltModeSecs = ui.scanPopupAltModeSecs->value();
p.scanPopupUseUIAutomation = ui.scanPopupUseUIAutomation->isChecked();
p.scanPopupUseIAccessibleEx = ui.scanPopupUseIAccessibleEx->isChecked();
p.scanPopupUseGDMessage = ui.scanPopupUseGDMessage->isChecked();
p.pronounceOnLoadMain = ui.pronounceOnLoadMain->isChecked();
p.pronounceOnLoadPopup = ui.pronounceOnLoadPopup->isChecked();

View file

@ -7,7 +7,7 @@
<x>0</x>
<y>0</y>
<width>572</width>
<height>347</height>
<height>357</height>
</rect>
</property>
<property name="windowTitle">
@ -276,6 +276,19 @@ With this on however, it will hide the main window.</string>
<layout class="QVBoxLayout" name="verticalLayout_10">
<item>
<spacer name="verticalSpacer_7">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<spacer name="verticalSpacer_16">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
@ -545,9 +558,88 @@ seconds, which is specified here.</string>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout_4">
<item>
<widget class="QCheckBox" name="scanPopupUseIAccessibleEx">
<property name="toolTip">
<string>Try to use IAccessibleEx interface to retrieve word under cursor.
This technology works only with some programs that support it.
Don't select this option if you don't use such programs.</string>
</property>
<property name="text">
<string>Use IAccessibleE&amp;x</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_6">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QCheckBox" name="scanPopupUseGDMessage">
<property name="toolTip">
<string>Use special GoldenDict message to ask other programs about a word under cursor.
This technology works only with some programs that support it.
Don't select this option if you don't use such programs.</string>
</property>
<property name="text">
<string>Use GD message</string>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer_8">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item>
<widget class="QCheckBox" name="scanPopupUseUIAutomation">
<property name="toolTip">
<string>Try to use UI Automation technology to retrieve word under cursor.
This technology works only with some programs that support it.
Don't select this option if you don't use such programs.</string>
</property>
<property name="text">
<string>Use UI Automation</string>
</property>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<spacer name="verticalSpacer_15">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item>
<spacer name="verticalSpacer_6">
<property name="orientation">
@ -1069,7 +1161,6 @@ download page.</string>
<tabstop>proxyPort</tabstop>
<tabstop>proxyUser</tabstop>
<tabstop>proxyPassword</tabstop>
<tabstop>enableScanPopup</tabstop>
</tabstops>
<resources>
<include location="resources.qrc"/>

View file

@ -153,8 +153,18 @@ ScanPopup::ScanPopup( QWidget * parent,
connect( &mouseGrabPollTimer, SIGNAL( timeout() ),
this, SLOT(mouseGrabPoll()) );
#ifdef Q_OS_WIN32
connect( &MouseOver::instance(), SIGNAL( askNeedWord( bool * ) ),
this, SLOT( needHandleWord( bool * ) ), Qt::DirectConnection );
connect( &MouseOver::instance(), SIGNAL( askUseUIAutomation( bool * ) ),
this, SLOT( useUIAutomation( bool * ) ), Qt::DirectConnection );
connect( &MouseOver::instance(), SIGNAL( askUseIAccessibleEx( bool * ) ),
this, SLOT( useIAccessibleEx( bool * ) ), Qt::DirectConnection );
connect( &MouseOver::instance(), SIGNAL( askUseGDMessage( bool * ) ),
this, SLOT( useGDMessage( bool * ) ), Qt::DirectConnection );
#endif
}
ScanPopup::~ScanPopup()
@ -768,7 +778,26 @@ void ScanPopup::mutedDictionariesChanged()
definition->updateMutedContents();
}
#ifdef Q_OS_WIN32
void ScanPopup::needHandleWord( bool *pNeed )
{
*pNeed = !cfg.preferences.enableScanPopupModifiers || checkModifiersPressed( cfg.preferences.scanPopupModifiers );
}
void ScanPopup::useUIAutomation( bool *pUse )
{
*pUse = cfg.preferences.scanPopupUseUIAutomation != 0;
}
void ScanPopup::useIAccessibleEx( bool *pUse )
{
*pUse = cfg.preferences.scanPopupUseIAccessibleEx != 0;
}
void ScanPopup::useGDMessage( bool *pUse )
{
*pUse = cfg.preferences.scanPopupUseGDMessage != 0;
}
#endif // Q_OS_WIN32

View file

@ -134,7 +134,12 @@ private slots:
void altModeExpired();
void altModePoll();
#ifdef Q_OS_WIN32
void needHandleWord(bool *pNeed);
void useUIAutomation(bool *pUse);
void useIAccessibleEx(bool *pUse);
void useGDMessage(bool *pUse);
#endif
/// Called repeatedly once the popup is initially engaged and we monitor the
/// mouse as it may move away from the window. This simulates mouse grab, in

330
uiauto.hh Normal file
View file

@ -0,0 +1,330 @@
#ifndef __UIAUTO_HH_INCLUDED__
#define __UIAUTO_HH_INCLUDED__
#ifdef __cplusplus
extern "C" {
#endif
#include <oleacc.h>
EXTERN_C const IID IID_IUIAutomation;
EXTERN_C const IID CLSID_CUIAutomation;
EXTERN_C const IID IID_IUIAutomationElement;
EXTERN_C const IID IID_IUIAutomationTextPattern;
EXTERN_C const IID IID_IUIAutomationTextRange;
EXTERN_C const IID IID_IUIAutomationTreeWalker;
typedef interface IUIAutomationElement IUIAutomationElement;
typedef interface IUIAutomationElementArray IUIAutomationElementArray;
typedef interface IUIAutomationTextPattern IUIAutomationTextPattern;
typedef interface IUIAutomationTextRange IUIAutomationTextRange;
typedef interface IUIAutomationTextRangeArray IUIAutomationTextRangeArray;
typedef interface IUIAutomationCacheRequest IUIAutomationCacheRequest;
typedef interface IUIAutomationTreeWalker IUIAutomationTreeWalker;
typedef interface IUIAutomationCondition IUIAutomationCondition;
typedef interface IUIAutomationEventHandler IUIAutomationEventHandler;
typedef interface IUIAutomationPropertyChangedEventHandler IUIAutomationPropertyChangedEventHandler;
typedef interface IUIAutomationStructureChangedEventHandler IUIAutomationStructureChangedEventHandler;
typedef interface IUIAutomationFocusChangedEventHandler IUIAutomationFocusChangedEventHandler;
typedef interface IUIAutomationProxyFactory IUIAutomationProxyFactory;
typedef interface IUIAutomationProxyFactoryEntry IUIAutomationProxyFactoryEntry;
typedef interface IUIAutomationProxyFactoryMapping IUIAutomationProxyFactoryMapping;
typedef void *UIA_HWND;
typedef int PROPERTYID;
typedef int EVENTID;
typedef int PATTERNID;
typedef int CONTROLTYPEID;
typedef int TEXTATTRIBUTEID;
enum TreeScope
{
TreeScope_Element = 0x1,
TreeScope_Children = 0x2,
TreeScope_Descendants = 0x4,
TreeScope_Parent = 0x8,
TreeScope_Ancestors = 0x10,
TreeScope_Subtree = ( ( TreeScope_Element | TreeScope_Children ) | TreeScope_Descendants )
};
enum PropertyConditionFlags
{
PropertyConditionFlags_None = 0,
PropertyConditionFlags_IgnoreCase = 0x1
};
enum OrientationType
{
OrientationType_None = 0,
OrientationType_Horizontal = 1,
OrientationType_Vertical = 2
};
enum SupportedTextSelection
{
SupportedTextSelection_None = 0,
SupportedTextSelection_Single = 1,
SupportedTextSelection_Multiple = 2
};
enum TextPatternRangeEndpoint
{
TextPatternRangeEndpoint_Start = 0,
TextPatternRangeEndpoint_End = 1
};
enum TextUnit
{
TextUnit_Character = 0,
TextUnit_Format = 1,
TextUnit_Word = 2,
TextUnit_Line = 3,
TextUnit_Paragraph = 4,
TextUnit_Page = 5,
TextUnit_Document = 6
};
enum ProviderOptions
{
ProviderOptions_ClientSideProvider = 0x1,
ProviderOptions_ServerSideProvider = 0x2,
ProviderOptions_NonClientAreaProvider = 0x4,
ProviderOptions_OverrideProvider = 0x8,
ProviderOptions_ProviderOwnsSetFocus = 0x10,
ProviderOptions_UseComThreading = 0x20
} ;
/* UIA_PatternIds */
const long UIA_InvokePatternId = 10000;
const long UIA_SelectionPatternId = 10001;
const long UIA_ValuePatternId = 10002;
const long UIA_RangeValuePatternId = 10003;
const long UIA_ScrollPatternId = 10004;
const long UIA_ExpandCollapsePatternId = 10005;
const long UIA_GridPatternId = 10006;
const long UIA_GridItemPatternId = 10007;
const long UIA_MultipleViewPatternId = 10008;
const long UIA_WindowPatternId = 10009;
const long UIA_SelectionItemPatternId = 10010;
const long UIA_DockPatternId = 10011;
const long UIA_TablePatternId = 10012;
const long UIA_TableItemPatternId = 10013;
const long UIA_TextPatternId = 10014;
const long UIA_TogglePatternId = 10015;
const long UIA_TransformPatternId = 10016;
const long UIA_ScrollItemPatternId = 10017;
const long UIA_LegacyIAccessiblePatternId = 10018;
const long UIA_ItemContainerPatternId = 10019;
const long UIA_VirtualizedItemPatternId = 10020;
const long UIA_SynchronizedInputPatternId = 10021;
#define INTERFACE IUIAutomation
DECLARE_INTERFACE_(IUIAutomation, IUnknown)
{
STDMETHOD(CompareElements)(THIS_ IUIAutomationElement *, IUIAutomationElement *, BOOL *) PURE;
STDMETHOD(CompareRuntimeIds)(THIS_ SAFEARRAY *, SAFEARRAY *, BOOL *) PURE;
STDMETHOD(GetRootElement)(THIS_ IUIAutomationElement **) PURE;
STDMETHOD(ElementFromHandle)(THIS_ UIA_HWND, IUIAutomationElement **) PURE;
STDMETHOD(ElementFromPoint)(THIS_ POINT, IUIAutomationElement **) PURE;
STDMETHOD(GetFocusedElement)(THIS_ IUIAutomationElement **) PURE;
STDMETHOD(GetRootElementBuildCache)(THIS_ IUIAutomationCacheRequest *, IUIAutomationElement **) PURE;
STDMETHOD(ElementFromHandleBuildCache)(THIS_ UIA_HWND, IUIAutomationCacheRequest *, IUIAutomationElement **) PURE;
STDMETHOD(ElementFromPointBuildCache)(THIS_ POINT, IUIAutomationCacheRequest *, IUIAutomationElement **) PURE;
STDMETHOD(GetFocusedElementBuildCache)(THIS_ IUIAutomationCacheRequest *, IUIAutomationElement **) PURE;
STDMETHOD(CreateTreeWalker)(THIS_ IUIAutomationCondition *, IUIAutomationTreeWalker **) PURE;
STDMETHOD(get_ControlViewWalker)(THIS_ IUIAutomationTreeWalker **) PURE;
STDMETHOD(get_ContentViewWalker)(THIS_ IUIAutomationTreeWalker **) PURE;
STDMETHOD(get_RawViewWalker)(THIS_ IUIAutomationTreeWalker **) PURE;
STDMETHOD(get_RawViewCondition)(THIS_ IUIAutomationCondition **) PURE;
STDMETHOD(get_ControlViewCondition)(THIS_ IUIAutomationCondition **) PURE;
STDMETHOD(get_ContentViewCondition)(THIS_ IUIAutomationCondition **) PURE;
STDMETHOD(CreateCacheRequest)(THIS_ IUIAutomationCacheRequest **) PURE;
STDMETHOD(CreateTrueCondition)(THIS_ IUIAutomationCondition **) PURE;
STDMETHOD(CreateFalseCondition)(THIS_ IUIAutomationCondition **) PURE;
STDMETHOD(CreatePropertyCondition)(THIS_ PROPERTYID, VARIANT, IUIAutomationCondition **) PURE;
STDMETHOD(CreatePropertyConditionEx)(THIS_ PROPERTYID, VARIANT, enum PropertyConditionFlags, IUIAutomationCondition **) PURE;
STDMETHOD(CreateAndCondition)(THIS_ IUIAutomationCondition *, IUIAutomationCondition *, IUIAutomationCondition **) PURE;
STDMETHOD(CreateAndConditionFromArray)(THIS_ SAFEARRAY *, IUIAutomationCondition **) PURE;
STDMETHOD(CreateAndConditionFromNativeArray)(THIS_ IUIAutomationCondition **, int , IUIAutomationCondition **) PURE;
STDMETHOD(CreateOrCondition)(THIS_ IUIAutomationCondition *, IUIAutomationCondition *, IUIAutomationCondition **) PURE;
STDMETHOD(CreateOrConditionFromArray)(THIS_ SAFEARRAY *, IUIAutomationCondition **) PURE;
STDMETHOD(CreateOrConditionFromNativeArray)(THIS_ IUIAutomationCondition **, int , IUIAutomationCondition **) PURE;
STDMETHOD(CreateNotCondition)(THIS_ IUIAutomationCondition *, IUIAutomationCondition **) PURE;
STDMETHOD(AddAutomationEventHandler)(THIS_ EVENTID, IUIAutomationElement *, enum TreeScope, IUIAutomationCacheRequest *, IUIAutomationEventHandler *) PURE;
STDMETHOD(RemoveAutomationEventHandler)(THIS_ EVENTID, IUIAutomationElement *, IUIAutomationEventHandler *) PURE;
STDMETHOD(AddPropertyChangedEventHandlerNativeArray)(THIS_ IUIAutomationElement *, enum TreeScope, IUIAutomationCacheRequest *,
IUIAutomationPropertyChangedEventHandler *, PROPERTYID *, int) PURE;
STDMETHOD(AddPropertyChangedEventHandler)(THIS_ IUIAutomationElement *, enum TreeScope, EVENTID, IUIAutomationCacheRequest *,
IUIAutomationPropertyChangedEventHandler *, SAFEARRAY *) PURE;
STDMETHOD(RemovePropertyChangedEventHandler)(THIS_ IUIAutomationElement *, IUIAutomationPropertyChangedEventHandler *) PURE;
STDMETHOD(AddStructureChangedEventHandler)(THIS_ IUIAutomationElement *, enum TreeScope, IUIAutomationCacheRequest *, IUIAutomationStructureChangedEventHandler *) PURE;
STDMETHOD(RemoveStructureChangedEventHandler)(THIS_ IUIAutomationElement *, IUIAutomationStructureChangedEventHandler *) PURE;
STDMETHOD(AddFocusChangedEventHandler)(THIS_ IUIAutomationCacheRequest *, IUIAutomationFocusChangedEventHandler *) PURE;
STDMETHOD(RemoveFocusChangedEventHandler)(THIS_ IUIAutomationFocusChangedEventHandler *) PURE;
STDMETHOD(RemoveAllEventHandlers)(THIS) PURE;
STDMETHOD(IntNativeArrayToSafeArray)(THIS_ int *, int, SAFEARRAY **) PURE;
STDMETHOD(IntSafeArrayToNativeArray)(THIS_ SAFEARRAY *, int **, int *) PURE;
STDMETHOD(RectToVariant)(THIS_ RECT, VARIANT *) PURE;
STDMETHOD(VariantToRect)(THIS_ VARIANT, RECT *) PURE;
STDMETHOD(SafeArrayToRectNativeArray)(THIS_ SAFEARRAY *, RECT **, int *) PURE;
STDMETHOD(CreateProxyFactoryEntry)(THIS_ IUIAutomationProxyFactory *, IUIAutomationProxyFactoryEntry **) PURE;
STDMETHOD(get_ProxyFactoryMapping)(THIS_ IUIAutomationProxyFactoryMapping **) PURE;
STDMETHOD(GetPropertyProgrammaticName)(THIS_ PROPERTYID, BSTR *) PURE;
STDMETHOD(GetPatternProgrammaticName)(THIS_ PATTERNID, BSTR *) PURE;
STDMETHOD(PollForPotentialSupportedPatterns)(THIS_ IUIAutomationElement *, SAFEARRAY **, SAFEARRAY **) PURE;
STDMETHOD(PollForPotentialSupportedProperties)(THIS_ IUIAutomationElement *, SAFEARRAY **, SAFEARRAY **) PURE;
STDMETHOD(CheckNotSupported)(THIS_ VARIANT, BOOL *) PURE;
STDMETHOD(get_ReservedNotSupportedValue)(THIS_ IUnknown **) PURE;
STDMETHOD(get_ReservedMixedAttributeValue)(THIS_ IUnknown **) PURE;
STDMETHOD(ElementFromIAccessible)(THIS_ IAccessible *, int, IUIAutomationElement **) PURE;
STDMETHOD(ElementFromIAccessibleBuildCache)(THIS_ IAccessible *, int, IUIAutomationCacheRequest *, IUIAutomationElement **) PURE;
};
#undef INTERFACE
#define INTERFACE IUIAutomationElement
DECLARE_INTERFACE_(IUIAutomationElement, IUnknown)
{
STDMETHOD(SetFocus)(THIS) PURE;
STDMETHOD(GetRuntimeId)(THIS_ SAFEARRAY **) PURE;
STDMETHOD(FindFirst)(THIS_ enum TreeScope, IUIAutomationCondition *, IUIAutomationElement **) PURE;
STDMETHOD(FindAll)(THIS_ enum TreeScope, IUIAutomationCondition *, IUIAutomationElementArray **) PURE;
STDMETHOD(FindFirstBuildCache)(THIS_ enum TreeScope, IUIAutomationCondition *, IUIAutomationCacheRequest *, IUIAutomationElement **) PURE;
STDMETHOD(FindAllBuildCache)(THIS_ enum TreeScope, IUIAutomationCondition *, IUIAutomationCacheRequest *, IUIAutomationElementArray **) PURE;
STDMETHOD(BuildUpdatedCache)(THIS_ IUIAutomationCacheRequest *, IUIAutomationElement **) PURE;
STDMETHOD(GetCurrentPropertyValue)(THIS_ PROPERTYID, VARIANT *) PURE;
STDMETHOD(GetCurrentPropertyValueEx)(THIS_ PROPERTYID, BOOL, VARIANT *) PURE;
STDMETHOD(GetCachedPropertyValue)(THIS_ PROPERTYID, VARIANT *) PURE;
STDMETHOD(GetCachedPropertyValueEx)(THIS_ PROPERTYID, BOOL, VARIANT *) PURE;
STDMETHOD(GetCurrentPatternAs)(THIS_ PATTERNID, REFIID, void **) PURE;
STDMETHOD(GetCachedPatternAs)(THIS_ PATTERNID, REFIID, void **) PURE;
STDMETHOD(GetCurrentPattern)(THIS_ PATTERNID, IUnknown **) PURE;
STDMETHOD(GetCachedPattern)(THIS_ PATTERNID, IUnknown **) PURE;
STDMETHOD(GetCachedParent)(THIS_ IUIAutomationElement **) PURE;
STDMETHOD(GetCachedChildren)(THIS_ IUIAutomationElement **) PURE;
STDMETHOD(get_CurrentProcessId)(THIS_ int *) PURE;
STDMETHOD(get_CurrentControlType)(THIS_ CONTROLTYPEID *) PURE;
STDMETHOD(get_CurrentLocalizedControlType)(THIS_ BSTR *) PURE;
STDMETHOD(get_CurrentName)(THIS_ BSTR *) PURE;
STDMETHOD(get_CurrentAcceleratorKey)(THIS_ BSTR *) PURE;
STDMETHOD(get_CurrentAccessKey)(THIS_ BSTR *) PURE;
STDMETHOD(get_CurrentHasKeyboardFocus)(THIS_ BOOL *) PURE;
STDMETHOD(get_CurrentIsKeyboardFocusable)(THIS_ BOOL *) PURE;
STDMETHOD(get_CurrentIsEnabled)(THIS_ BOOL *) PURE;
STDMETHOD(get_CurrentAutomationId)(THIS_ BSTR *) PURE;
STDMETHOD(get_CurrentClassName)(THIS_ BSTR *) PURE;
STDMETHOD(get_CurrentHelpText)(THIS_ BSTR *) PURE;
STDMETHOD(get_CurrentCulture)(THIS_ int *) PURE;
STDMETHOD(get_CurrentIsControlElement)(THIS_ BOOL *) PURE;
STDMETHOD(get_CurrentIsContentElement)(THIS_ BOOL *) PURE;
STDMETHOD(get_CurrentIsPassword)(THIS_ BOOL *) PURE;
STDMETHOD(get_CurrentNativeWindowHandle)(THIS_ UIA_HWND *) PURE;
STDMETHOD(get_CurrentItemType)(THIS_ BSTR *) PURE;
STDMETHOD(get_CurrentIsOffscreen)(THIS_ BOOL *) PURE;
STDMETHOD(get_CurrentOrientation)(THIS_ enum OrientationType *) PURE;
STDMETHOD(get_CurrentFrameworkId)(THIS_ BSTR *) PURE;
STDMETHOD(get_CurrentIsRequiredForForm)(THIS_ BOOL *) PURE;
STDMETHOD(get_CurrentItemStatus)(THIS_ BSTR *) PURE;
STDMETHOD(get_CurrentBoundingRectangle)(THIS_ RECT *) PURE;
STDMETHOD(get_CurrentLabeledBy)(THIS_ IUIAutomationElement **) PURE;
STDMETHOD(get_CurrentAriaRole)(THIS_ BSTR *) PURE;
STDMETHOD(get_CurrentAriaProperties)(THIS_ BSTR *) PURE;
STDMETHOD(get_CurrentIsDataValidForForm)(THIS_ BOOL *) PURE;
STDMETHOD(get_CurrentControllerFor)(THIS_ IUIAutomationElementArray **) PURE;
STDMETHOD(get_CurrentDescribedBy)(THIS_ IUIAutomationElementArray **) PURE;
STDMETHOD(get_CurrentFlowsTo)(THIS_ IUIAutomationElementArray **) PURE;
STDMETHOD(get_CurrentProviderDescription)(THIS_ BSTR *) PURE;
STDMETHOD(get_CachedProcessId)(THIS_ int *) PURE;
STDMETHOD(get_CachedControlType)(THIS_ CONTROLTYPEID *) PURE;
STDMETHOD(get_CachedLocalizedControlType)(THIS_ BSTR *) PURE;
STDMETHOD(get_CachedName)(THIS_ BSTR *) PURE;
STDMETHOD(get_CachedAcceleratorKey)(THIS_ BSTR *) PURE;
STDMETHOD(get_CachedAccessKey)(THIS_ BSTR *) PURE;
STDMETHOD(get_CachedHasKeyboardFocus)(THIS_ BOOL *) PURE;
STDMETHOD(get_CachedIsKeyboardFocusable)(THIS_ BOOL *) PURE;
STDMETHOD(get_CachedIsEnabled)(THIS_ BOOL *) PURE;
STDMETHOD(get_CachedAutomationId)(THIS_ BSTR *) PURE;
STDMETHOD(get_CachedClassName)(THIS_ BSTR *) PURE;
STDMETHOD(get_CachedHelpText)(THIS_ BSTR *) PURE;
STDMETHOD(get_CachedCulture)(THIS_ int *) PURE;
STDMETHOD(get_CachedIsControlElement)(THIS_ BOOL *) PURE;
STDMETHOD(get_CachedIsContentElement)(THIS_ BOOL *) PURE;
STDMETHOD(get_CachedIsPassword)(THIS_ BOOL *) PURE;
STDMETHOD(get_CachedNativeWindowHandle)(THIS_ UIA_HWND *) PURE;
STDMETHOD(get_CachedItemType)(THIS_ BSTR *) PURE;
STDMETHOD(get_CachedIsOffscreen)(THIS_ BOOL *) PURE;
STDMETHOD(get_CachedOrientation)(THIS_ enum OrientationType *) PURE;
STDMETHOD(get_CachedFrameworkId)(THIS_ BSTR *) PURE;
STDMETHOD(get_CachedIsRequiredForForm)(THIS_ BOOL *) PURE;
STDMETHOD(get_CachedItemStatus)(THIS_ BSTR *) PURE;
STDMETHOD(get_CachedBoundingRectangle)(THIS_ RECT *) PURE;
STDMETHOD(get_CachedLabeledBy)(THIS_ IUIAutomationElement **) PURE;
STDMETHOD(get_CachedAriaRole)(THIS_ BSTR *) PURE;
STDMETHOD(get_CachedAriaProperties)(THIS_ BSTR *) PURE;
STDMETHOD(get_CachedIsDataValidForForm)(THIS_ BOOL *) PURE;
STDMETHOD(get_CachedControllerFor)(THIS_ IUIAutomationElementArray **) PURE;
STDMETHOD(get_CachedDescribedBy)(THIS_ IUIAutomationElementArray **) PURE;
STDMETHOD(get_CachedFlowsTo)(THIS_ IUIAutomationElementArray **) PURE;
STDMETHOD(get_CachedProviderDescription)(THIS_ BSTR *) PURE;
};
#undef INTERFACE
#define INTERFACE IUIAutomationTextPattern
DECLARE_INTERFACE_(IUIAutomationTextPattern, IUnknown)
{
STDMETHOD(RangeFromPoint)(THIS_ POINT, IUIAutomationTextRange **) PURE;
STDMETHOD(RangeFromChild)(THIS_ IUIAutomationElement *, IUIAutomationTextRange **) PURE;
STDMETHOD(GetSelection)(THIS_ IUIAutomationTextRangeArray **) PURE;
STDMETHOD(GetVisibleRanges)(THIS_ IUIAutomationTextRangeArray **) PURE;
STDMETHOD(get_DocumentRange)(THIS_ IUIAutomationTextRange **) PURE;
STDMETHOD(get_SupportedTextSelection)(THIS_ enum SupportedTextSelection *) PURE;
};
#undef INTERFACE
#define INTERFACE IUIAutomationTreeWalker
DECLARE_INTERFACE_(IUIAutomationTreeWalker, IUnknown)
{
STDMETHOD(GetParentElement)(THIS_ IUIAutomationElement *, IUIAutomationElement **) PURE;
STDMETHOD(GetFirstChildElement)(THIS_ IUIAutomationElement *, IUIAutomationElement **) PURE;
STDMETHOD(GetLastChildElement)(THIS_ IUIAutomationElement *, IUIAutomationElement **) PURE;
STDMETHOD(GetNextSiblingElement)(THIS_ IUIAutomationElement *, IUIAutomationElement **) PURE;
STDMETHOD(GetPreviousSiblingElement)(THIS_ IUIAutomationElement *, IUIAutomationElement **) PURE;
STDMETHOD(NormalizeElement)(THIS_ IUIAutomationElement *, IUIAutomationElement **) PURE;
STDMETHOD(GetParentElementBuildCache)(THIS_ IUIAutomationElement *, IUIAutomationCacheRequest *, IUIAutomationElement **) PURE;
STDMETHOD(GetFirstChildElementBuildCache)(THIS_ IUIAutomationElement *, IUIAutomationCacheRequest *, IUIAutomationElement **) PURE;
STDMETHOD(GetLastChildElementBuildCache)(THIS_ IUIAutomationElement *, IUIAutomationCacheRequest *, IUIAutomationElement **) PURE;
STDMETHOD(GetNextSiblingElementBuildCache)(THIS_ IUIAutomationElement *, IUIAutomationCacheRequest *, IUIAutomationElement **) PURE;
STDMETHOD(GetPreviousSiblingElementBuildCache)(THIS_ IUIAutomationElement *, IUIAutomationCacheRequest *, IUIAutomationElement **) PURE;
STDMETHOD(NormalizeElementBuildCache)(THIS_ IUIAutomationElement *, IUIAutomationCacheRequest *, IUIAutomationElement **) PURE;
STDMETHOD(get_Condition)(THIS_ IUIAutomationCondition **) PURE;
};
#undef INTERFACE
#define INTERFACE IUIAutomationTextRange
DECLARE_INTERFACE_(IUIAutomationTextRange, IUnknown)
{
STDMETHOD(Clone)(THIS_ IUIAutomationTextRange **) PURE;
STDMETHOD(Compare)(THIS_ IUIAutomationTextRange *, BOOL *) PURE;
STDMETHOD(CompareEndpoints)(THIS_ enum TextPatternRangeEndpoint, IUIAutomationTextRange *, enum TextPatternRangeEndpoint, int *) PURE;
STDMETHOD(ExpandToEnclosingUnit)(THIS_ enum TextUnit) PURE;
STDMETHOD(FindAttribute)(THIS_ TEXTATTRIBUTEID, VARIANT, BOOL, IUIAutomationTextRange **) PURE;
STDMETHOD(FindText)(THIS_ BSTR, BOOL, BOOL, IUIAutomationTextRange **) PURE;
STDMETHOD(GetAttributeValue)(THIS_ TEXTATTRIBUTEID, VARIANT *) PURE;
STDMETHOD(GetBoundingRectangles)(THIS_ SAFEARRAY **) PURE;
STDMETHOD(GetEnclosingElement)(THIS_ IUIAutomationElement **) PURE;
STDMETHOD(GetText)(THIS_ int, BSTR *) PURE;
STDMETHOD(Move)(THIS_ enum TextUnit, int, int *) PURE;
STDMETHOD(MoveEndpointByUnit)(THIS_ enum TextPatternRangeEndpoint, enum TextUnit, int *) PURE;
STDMETHOD(MoveEndpointByRange)(THIS_ enum TextPatternRangeEndpoint, IUIAutomationTextRange *, enum TextPatternRangeEndpoint) PURE;
STDMETHOD(Select)(THIS) PURE;
STDMETHOD(AddToSelection)(THIS) PURE;
STDMETHOD(RemoveFromSelection)(THIS) PURE;
STDMETHOD(ScrollIntoView)(THIS_ BOOL) PURE;
STDMETHOD(GetChildren)(THIS_ IUIAutomationElementArray **) PURE;
};
#undef INTERFACE
#ifdef __cplusplus
}
#endif
#endif // UIAUTO_HH

114
wordbyauto.cc Normal file
View file

@ -0,0 +1,114 @@
#include <windows.h>
#include <servprov.h>
#include <winable.h>
#include "wordbyauto.hh"
#include "uiauto.hh"
#include <cstdio>
#include "dprintf.hh"
class GDAutomationClient {
public:
GDAutomationClient();
~GDAutomationClient();
bool getWordAtPoint( POINT pt );
WCHAR *getText() { return buffer; };
private:
WCHAR buffer[256];
IUIAutomation *pGDAutomation;
IUIAutomationTreeWalker *pTree;
};
GDAutomationClient gdAuto;
GDAutomationClient::GDAutomationClient()
{
HRESULT hr;
CoInitializeEx( NULL, COINIT_APARTMENTTHREADED );
hr = CoCreateInstance( CLSID_CUIAutomation , NULL, CLSCTX_INPROC_SERVER, IID_IUIAutomation, (void**)&pGDAutomation );
if( hr != S_OK ) pGDAutomation = NULL;
pTree = NULL;
hr = pGDAutomation->get_RawViewWalker( &pTree );
memset( buffer, 0, sizeof(buffer) );
}
GDAutomationClient::~GDAutomationClient()
{
if( pTree != NULL ) pTree->Release();
if( pGDAutomation != NULL ) pGDAutomation->Release();
CoUninitialize();
}
bool GDAutomationClient::getWordAtPoint( POINT pt )
{
HRESULT hr;
IUIAutomationTextPattern *pTextPattern;
IUIAutomationTextRange *pTextRange;
IUIAutomationElement *pElement, *pParent;
BSTR bstr;
RECT r = { 0, 0, 0, 0 };
bool bGoUp;
DPRINTF("\nEntering getWordAtPoint\n");
if( pGDAutomation == NULL ) return false;
buffer[0] = 0;
pElement = NULL;
hr = pGDAutomation->ElementFromPoint( pt, &pElement );
DPRINTF("ElementFromPoint return hr=%08X, ptr=%p\n", hr, pElement);
if( hr != S_OK || pElement == NULL )
return false;
pTextPattern = NULL;
bGoUp = false;
while( pElement != NULL ) {
hr = pElement->GetCurrentPatternAs( UIA_TextPatternId, IID_IUIAutomationTextPattern, (void**)&pTextPattern );
if( hr == S_OK && pTextPattern != NULL )
break;
if( pTree == NULL ) {
pElement->Release();
return false;
}
pParent = NULL;
hr = pTree->GetParentElement( pElement, &pParent );
pElement->Release();
pElement = pParent;
bGoUp = TRUE;
}
if( pElement == NULL )
return false;
if( !bGoUp ) {
hr = pElement->get_CurrentBoundingRectangle( &r );
if( hr == S_OK) {
pt.x -= r.left;
pt.y -= r.top;
}
}
pElement->Release();
pTextRange = NULL;
hr = pTextPattern->RangeFromPoint( pt, &pTextRange );
pTextPattern->Release();
if( hr != S_OK || pTextRange == NULL )
return false;
hr = pTextRange->ExpandToEnclosingUnit( TextUnit_Word );
if( hr == S_OK) {
hr = pTextRange->GetText( 255, &bstr );
if (hr == S_OK) {
wsprintfW( buffer, L"%s", (LPCWSTR)bstr );
SysFreeString( bstr );
}
}
pTextRange->Release();
return ( buffer[0] != 0 );
}
WCHAR *gdGetWordAtPointByAutomation( POINT pt )
{
if( gdAuto.getWordAtPoint( pt ) ) return gdAuto.getText();
else return NULL;
}

6
wordbyauto.hh Normal file
View file

@ -0,0 +1,6 @@
#ifndef __WORD_BY_AUTO_HH_INCLUDED
#define __WORD_BY_AUTO_HH_INCLUDED
WCHAR *gdGetWordAtPointByAutomation( POINT pt );
#endif