mirror of
https://github.com/xiaoyifang/goldendict-ng.git
synced 2024-11-30 17:24:08 +00:00
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:
parent
74e7a41548
commit
a8589b39bf
18
config.cc
18
config.cc
|
@ -102,6 +102,9 @@ Preferences::Preferences():
|
||||||
scanPopupModifiers( 0 ),
|
scanPopupModifiers( 0 ),
|
||||||
scanPopupAltMode( false ),
|
scanPopupAltMode( false ),
|
||||||
scanPopupAltModeSecs( 3 ),
|
scanPopupAltModeSecs( 3 ),
|
||||||
|
scanPopupUseUIAutomation( false ),
|
||||||
|
scanPopupUseIAccessibleEx( false ),
|
||||||
|
scanPopupUseGDMessage( false ),
|
||||||
pronounceOnLoadMain( false ),
|
pronounceOnLoadMain( false ),
|
||||||
pronounceOnLoadPopup( false ),
|
pronounceOnLoadPopup( false ),
|
||||||
#ifdef Q_WS_WIN
|
#ifdef Q_WS_WIN
|
||||||
|
@ -597,6 +600,9 @@ Class load() throw( exError )
|
||||||
c.preferences.scanPopupAltMode = ( preferences.namedItem( "scanPopupAltMode" ).toElement().text() == "1" );
|
c.preferences.scanPopupAltMode = ( preferences.namedItem( "scanPopupAltMode" ).toElement().text() == "1" );
|
||||||
if ( !preferences.namedItem( "scanPopupAltModeSecs" ).isNull() )
|
if ( !preferences.namedItem( "scanPopupAltModeSecs" ).isNull() )
|
||||||
c.preferences.scanPopupAltModeSecs = preferences.namedItem( "scanPopupAltModeSecs" ).toElement().text().toUInt();
|
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.pronounceOnLoadMain = ( preferences.namedItem( "pronounceOnLoadMain" ).toElement().text() == "1" );
|
||||||
c.preferences.pronounceOnLoadPopup = ( preferences.namedItem( "pronounceOnLoadPopup" ).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 ) ) );
|
opt.appendChild( dd.createTextNode( QString::number( c.preferences.scanPopupAltModeSecs ) ) );
|
||||||
preferences.appendChild( opt );
|
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 = dd.createElement( "pronounceOnLoadMain" );
|
||||||
opt.appendChild( dd.createTextNode( c.preferences.pronounceOnLoadMain ? "1" : "0" ) );
|
opt.appendChild( dd.createTextNode( c.preferences.pronounceOnLoadMain ? "1" : "0" ) );
|
||||||
preferences.appendChild( opt );
|
preferences.appendChild( opt );
|
||||||
|
|
|
@ -159,6 +159,9 @@ struct Preferences
|
||||||
unsigned long scanPopupModifiers; // Combination of KeyboardState::Modifier
|
unsigned long scanPopupModifiers; // Combination of KeyboardState::Modifier
|
||||||
bool scanPopupAltMode; // When you press modifier shortly after the selection
|
bool scanPopupAltMode; // When you press modifier shortly after the selection
|
||||||
unsigned scanPopupAltModeSecs;
|
unsigned scanPopupAltModeSecs;
|
||||||
|
bool scanPopupUseUIAutomation;
|
||||||
|
bool scanPopupUseIAccessibleEx;
|
||||||
|
bool scanPopupUseGDMessage;
|
||||||
|
|
||||||
// Whether the word should be pronounced on page load, in main window/popup
|
// Whether the word should be pronounced on page load, in main window/popup
|
||||||
bool pronounceOnLoadMain, pronounceOnLoadPopup;
|
bool pronounceOnLoadMain, pronounceOnLoadPopup;
|
||||||
|
|
|
@ -37,7 +37,10 @@ win32 {
|
||||||
LIBS += -liconv \
|
LIBS += -liconv \
|
||||||
-lwsock32 \
|
-lwsock32 \
|
||||||
-lwinmm \
|
-lwinmm \
|
||||||
-lpsapi
|
-lpsapi \
|
||||||
|
-lole32 \
|
||||||
|
-loleaut32 \
|
||||||
|
-ladvapi32
|
||||||
LIBS += -lvorbisfile \
|
LIBS += -lvorbisfile \
|
||||||
-lvorbis \
|
-lvorbis \
|
||||||
-logg \
|
-logg \
|
||||||
|
@ -255,8 +258,12 @@ SOURCES += folding.cc \
|
||||||
maintabwidget.cc \
|
maintabwidget.cc \
|
||||||
mainstatusbar.cc
|
mainstatusbar.cc
|
||||||
win32 {
|
win32 {
|
||||||
SOURCES += mouseover_win32/ThTypes.c
|
SOURCES += mouseover_win32/ThTypes.c \
|
||||||
HEADERS += mouseover_win32/ThTypes.h
|
wordbyauto.cc \
|
||||||
|
guids.c
|
||||||
|
HEADERS += mouseover_win32/ThTypes.h \
|
||||||
|
wordbyauto.hh \
|
||||||
|
uiauto.hh
|
||||||
}
|
}
|
||||||
RESOURCES += resources.qrc \
|
RESOURCES += resources.qrc \
|
||||||
flags.qrc
|
flags.qrc
|
||||||
|
|
9
guids.c
Normal file
9
guids.c
Normal 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);
|
197
mouseover.cc
197
mouseover.cc
|
@ -5,7 +5,13 @@
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
#ifdef Q_OS_WIN32
|
#ifdef Q_OS_WIN32
|
||||||
|
#undef WINVER
|
||||||
|
#define WINVER 0x0500
|
||||||
|
#include <sddl.h>
|
||||||
|
#include <accctrl.h>
|
||||||
|
#include <aclapi.h>
|
||||||
#include "mouseover_win32/ThTypes.h"
|
#include "mouseover_win32/ThTypes.h"
|
||||||
|
#include "wordbyauto.hh"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
MouseOver & MouseOver::instance()
|
MouseOver & MouseOver::instance()
|
||||||
|
@ -18,12 +24,71 @@ MouseOver & MouseOver::instance()
|
||||||
#ifdef Q_OS_WIN32
|
#ifdef Q_OS_WIN32
|
||||||
const UINT WM_MY_SHOW_TRANSLATION = WM_USER + 301;
|
const UINT WM_MY_SHOW_TRANSLATION = WM_USER + 301;
|
||||||
static wchar_t className[] = L"GoldenDictMouseover";
|
static wchar_t className[] = L"GoldenDictMouseover";
|
||||||
|
typedef BOOL WINAPI ( *ChangeWindowMessageFilterFunc )( UINT, DWORD );
|
||||||
|
|
||||||
|
#ifndef CHANGEFILTERSTRUCT
|
||||||
|
typedef struct tagCHANGEFILTERSTRUCT {
|
||||||
|
DWORD cbSize;
|
||||||
|
DWORD ExtStatus;
|
||||||
|
} CHANGEFILTERSTRUCT, *PCHANGEFILTERSTRUCT;
|
||||||
#endif
|
#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()
|
MouseOver::MouseOver()
|
||||||
{
|
{
|
||||||
#ifdef Q_OS_WIN32
|
#ifdef Q_OS_WIN32
|
||||||
|
HMODULE hm;
|
||||||
|
ChangeWindowMessageFilterFunc changeWindowMessageFilterFunc = NULL;
|
||||||
|
ChangeWindowMessageFilterExFunc changeWindowMessageFilterExFunc = NULL;
|
||||||
mouseOverEnabled = false;
|
mouseOverEnabled = false;
|
||||||
|
|
||||||
ThTypes_Init();
|
ThTypes_Init();
|
||||||
|
@ -37,17 +102,17 @@ MouseOver::MouseOver()
|
||||||
|
|
||||||
wcex.cbSize = sizeof( WNDCLASSEX );
|
wcex.cbSize = sizeof( WNDCLASSEX );
|
||||||
|
|
||||||
wcex.style = 0;
|
wcex.style = 0;
|
||||||
wcex.lpfnWndProc = ( WNDPROC ) eventHandler;
|
wcex.lpfnWndProc = ( WNDPROC ) eventHandler;
|
||||||
wcex.cbClsExtra = 0;
|
wcex.cbClsExtra = 0;
|
||||||
wcex.cbWndExtra = 0;
|
wcex.cbWndExtra = 0;
|
||||||
wcex.hInstance = GetModuleHandle( 0 );
|
wcex.hInstance = GetModuleHandle( 0 );
|
||||||
wcex.hIcon = NULL;
|
wcex.hIcon = NULL;
|
||||||
wcex.hCursor = NULL,
|
wcex.hCursor = NULL,
|
||||||
wcex.hbrBackground = NULL;
|
wcex.hbrBackground = NULL;
|
||||||
wcex.lpszMenuName = NULL;
|
wcex.lpszMenuName = NULL;
|
||||||
wcex.lpszClassName = className;
|
wcex.lpszClassName = className;
|
||||||
wcex.hIconSm = NULL;
|
wcex.hIconSm = NULL;
|
||||||
|
|
||||||
RegisterClassEx( &wcex );
|
RegisterClassEx( &wcex );
|
||||||
|
|
||||||
|
@ -58,6 +123,23 @@ MouseOver::MouseOver()
|
||||||
if ( spyDll )
|
if ( spyDll )
|
||||||
activateSpyFn = ( ActivateSpyFn ) GetProcAddress( spyDll, "ActivateTextOutSpying" );
|
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
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -90,46 +172,72 @@ LRESULT CALLBACK MouseOver::eventHandler( HWND hwnd, UINT msg,
|
||||||
{
|
{
|
||||||
if ( msg == WM_MY_SHOW_TRANSLATION )
|
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;
|
if( wparam != 0) { //Ask for methods of word retrieving
|
||||||
emit instance().askNeedWord( &bNeedHandle );
|
LRESULT ret = GD_FLAG_METHOD_STANDARD;
|
||||||
if( !bNeedHandle ) return 0;
|
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;
|
QString wordSeq;
|
||||||
|
|
||||||
// Is the string in utf8 or in locale encoding?
|
if( GlobalData->CurMod.WordLen == 0)
|
||||||
|
|
||||||
gd::wchar testBuf[ 256 ];
|
|
||||||
|
|
||||||
long result = Utf8::decode( GlobalData->CurMod.MatchedWord,
|
|
||||||
strlen( GlobalData->CurMod.MatchedWord ),
|
|
||||||
testBuf );
|
|
||||||
|
|
||||||
if ( result >= 0 )
|
|
||||||
{
|
{
|
||||||
// It seems to be
|
emit instance().askUseUIAutomation( &bNeed );
|
||||||
QString begin = QString::fromUtf8( GlobalData->CurMod.MatchedWord,
|
if( !bNeed ) return 0;
|
||||||
GlobalData->CurMod.BeginPos ).normalized( QString::NormalizationForm_C );
|
POINT pt = GlobalData->CurMod.Pt;
|
||||||
|
WCHAR *pwstr = gdGetWordAtPointByAutomation( pt );
|
||||||
QString end = QString::fromUtf8( GlobalData->CurMod.MatchedWord +
|
if( pwstr == NULL ) return 0;
|
||||||
GlobalData->CurMod.BeginPos ).normalized( QString::NormalizationForm_C );
|
wordSeq = QString::fromWCharArray( pwstr );
|
||||||
|
|
||||||
wordSeq = begin + end;
|
|
||||||
wordSeqPos = begin.size();
|
|
||||||
}
|
}
|
||||||
else
|
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 +
|
// Is the string in utf8 or in locale encoding?
|
||||||
GlobalData->CurMod.BeginPos ).normalized( QString::NormalizationForm_C );
|
|
||||||
|
|
||||||
wordSeq = begin + end;
|
gd::wchar testBuf[ 256 ];
|
||||||
wordSeqPos = begin.size();
|
|
||||||
|
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
|
// Now locate the word inside the sequence
|
||||||
|
@ -139,7 +247,7 @@ LRESULT CALLBACK MouseOver::eventHandler( HWND hwnd, UINT msg,
|
||||||
if ( wordSeq[ wordSeqPos ].isSpace() )
|
if ( wordSeq[ wordSeqPos ].isSpace() )
|
||||||
{
|
{
|
||||||
// Currently we ignore such cases
|
// Currently we ignore such cases
|
||||||
return DefWindowProc( hwnd, msg, wparam, lparam );
|
return 0;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
if ( !wordSeq[ wordSeqPos ].isLetterOrNumber() )
|
if ( !wordSeq[ wordSeqPos ].isLetterOrNumber() )
|
||||||
|
@ -163,7 +271,7 @@ LRESULT CALLBACK MouseOver::eventHandler( HWND hwnd, UINT msg,
|
||||||
if ( end - begin == 1 )
|
if ( end - begin == 1 )
|
||||||
{
|
{
|
||||||
// Well, turns out it was just a single non-letter char, discard it
|
// 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 );
|
word = wordSeq.mid( begin, end - begin );
|
||||||
|
@ -203,6 +311,7 @@ LRESULT CALLBACK MouseOver::eventHandler( HWND hwnd, UINT msg,
|
||||||
}
|
}
|
||||||
|
|
||||||
emit instance().hovered( word );
|
emit instance().hovered( word );
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return DefWindowProc( hwnd, msg, wparam, lparam );
|
return DefWindowProc( hwnd, msg, wparam, lparam );
|
||||||
|
|
11
mouseover.hh
11
mouseover.hh
|
@ -33,8 +33,19 @@ signals:
|
||||||
|
|
||||||
/// Emitted when there was some text under cursor which was hovered over.
|
/// Emitted when there was some text under cursor which was hovered over.
|
||||||
void hovered( QString const & );
|
void hovered( QString const & );
|
||||||
|
|
||||||
|
#ifdef Q_OS_WIN32
|
||||||
|
|
||||||
/// Ask for need to handle word under cursor
|
/// Ask for need to handle word under cursor
|
||||||
void askNeedWord( bool * );
|
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:
|
private:
|
||||||
|
|
||||||
|
|
108
mouseover_win32/GetWordByIAccEx.cc
Normal file
108
mouseover_win32/GetWordByIAccEx.cc
Normal 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;
|
||||||
|
}
|
19
mouseover_win32/GetWordByIAccEx.h
Normal file
19
mouseover_win32/GetWordByIAccEx.h
Normal 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
|
|
@ -87,8 +87,10 @@ static BOOL HookImportFunction(HMODULE hModule, LPCSTR szImportModule, LPCSTR sz
|
||||||
MEMORY_BASIC_INFORMATION mbi_thunk;
|
MEMORY_BASIC_INFORMATION mbi_thunk;
|
||||||
DWORD dwOldProtect;
|
DWORD dwOldProtect;
|
||||||
|
|
||||||
VirtualQuery(pRealThunk, &mbi_thunk, sizeof(MEMORY_BASIC_INFORMATION));
|
if( !VirtualQuery(pRealThunk, &mbi_thunk, sizeof(MEMORY_BASIC_INFORMATION)) )
|
||||||
VirtualProtect(mbi_thunk.BaseAddress, mbi_thunk.RegionSize, PAGE_READWRITE, &mbi_thunk.Protect);
|
return FALSE;
|
||||||
|
if( !VirtualProtect(mbi_thunk.BaseAddress, mbi_thunk.RegionSize, PAGE_READWRITE, &mbi_thunk.Protect) )
|
||||||
|
return FALSE;
|
||||||
if (paOrigFuncs)
|
if (paOrigFuncs)
|
||||||
*paOrigFuncs = (PROC)pRealThunk->u1.Function;
|
*paOrigFuncs = (PROC)pRealThunk->u1.Function;
|
||||||
pRealThunk->u1.Function = (DWORD)paHookFuncs;
|
pRealThunk->u1.Function = (DWORD)paHookFuncs;
|
||||||
|
|
90
mouseover_win32/IAccEx.cc
Normal file
90
mouseover_win32/IAccEx.cc
Normal 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
157
mouseover_win32/IAccExInt.h
Normal 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
|
|
@ -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
|
.PHONY: all clean
|
||||||
|
|
||||||
|
@ -16,6 +17,15 @@ HookImportFunction.o: HookImportFunction.c
|
||||||
GetWord.o: GetWord.c
|
GetWord.o: GetWord.c
|
||||||
$(GCC) -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
|
GdTextOutHook.dll libGdTextOutHook.a: TextOutHook.o HookImportFunction.o GetWord.o
|
||||||
$(GCC) -shared -o GdTextOutHook.dll $^ -lgdi32 -Wl,--out-implib,libGdTextOutHook.a
|
$(GCC) -shared -o GdTextOutHook.dll $^ -lgdi32 -Wl,--out-implib,libGdTextOutHook.a
|
||||||
|
|
||||||
|
@ -25,5 +35,5 @@ TextOutSpy.o: TextOutSpy.c
|
||||||
ThTypes.o: ThTypes.c
|
ThTypes.o: ThTypes.c
|
||||||
$(GCC) -c $<
|
$(GCC) -c $<
|
||||||
|
|
||||||
GdTextOutSpy.dll libGdTextOutSpy.a: TextOutSpy.o ThTypes.o
|
GdTextOutSpy.dll libGdTextOutSpy.a: TextOutSpy.o ThTypes.o IAccEx.o guids.o GetWordByIAccEx.o
|
||||||
$(GCC) -shared -o GdTextOutSpy.dll $^ -lgdi32 -Wl,--out-implib,libGdTextOutSpy.a
|
$(GPP) -shared -o GdTextOutSpy.dll $^ -lgdi32 -luuid -loleacc -loleaut32 -Wl,--out-implib,libGdTextOutSpy.a
|
||||||
|
|
|
@ -525,9 +525,9 @@ DWORD wso;
|
||||||
case DLL_PROCESS_ATTACH:
|
case DLL_PROCESS_ATTACH:
|
||||||
if(hHookMutex==0) {
|
if(hHookMutex==0) {
|
||||||
hHookMutex = CreateMutex(NULL, FALSE, "GoldenDictTextOutHookMutex");
|
hHookMutex = CreateMutex(NULL, FALSE, "GoldenDictTextOutHookMutex");
|
||||||
if(hHookMutex==0) return(FALSE);
|
if(hHookMutex==0)
|
||||||
|
return(FALSE);
|
||||||
}
|
}
|
||||||
//ThTypes_Init();
|
|
||||||
InstallTextOutHooks();
|
InstallTextOutHooks();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -541,7 +541,6 @@ DWORD wso;
|
||||||
hHookMutex=0;
|
hHookMutex=0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//Thtypes_End();
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case DLL_THREAD_ATTACH:
|
case DLL_THREAD_ATTACH:
|
||||||
|
|
|
@ -1,13 +1,14 @@
|
||||||
#include "TextOutSpy.h"
|
#include "TextOutSpy.h"
|
||||||
#include "ThTypes.h"
|
#include "ThTypes.h"
|
||||||
#include "GDDataTranfer.h"
|
#include "GDDataTranfer.h"
|
||||||
|
#include "GetWordByIAccEx.h"
|
||||||
|
|
||||||
const int MOUSEOVER_INTERVAL = 300;
|
const int MOUSEOVER_INTERVAL = 300;
|
||||||
const int REQUEST_MESSAGE_INTERVAL = 500;
|
const int REQUEST_MESSAGE_INTERVAL = 500;
|
||||||
const int WM_MY_SHOW_TRANSLATION = WM_USER + 301;
|
const int WM_MY_SHOW_TRANSLATION = WM_USER + 301;
|
||||||
|
|
||||||
HINSTANCE g_hInstance = NULL;
|
HINSTANCE g_hInstance = NULL;
|
||||||
HANDLE hSynhroMutex = 0;
|
HANDLE hSynhroMutex = 0, hHookMutex = 0;
|
||||||
HINSTANCE hGetWordLib = 0;
|
HINSTANCE hGetWordLib = 0;
|
||||||
UINT_PTR TimerID = 0;
|
UINT_PTR TimerID = 0;
|
||||||
typedef void (*GetWordProc_t)(TCurrentMode *);
|
typedef void (*GetWordProc_t)(TCurrentMode *);
|
||||||
|
@ -29,9 +30,29 @@ HWND WndParent,WndChild;
|
||||||
|
|
||||||
static void SendWordToServer()
|
static void SendWordToServer()
|
||||||
{
|
{
|
||||||
DWORD SendMsgAnswer;
|
DWORD SendMsgAnswer, flags;
|
||||||
if(uGdAskMessage) {
|
LRESULT lr;
|
||||||
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;
|
int n;
|
||||||
gds.dwSize = sizeof(gds);
|
gds.dwSize = sizeof(gds);
|
||||||
gds.cwData = Buffer;
|
gds.cwData = Buffer;
|
||||||
|
@ -51,23 +72,28 @@ DWORD SendMsgAnswer;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (hGetWordLib == 0) {
|
|
||||||
hGetWordLib = LoadLibrary(GlobalData->LibName);
|
if( ( flags & GD_FLAG_METHOD_STANDARD ) != 0 && GetWordProc != 0 ) {
|
||||||
if (hGetWordLib) {
|
|
||||||
GetWordProc = (GetWordProc_t)GetProcAddress(hGetWordLib, "__gdGetWord");
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
hGetWordLib = (HINSTANCE)-1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (GetWordProc) {
|
|
||||||
GlobalData->CurMod.WND = GlobalData->LastWND;
|
GlobalData->CurMod.WND = GlobalData->LastWND;
|
||||||
GlobalData->CurMod.Pt = GlobalData->LastPt;
|
GlobalData->CurMod.Pt = GlobalData->LastPt;
|
||||||
GetWordProc(&(GlobalData->CurMod));
|
GetWordProc(&(GlobalData->CurMod));
|
||||||
if (GlobalData->CurMod.WordLen > 0) {
|
if (GlobalData->CurMod.WordLen > 0) {
|
||||||
SendMessageTimeout(GlobalData->ServerWND, WM_MY_SHOW_TRANSLATION, 0, 0, SMTO_ABORTIFHUNG, MOUSEOVER_INTERVAL, &SendMsgAnswer);
|
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)
|
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)
|
LRESULT CALLBACK MouseHookProc(int nCode, WPARAM wParam, LPARAM lParam)
|
||||||
{
|
{
|
||||||
DWORD wso;
|
DWORD wso;
|
||||||
|
|
||||||
if ((nCode == HC_ACTION) && ((wParam == WM_MOUSEMOVE) || (wParam == WM_NCMOUSEMOVE)) && (GlobalData != NULL)) {
|
if ((nCode == HC_ACTION) && ((wParam == WM_MOUSEMOVE) || (wParam == WM_NCMOUSEMOVE)) && (GlobalData != NULL)) {
|
||||||
wso = WaitForSingleObject(hSynhroMutex, 0);
|
wso = WaitForSingleObject(hSynhroMutex, 0);
|
||||||
if (wso == WAIT_OBJECT_0 || wso == WAIT_ABANDONED) {
|
if (wso == WAIT_OBJECT_0 || wso == WAIT_ABANDONED) {
|
||||||
|
@ -163,12 +190,18 @@ BOOL APIENTRY DllMain (HINSTANCE hInst /* Library instance handle. */ ,
|
||||||
{
|
{
|
||||||
case DLL_PROCESS_ATTACH:
|
case DLL_PROCESS_ATTACH:
|
||||||
g_hInstance = hInst;
|
g_hInstance = hInst;
|
||||||
|
if(hHookMutex==0) {
|
||||||
|
hHookMutex = CreateMutex(NULL, FALSE, "GoldenDictTextOutHookMutex");
|
||||||
|
}
|
||||||
if(hSynhroMutex==0) {
|
if(hSynhroMutex==0) {
|
||||||
hSynhroMutex = CreateMutex(NULL, FALSE, "GoldenDictTextOutSpyMutex");
|
hSynhroMutex = CreateMutex(NULL, FALSE, "GoldenDictTextOutSpyMutex");
|
||||||
if(hSynhroMutex==0) return(FALSE);
|
if(hSynhroMutex==0) {
|
||||||
|
return(FALSE);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
ThTypes_Init();
|
ThTypes_Init();
|
||||||
uGdAskMessage = RegisterWindowMessage(GD_MESSAGE_NAME);
|
uGdAskMessage = RegisterWindowMessage(GD_MESSAGE_NAME);
|
||||||
|
FindGetPhysicalCursorPos();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case DLL_PROCESS_DETACH:
|
case DLL_PROCESS_DETACH:
|
||||||
|
@ -190,6 +223,14 @@ BOOL APIENTRY DllMain (HINSTANCE hInst /* Library instance handle. */ ,
|
||||||
if ((hGetWordLib != 0)&&(hGetWordLib != (HINSTANCE)(-1))) {
|
if ((hGetWordLib != 0)&&(hGetWordLib != (HINSTANCE)(-1))) {
|
||||||
FreeLibrary(hGetWordLib);
|
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();
|
Thtypes_End();
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
|
@ -5,8 +5,12 @@ TGlobalDLLData *GlobalData = NULL;
|
||||||
|
|
||||||
void ThTypes_Init()
|
void ThTypes_Init()
|
||||||
{
|
{
|
||||||
if (!MMFHandle)
|
if (!MMFHandle) {
|
||||||
MMFHandle = CreateFileMappingA(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, sizeof(TGlobalDLLData), "GoldenDictTextOutHookSharedMem");
|
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)
|
if (!GlobalData && MMFHandle != NULL)
|
||||||
GlobalData = MapViewOfFile(MMFHandle, FILE_MAP_ALL_ACCESS, 0, 0, 0);
|
GlobalData = MapViewOfFile(MMFHandle, FILE_MAP_ALL_ACCESS, 0, 0, 0);
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,11 @@
|
||||||
|
|
||||||
#include <windows.h>
|
#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
|
#ifdef __cplusplus
|
||||||
extern "C"
|
extern "C"
|
||||||
{
|
{
|
||||||
|
|
8
mouseover_win32/guids.c
Normal file
8
mouseover_win32/guids.c
Normal 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);
|
||||||
|
|
|
@ -118,6 +118,9 @@ Preferences::Preferences( QWidget * parent, Config::Preferences const & p ):
|
||||||
|
|
||||||
ui.scanPopupAltMode->setChecked( p.scanPopupAltMode );
|
ui.scanPopupAltMode->setChecked( p.scanPopupAltMode );
|
||||||
ui.scanPopupAltModeSecs->setValue( p.scanPopupAltModeSecs );
|
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
|
// Different platforms have different keys available
|
||||||
|
|
||||||
|
@ -130,6 +133,11 @@ Preferences::Preferences( QWidget * parent, Config::Preferences const & p ):
|
||||||
ui.rightCtrl->hide();
|
ui.rightCtrl->hide();
|
||||||
ui.leftShift->hide();
|
ui.leftShift->hide();
|
||||||
ui.rightShift->hide();
|
ui.rightShift->hide();
|
||||||
|
|
||||||
|
// This settings is Windows-specific
|
||||||
|
ui.scanPopupUseUIAutomation->hide();
|
||||||
|
ui.scanPopupUseIAccessibleEx->hide();
|
||||||
|
ui.scanPopupUseGDMessage->hide();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Sound
|
// Sound
|
||||||
|
@ -224,6 +232,9 @@ Config::Preferences Preferences::getPreferences()
|
||||||
|
|
||||||
p.scanPopupAltMode = ui.scanPopupAltMode->isChecked();
|
p.scanPopupAltMode = ui.scanPopupAltMode->isChecked();
|
||||||
p.scanPopupAltModeSecs = ui.scanPopupAltModeSecs->value();
|
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.pronounceOnLoadMain = ui.pronounceOnLoadMain->isChecked();
|
||||||
p.pronounceOnLoadPopup = ui.pronounceOnLoadPopup->isChecked();
|
p.pronounceOnLoadPopup = ui.pronounceOnLoadPopup->isChecked();
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>572</width>
|
<width>572</width>
|
||||||
<height>347</height>
|
<height>357</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<property name="windowTitle">
|
<property name="windowTitle">
|
||||||
|
@ -276,6 +276,19 @@ With this on however, it will hide the main window.</string>
|
||||||
<layout class="QVBoxLayout" name="verticalLayout_10">
|
<layout class="QVBoxLayout" name="verticalLayout_10">
|
||||||
<item>
|
<item>
|
||||||
<spacer name="verticalSpacer_7">
|
<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">
|
<property name="orientation">
|
||||||
<enum>Qt::Vertical</enum>
|
<enum>Qt::Vertical</enum>
|
||||||
</property>
|
</property>
|
||||||
|
@ -545,9 +558,88 @@ seconds, which is specified here.</string>
|
||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</item>
|
</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&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>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</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>
|
<item>
|
||||||
<spacer name="verticalSpacer_6">
|
<spacer name="verticalSpacer_6">
|
||||||
<property name="orientation">
|
<property name="orientation">
|
||||||
|
@ -1069,7 +1161,6 @@ download page.</string>
|
||||||
<tabstop>proxyPort</tabstop>
|
<tabstop>proxyPort</tabstop>
|
||||||
<tabstop>proxyUser</tabstop>
|
<tabstop>proxyUser</tabstop>
|
||||||
<tabstop>proxyPassword</tabstop>
|
<tabstop>proxyPassword</tabstop>
|
||||||
<tabstop>enableScanPopup</tabstop>
|
|
||||||
</tabstops>
|
</tabstops>
|
||||||
<resources>
|
<resources>
|
||||||
<include location="resources.qrc"/>
|
<include location="resources.qrc"/>
|
||||||
|
|
29
scanpopup.cc
29
scanpopup.cc
|
@ -153,8 +153,18 @@ ScanPopup::ScanPopup( QWidget * parent,
|
||||||
connect( &mouseGrabPollTimer, SIGNAL( timeout() ),
|
connect( &mouseGrabPollTimer, SIGNAL( timeout() ),
|
||||||
this, SLOT(mouseGrabPoll()) );
|
this, SLOT(mouseGrabPoll()) );
|
||||||
|
|
||||||
|
#ifdef Q_OS_WIN32
|
||||||
|
|
||||||
connect( &MouseOver::instance(), SIGNAL( askNeedWord( bool * ) ),
|
connect( &MouseOver::instance(), SIGNAL( askNeedWord( bool * ) ),
|
||||||
this, SLOT( needHandleWord( bool * ) ), Qt::DirectConnection );
|
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()
|
ScanPopup::~ScanPopup()
|
||||||
|
@ -768,7 +778,26 @@ void ScanPopup::mutedDictionariesChanged()
|
||||||
definition->updateMutedContents();
|
definition->updateMutedContents();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef Q_OS_WIN32
|
||||||
|
|
||||||
void ScanPopup::needHandleWord( bool *pNeed )
|
void ScanPopup::needHandleWord( bool *pNeed )
|
||||||
{
|
{
|
||||||
*pNeed = !cfg.preferences.enableScanPopupModifiers || checkModifiersPressed( cfg.preferences.scanPopupModifiers );
|
*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
|
||||||
|
|
|
@ -134,7 +134,12 @@ private slots:
|
||||||
void altModeExpired();
|
void altModeExpired();
|
||||||
void altModePoll();
|
void altModePoll();
|
||||||
|
|
||||||
|
#ifdef Q_OS_WIN32
|
||||||
void needHandleWord(bool *pNeed);
|
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
|
/// 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
|
/// mouse as it may move away from the window. This simulates mouse grab, in
|
||||||
|
|
330
uiauto.hh
Normal file
330
uiauto.hh
Normal 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
114
wordbyauto.cc
Normal 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
6
wordbyauto.hh
Normal file
|
@ -0,0 +1,6 @@
|
||||||
|
#ifndef __WORD_BY_AUTO_HH_INCLUDED
|
||||||
|
#define __WORD_BY_AUTO_HH_INCLUDED
|
||||||
|
|
||||||
|
WCHAR *gdGetWordAtPointByAutomation( POINT pt );
|
||||||
|
|
||||||
|
#endif
|
Loading…
Reference in a new issue