goldendict-ng/src/mouseover.cc
Konstantin Isakov babde3d53d *! Introduce gd::wstring and gd:wchar and switch to them from std::wstring and
wchar_t. This changes nothing on Linux and most other systems, but on Win32
   it causes to use normal UCS-4 strings instead of Win32's usual UTF-16.
2009-04-18 17:20:12 +00:00

209 lines
5 KiB
C++

#include "mouseover.hh"
#include "utf8.hh"
#include <QCoreApplication>
#include <QDir>
#ifdef Q_OS_WIN32
#include "mouseover_win32/ThTypes.h"
#endif
MouseOver & MouseOver::instance()
{
static MouseOver m;
return m;
}
#ifdef Q_OS_WIN32
const UINT WM_MY_SHOW_TRANSLATION = WM_USER + 301;
static wchar_t className[] = L"GoldenDictMouseover";
#endif
MouseOver::MouseOver()
{
#ifdef Q_OS_WIN32
mouseOverEnabled = false;
ThTypes_Init();
memset( GlobalData, 0, sizeof( TGlobalDLLData ) );
strcpy( GlobalData->LibName,
QDir::toNativeSeparators( QDir( QCoreApplication::applicationDirPath() ).filePath( "GdTextOutHook.dll" ) ).toLocal8Bit().data() );
// Create the window to recive spying results to
WNDCLASSEX wcex;
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;
RegisterClassEx( &wcex );
GlobalData->ServerWND = CreateWindow( className, L"", 0, 0, 0, 0, 0, GetDesktopWindow(), NULL, GetModuleHandle( 0 ), 0 );
spyDll = LoadLibrary( QDir::toNativeSeparators( QDir( QCoreApplication::applicationDirPath() ).filePath( "GdTextOutSpy.dll" ) ).toStdWString().c_str() );
if ( spyDll )
activateSpyFn = ( ActivateSpyFn ) GetProcAddress( spyDll, "ActivateTextOutSpying" );
#endif
}
void MouseOver::enableMouseOver()
{
#ifdef Q_OS_WIN32
if ( !mouseOverEnabled && activateSpyFn )
{
activateSpyFn( true );
mouseOverEnabled = true;
}
#endif
}
void MouseOver::disableMouseOver()
{
#ifdef Q_OS_WIN32
if ( mouseOverEnabled && activateSpyFn )
{
activateSpyFn( false );
mouseOverEnabled = false;
}
#endif
}
#ifdef Q_OS_WIN32
LRESULT CALLBACK MouseOver::eventHandler( HWND hwnd, UINT msg,
WPARAM wparam, LPARAM lparam )
{
if ( msg == WM_MY_SHOW_TRANSLATION )
{
int wordSeqPos;
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 )
{
// 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
QString word;
if ( wordSeq[ wordSeqPos ].isSpace() )
{
// Currently we ignore such cases
return DefWindowProc( hwnd, msg, wparam, lparam );
}
else
if ( !wordSeq[ wordSeqPos ].isLetterOrNumber() )
{
// Special case: the cursor points to something which doesn't look like a
// middle of the word -- assume that it's something that joins two words
// together.
int begin = wordSeqPos;
for( ; begin; --begin )
if ( !wordSeq[ begin - 1 ].isLetterOrNumber() )
break;
int end = wordSeqPos;
while( ++end < wordSeq.size() )
if ( !wordSeq[ end ].isLetterOrNumber() )
break;
if ( end - begin == 1 )
{
// Well, turns out it was just a single non-letter char, discard it
return DefWindowProc( hwnd, msg, wparam, lparam );
}
word = wordSeq.mid( begin, end - begin );
}
else
{
// Cursor points to a letter -- cut the word it points to
int begin = wordSeqPos;
for( ; begin; --begin )
if ( !wordSeq[ begin - 1 ].isLetterOrNumber() )
break;
int end = wordSeqPos;
while( ++end < wordSeq.size() )
{
if ( !wordSeq[ end ].isLetterOrNumber() )
break;
}
word = wordSeq.mid( begin, end - begin );
}
emit instance().hovered( word );
}
return DefWindowProc( hwnd, msg, wparam, lparam );
}
#endif
MouseOver::~MouseOver()
{
#ifdef Q_OS_WIN32
disableMouseOver();
FreeLibrary( spyDll );
DestroyWindow( GlobalData->ServerWND );
UnregisterClass( className, GetModuleHandle( 0 ) );
Thtypes_End();
#endif
}