From 626934c0cc64a4965b36cd37f46be7c1df788387 Mon Sep 17 00:00:00 2001 From: Konstantin Isakov Date: Mon, 2 Feb 2009 20:28:53 +0000 Subject: [PATCH] Initial support for mouseover feature in Windows added. --- src/goldendict.pro | 10 ++- src/mouseover.cc | 190 +++++++++++++++++++++++++++++++++++++++++++++ src/mouseover.hh | 50 ++++++++++++ src/scanpopup.cc | 16 +++- src/scanpopup.hh | 2 + 5 files changed, 265 insertions(+), 3 deletions(-) create mode 100644 src/mouseover.cc create mode 100644 src/mouseover.hh diff --git a/src/goldendict.pro b/src/goldendict.pro index 59b0d1ed..960ce4b6 100644 --- a/src/goldendict.pro +++ b/src/goldendict.pro @@ -64,7 +64,8 @@ HEADERS += folding.hh \ wordfinder.hh \ groupcombobox.hh \ griparea.hh \ - keyboardstate.hh + keyboardstate.hh \ + mouseover.hh FORMS += groups.ui dictgroupwidget.ui mainwindow.ui sources.ui initializing.ui\ @@ -77,6 +78,11 @@ SOURCES += folding.cc main.cc dictionary.cc md5.c config.cc sources.cc \ dsl.cc dsl_details.cc filetype.cc fsencoding.cc groups.cc \ groups_widgets.cc instances.cc article_maker.cc scanpopup.cc \ articleview.cc externalviewer.cc dictlock.cc wordfinder.cc \ - groupcombobox.cc griparea.cc keyboardstate.cc + groupcombobox.cc griparea.cc keyboardstate.cc mouseover.cc + +win32 { + SOURCES += mouseover_win32/ThTypes.c + HEADERS += mouseover_win32/ThTypes.h +} RESOURCES += resources.qrc flags.qrc diff --git a/src/mouseover.cc b/src/mouseover.cc new file mode 100644 index 00000000..998c8289 --- /dev/null +++ b/src/mouseover.cc @@ -0,0 +1,190 @@ +#include "mouseover.hh" +#include "utf8.hh" +#include +#include + +#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 + + 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" ); + + if ( activateSpyFn ) + activateSpyFn( true ); + } + +#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? + + wchar_t 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 + + if ( activateSpyFn ) + activateSpyFn( false ); + + FreeLibrary( spyDll ); + + DestroyWindow( GlobalData->ServerWND ); + + UnregisterClass( className, GetModuleHandle( 0 ) ); + + Thtypes_End(); + +#endif +} + diff --git a/src/mouseover.hh b/src/mouseover.hh new file mode 100644 index 00000000..3dcc2808 --- /dev/null +++ b/src/mouseover.hh @@ -0,0 +1,50 @@ +#ifndef __MOUSEOVER_HH_INCLUDED__ +#define __MOUSEOVER_HH_INCLUDED__ + +#include + +#ifdef Q_OS_WIN32 +#include +#endif + +/// This is a mouseover feature interface, where you can point your mouse at +/// any word in any window and wait a little, and it would provide that word +/// for the translation. +/// This interface always exists, even on platforms that don't support that +/// feature -- it just remains dormant on them. +/// +/// The Windows platform is the only one supported; it works with the help of +/// two external .dll files, +class MouseOver: public QObject +{ + Q_OBJECT + +public: + + /// The class is a singleton. + static MouseOver & instance(); + +signals: + + /// Emitted when there was some text under cursor which was hovered over. + void hovered( QString const & ); + +private: + + MouseOver(); + ~MouseOver(); + +#ifdef Q_OS_WIN32 + + static LRESULT CALLBACK eventHandler( HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam ); + + typedef void ( *ActivateSpyFn )( bool ); + ActivateSpyFn activateSpyFn; + HINSTANCE spyDll; + +#endif + +}; + +#endif + diff --git a/src/scanpopup.cc b/src/scanpopup.cc index 8f57ae33..58ccead8 100644 --- a/src/scanpopup.cc +++ b/src/scanpopup.cc @@ -3,6 +3,7 @@ #include "scanpopup.hh" #include "folding.hh" +#include "mouseover.hh" #include #include #include @@ -59,6 +60,9 @@ ScanPopup::ScanPopup( QWidget * parent, connect( QApplication::clipboard(), SIGNAL( changed( QClipboard::Mode ) ), this, SLOT( clipboardChanged( QClipboard::Mode ) ) ); + + connect( &MouseOver::instance(), SIGNAL( hovered( QString const & ) ), + this, SLOT( mouseHovered( QString const & ) ) ); } void ScanPopup::clipboardChanged( QClipboard::Mode m ) @@ -72,7 +76,17 @@ void ScanPopup::clipboardChanged( QClipboard::Mode m ) QString subtype = "plain"; - inputWord = QApplication::clipboard()->text( subtype, m ).trimmed(); + handleInputWord( QApplication::clipboard()->text( subtype, m ) ); +} + +void ScanPopup::mouseHovered( QString const & str ) +{ + handleInputWord( str ); +} + +void ScanPopup::handleInputWord( QString const & str ) +{ + inputWord = str.trimmed(); if ( !inputWord.size() ) return; diff --git a/src/scanpopup.hh b/src/scanpopup.hh index e80c9902..d2777151 100644 --- a/src/scanpopup.hh +++ b/src/scanpopup.hh @@ -36,6 +36,7 @@ private: vector< QString > diacriticMatches, prefixMatches; + void handleInputWord( QString const & ); void initiateTranslation(); vector< sptr< Dictionary::Class > > const & getActiveDicts(); @@ -47,6 +48,7 @@ private: private slots: void clipboardChanged( QClipboard::Mode ); + void mouseHovered( QString const & ); void currentGroupChanged( QString const & ); void prefixMatchComplete( WordFinderResults r ); void diacriticButtonClicked();