C++Builder Programming Forum
C++Builder  |  Delphi  |  FireMonkey  |  C/C++  |  Free Pascal  |  Firebird
볼랜드포럼 BorlandForum
 경고! 게시물 작성자의 사전 허락없는 메일주소 추출행위 절대 금지
C++빌더 포럼
Q & A
FAQ
팁&트릭
강좌/문서
자료실
컴포넌트/라이브러리
메신저 프로젝트
볼랜드포럼 홈
헤드라인 뉴스
IT 뉴스
공지사항
자유게시판
해피 브레이크
공동 프로젝트
구인/구직
회원 장터
건의사항
운영진 게시판
회원 메뉴
북마크
볼랜드포럼 광고 모집

C++빌더 Q&A
C++Builder Programming Q&A
[58784] 편집기, 웹 부라우저등에서 마우스 위치 단어 가져오기
넘초보 [mspower] 3496 읽음    2009-10-15 08:16
% 영어 사전(야후미니사전등)에서 더블클릭, 마우스 오버시 단어 인식 부분을 구현해 보고자
  구글링을 통하여 위 소스까지 구현된 상태입니다. 그런데 아직, 딱 원하는 기능 구현에 어려움이 있군요.

    첫째 방법에서는 메모장 등 일반 편집기(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() 호출
    현재 마우스가 위치한 곳의 문자열을 가져온다.
}
//---------------------------------------------------------------------------

//============================================================================================

+ -

관련 글 리스트
58784 편집기, 웹 부라우저등에서 마우스 위치 단어 가져오기 넘초보 3496 2009/10/15
Google
Copyright © 1999-2015, borlandforum.com. All right reserved.