|
% 영어 사전(야후미니사전등)에서 더블클릭, 마우스 오버시 단어 인식 부분을 구현해 보고자
구글링을 통하여 위 소스까지 구현된 상태입니다. 그런데 아직, 딱 원하는 기능 구현에 어려움이 있군요.
첫째 방법에서는 메모장 등 일반 편집기(Edit, RichEdit,..)에서만 작동하고, IE, Firefox 등에서
작동하지 않네요.
두번째 방법은 IE, FireFox 등에서만 작동되고 메모장 등에서는 작동하지 않습니다. 그나마 마우스가
위치한 곳의 단어만 가져오는것이 아니라 HTML Tag 로 구분된 문장을 모두 가져온다는 겁니다.
이 문장을 파싱하여, 현재 커서가 위치한 곳의 "단어"만을 가져오려는데, 아직 풀지 못하고 있네요.ㅠ.ㅠ
제가 처음에 생각했던 방법(더블 클릭시)은 클립보드를 이용하는 것이 었습니다. 메모장, 웹 브라우저 모두
문자열 선택이 가능하며, CTRL+C 의 기능이 있기 때문에, 더블 클릭이 발생한 윈도우에 CTRL+C 를 전송하고
어플리케이션에서 클립보드 내용을 읽어 오면 될것으로 기대 했는데,,,,
// 1
keybd_event(VK_CONTROL, 0x1D, KEYEVENTF_EXTENDEDKEY,0 );
keybd_event('C', 0x2E, 0, 0);
keybd_event('C', 0x2E, KEYEVENTF_KEYUP, 0);
keybd_event(VK_CONTROL, 0x1D, KEYEVENTF_EXTENDEDKEY | KEYEVENTF_KEYUP, 0);
// 2
keybd_event(VK_CONTROL, 0x1D, 0, 0);
keybd_event('C', 0x2E, 0, 0);
keybd_event('C', 0x2E, KEYEVENTF_KEYUP, 0);
keybd_event(VK_CONTROL, 0x1D, KEYEVENTF_KEYUP, 0);
// 3
PostMessage(wHandle, WM_KEYDOWN, VK_CONTROL, 0);
PostMessage(wHandle, WM_CHAR, 'C', 0);
PostMessage(wHandle, WM_KEYUP, VK_CONTROL, 0);
// 4
unsigned int k = 0;
k = k | 1 | 0x1D << 16;
PostMessage(wHandle, WM_KEYDOWN, VK_CONTROL, k);
k = k | 1 | 0x1D << 16 | 1 << 30;
PostMessage(wHandle, WM_KEYDOWN, VK_CONTROL, k);
k = 1 | 0x2E << 16;
PostMessage(wHandle, WM_KEYDOWN, 'C', k);
k = 1 | 0x2E << 16 | 1 << 31 | 1 << 30;
PostMessage(wHandle, WM_KEYUP, 'C', k);
k = 1 | 0x1D << 16 | 1 << 31 | 1 << 30;
PostMessage(wHandle, WM_KEYUP, VK_CONTROL, k);
// 5 : 부모창 모두에거 보내보기.^^
HWND c = wHandle, t;
do {
t = GetParent(c);
if(t){
c = t;
PostMessage(wHandle, WM_KEYDOWN, VK_CONTROL, 0);
PostMessage(wHandle, WM_CHAR, 'C', 0);
PostMessage(wHandle, WM_KEYUP, VK_CONTROL, 0);
}
}while(t);
위 처럼 여러 방법으로 시도해 봐도, 클립보드에는 아무 변화가 없네요.
%% 풀어야할 문제 및 도움 요청
1. 클립보드로 복사하려면 어떤 메시지를 어떤 식으로 보내야 할까요?
2. 마우스 오버서 가져온 문자열에서, 현재 커서 위치의 단어를 가져오려면 어떻게 해야 할까요?
// 아래는 그동안 구현한 코드입니다. 다른분들에게 참고될까 하고 올려봅니다.
//============================================================================================
* 마우스 위치 단어, 더블클릭 단어 가져오기
//============================================================================================
1. 전역 마우스 후킹
Main.cpp
//---------------------------------------------------------------------------
// 마우스 후킹 함수
LRESULT CALLBACK mouseHookProc(int nCode, WPARAM wParam, LPARAM lParam)
{
if(nCode > -1){
SendMessage(wwHandle, WM_USER + 1, wParam, lParam);
}
return CallNextHookEx(NULL, nCode, wParam, lParam);
}
//---------------------------------------------------------------------------
// 전역 마우스 후킹 등록
void __fastcall TMainForm::FormShow(TObject *Sender)
{
m_mouseHook = SetWindowsHookEx(
WH_MOUSE_LL, /* Type of hook */
(HOOKPROC)::mouseHookProc, /* Hook process */
GetModuleHandle(NULL), /* Instance */
NULL // dwThreadID.
);
}
//---------------------------------------------------------------------------
// 종료시 후킹 해제
void __fastcall TMainForm::FormClose(TObject *Sender, TCloseAction &Action)
{
if(mouseHook) UnhookWindowsHookEx(mouseHook);
}
//---------------------------------------------------------------------------
void __fastcall TMainForm::OnMouse(TMessage &Message)
{
/*
PMSLLHOOKSTRUCT p = (PMSLLHOOKSTRUCT)Message.LParam;
p->pt.x, p->pt.y, p->time
Message.WParam : WM_MOUSEMOVE, WM_LBUTTONDOWN, WM_LBUTTONUP, WM_MOUSEWHEEL, WM_RBUTTONDOWN, WM_RBUTTONUP
WM_LBUTTONUP 메시지 발생시
마우스 좌표 p->pt.x, p->pt.y 와 발생 타임스탬프 p->time
m_DoubleClickSpeed, m_DoubleClickHeight, m_DoubleClickWidth 을 이용하여
더블 클릭 여부를 판단한다.
// 더블 클릭 윈도우 핸들을 구한다.
POINT pt;
pt.x = p->pt.x; pt.y = p->pt.y;
HWND wHandle = WindowFromPoint(pt);
*/
/* 첫번째 방법
// 더블 클릭한 라인을 구한다.
int nindex = (int)::SendMessage(wHandle, EM_LINEFROMCHAR, -1, 0L);
// buf 에 더블 클릭된 문자열을 구한다.
char buf[1024];
*(short int *)buf = 1024; // % 버퍼 선두 워드에 버퍼의 크기를 넣어줘야 한다. 잠간 고생을...^^
::SendMessage(wHandle, EM_GETLINE, nindex, (LPARAM)buf);
// 선택된 문자열 정보를 구한다.
DWORD dwStart, dwEnd;
int Sel = (int)::SendMessage(wHandle, EM_GETSEL, (WPARAM)&dwStart, (LPARAM)&dwEnd);
int SelLen = dwEnd - dwStart; // 선택된 문자열 길이
int ai = Sel & 0xffff;
int li = (int)::SendMessage(wHandle, EM_LINEINDEX, -1, 0);
int c = ai - li; // 선택된 문자열 시작 인덱스(0 이 처음)
String SelectedText = ((String)buf).SubString(c + 1, SelLen);
*/
/* 두번째 방법
SendMessage(wHandle, WM_COPY, 0, 0);
TClipboard *cb = new TClipboard();
wchar_t buf[1000];
cb->GetTextBuf(buf, 1000); // buf 에 더블 클릭시 선택된 문자열이 저장된다.
delete cb;
*/
}
//---------------------------------------------------------------------------
// 레지스트리에서 마우스 더블 클릭 정보를 읽어온다.
void __fastcall TMainForm::GetMouseDoubleClickInfo()
{
TRegistry *reg = new TRegistry(KEY_READ);
reg->RootKey = HKEY_CURRENT_USER;
bool openResult = reg->OpenKey("Control Panel\\Mouse\\", false);
if(openResult == true){
try {
m_DoubleClickSpeed = reg->ReadString("DoubleClickSpeed").ToInt();
m_DoubleClickHeight = reg->ReadString("DoubleClickHeight").ToInt();
m_DoubleClickWidth = reg->ReadString("DoubleClickWidth").ToInt();
#ifdef _DEBUG
Memo1->Lines->Add(
"DoubleClickSpeed : " + IntToStr(m_DoubleClickSpeed) +
", DoubleClickHeight : " + IntToStr(m_DoubleClickHeight) +
", DoubleClickWidth : " + IntToStr(m_DoubleClickWidth)
);
#endif
}
catch(const Exception &E){
m_DoubleClickSpeed = 500;
m_DoubleClickHeight = 4;
m_DoubleClickWidth = 4;
}
}
else {
m_DoubleClickSpeed = 500;
m_DoubleClickHeight = 4;
m_DoubleClickWidth = 4;
}
delete reg;
}
//---------------------------------------------------------------------------
Main.h
void __fastcall OnMouse(TMessage &Message);
BEGIN_MESSAGE_MAP
MESSAGE_HANDLER(WM_USER + 1, TMessage, OnMouse);
END_MESSAGE_MAP(TForm)
//============================================================================================
2. IAccessible 인터페이스를 이용한 방법
헤더 : Oleacc.h
라이브러리 : oleacc.lib
마우스 후킹은 1번 방법과 동일
Main.cpp
//---------------------------------------------------------------------------
bool __fastcall TMainForm::TextFromCursorPosition()
{
POINT CursorPos;
GetCursorPos(&CursorPos);
IAccessible *pIAcc;
VARIANT vt;
static String prevStr = "";
try {
if(SUCCEEDED(AccessibleObjectFromPoint(CursorPos, &pIAcc, &vt))){
BSTR pName = NULL;
if( SUCCEEDED(pIAcc->get_accName( vt, &pName ))){
if( pName && ::SysStringLen( pName )){
if(prevStr == String(pName)){
::SysFreeString( pName );
return false;
}
Edit1->Text = pName;
}
else {
::SysFreeString( pName );
return false;
}
}
else {
return false;
}
Edit2->Text = "";
BSTR pValue = NULL;
if( SUCCEEDED( pIAcc->get_accValue( vt, &pValue ))){
if( pValue && ::SysStringLen( pValue )){
Edit2->Text += pValue;
}
::SysFreeString( pValue );
}
VARIANT Role;
char cBuf[256];
if(SUCCEEDED(pIAcc->get_accRole(vt, &Role))){
GetRoleText(Role.lVal, cBuf, 256);
//if(pValue && ::SysStringLen( pValue )) {
// int t = 100;
//}
//::SysFreeString( pValue );
Memo1->Lines->Add(String("Role : ") + cBuf);
}
HWND ChildHandle;
RECT Rect;
if(SUCCEEDED(WindowFromAccessibleObject(pIAcc, &ChildHandle))){
GetWindowRect(ChildHandle, &Rect);
Memo1->Lines->Add(
"CURSOR X : " + IntToStr((int)CursorPos.x) +
" Y : " + IntToStr((int)CursorPos.y) +
", RECT Left : " + IntToStr((int)Rect.left) +
", Top : " + IntToStr((int)Rect.top) +
", Right : " + IntToStr((int)Rect.right) +
", Bottom : " + IntToStr((int)Rect.bottom)
);
}
VariantClear(&vt);
return true;
}// End if
}
__finally {
prevStr = Edit1->Text;
}
return false;
}// End TextFromCursorPosition
//---------------------------------------------------------------------------
void __fastcall TMainForm::OnMouse(TMessage &Message)
{
WM_MOUSEMOVE 메시지에서 좌표 및 타이머를 이용하여 TextFromCursorPosition() 호출
현재 마우스가 위치한 곳의 문자열을 가져온다.
}
//---------------------------------------------------------------------------
//============================================================================================
|