. 더블클릭

마우스는 아주 단순한 도구이지만 마우스로 할 수 있는 작업의 종류는 무척이나 많다. 클릭, 더블클릭, 양쪽 클릭, 드래그, 더블클릭 드래그, 트리플클릭 등등 마우스 자체의 액션도 풍부하지만 키보드와 결합되면 표현 가능한 명령의 수가 대폭 늘어난다. 뿐만 아니라 ApiEdit의 마진 같은 특별한 영역에서의 마우스 액션은 또 다른 의미를 가질 수 있기 때문에 마우스 액션의 종류는 거의 상상을 초월할 정도다.

편집기들은 사용자들의 다양한 명령들을 신속하게 받아들이기 위해 마우스에 대한 충분한 지원을 해야 한다. 캐럿을 옮기고 선택영역을 만드는 것만이 마우스로 할 수 있는 일의 전부가 아니다. 마우스는 굉장히 쓰기 편리한 도구이고 키보드보다 더 빨리 작업할 수 있도록 하므로 편집기는 모름지기 마우스 액션을 최대한 풍부하게 지원해야 한다.

ApiEdit는 아직 더블클릭을 지원하지 않는데 더블클릭에 단어 선택 기능을 넣어 보도록 하자. 단어 단위로 이동시킨다거나 복사할 일이 많기 때문에 이 기능은 많은 편리함을 준다. 새로운 기능들이 추가되므로 프로젝트를 ApiEdit8로 새로 작성하도록 하자. 늘 해 오던 대로 ApiEdit7을 복사하여 새 프로젝트를 만들되 줄번호 보기, 제어문자 보기, 현재행 보기 등의 플래그들은 테스트가 끝났으므로 FALSE로 바꾸어 놓는 것이 깔끔하다. OnCreate에 있는 예문은 여기서도 필요하므로 그냥 두도록 하자.

윈도우가 더블클릭 메시지를 받으려면 윈도우 클래스에 CS_DBLCLKS 스타일을 줘야 한다. 이 스타일이 있어야 WM_LBUTTONDBLCLK 메시지가 전달된다. WinMain의 윈도우 클래스 스타일을 수정하도록 하자.

 

int APIENTRY WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance

       ,LPSTR lpszCmdParam,int nCmdShow)

{

     ....

     WndClass.style=CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS;

     RegisterClass(&WndClass);

 

다음 함수는 nPos 위치에 있는 단어를 조사하는데 레퍼런스로 전달된 s, e에 시작 오프셋과 끝 오프셋을 대입한다. 앞에서 작성했던 GetPrevWord, GetNextWord와 비슷한 방식대로 단어를 찾는다.

 

void GetNowWord(int nPos, int &s, int &e)

{

     for (;;nPos--) {

          if (IsDelimiter(nPos)==TRUE || nPos==0) {

              break;

          }

     }

 

     if (nPos != 0 && nPos != lstrlen(buf) && IsDelimiter(nPos+1)==FALSE) {

          nPos++;

     }

     s=nPos;

 

     for (;;nPos++) {

          if (IsDelimiter(nPos)==TRUE) {

              break;

          }

     }

     e=nPos;

}

 

현재 위치에서 앞쪽으로 이동하며 구분자를 찾아 그 다음 오프셋을 시작위치로 취한다. 단 버퍼의 처음인 경우와 문서의 끝 그리고 다음 문자도 구분자인 경우는 첫 위치가 단어의 시작이다. 시작위치에서 뒤로 이동하며 다음 구분자를 찾으면 단어의 끝을 찾을 수 있다.

마우스 더블클릭 메시지는 WM_LBUTTONDBLCLK라는 별도의 번호가 할당되어 있으나 메시지크래커는 이 메시지와 WM_LBUTTONDOWN 메시지를 같은 함수에서 처리하도록 연결하며 fDoubleClick 인수로 더블클릭 여부를 알려준다. 그래서 더블클릭시의 처리는 OnLButtonDown 함수의 fDoubleClick TRUE인 조건문 안에 작성하면 된다.

 

void OnLButtonDown(HWND hWnd, BOOL fDoubleClick, int x, int y, UINT keyFlags)

{

     int toff;

 

     if (fDoubleClick) {

          toff=GetOffFromXY(x+xPos,y+yPos);

          GetNowWord(toff,SelStart,SelEnd);

          if (SelStart != SelEnd) {

              off=SelEnd;

              SetCaret();

              Invalidate(-1);

          }

          return;

     }

     ....

 

현재 오프셋을 찾고 이 오프셋 위치의 단어를 찾아 선택했다. 문장의 아무 곳이나 더블클릭해보면 단어가 선택될 것이다. 이 함수는 마우스 클릭 메시지도 같이 처리하고 있기 때문에 더블클릭을 처리했으면 지체없이 리턴하여 더블클릭 이외의 다른 코드가 실행되지 않도록 해야 한다. 함수 중간에서 리턴하는 것은 별로 바람직하지 않지만 이 경우는 한 함수에 두 메시지가 전달되기 때문에 처리 영역을 명확히 나누기 위해 return 문을 사용하였다.