한글 문서를 프로그램으로 채울 때 글자를 넣는 것보다 먼저 해결해야 하는 게 "어디에 넣을 것인가"입니다. HwpCtrl(한글 웹/ActiveX 컨트롤)에서 그 위치를 잡는 메서드가 MovePos입니다. 캐럿, 즉 입력 위치를 문서 처음이나 끝, 특정 문단의 특정 글자, 표 안의 옆 칸 같은 곳으로 옮겨 줍니다. 반환값은 성공하면 true, 실패하면 false입니다.
구문
BOOL MovePos(VARIANT& moveID, VARIANT& para, VARIANT& pos)
boolean MovePos([number moveID], [number para], [number pos])
세 인자 모두 생략할 수 있습니다. moveID를 생략하면 moveCurList(1)로 처리됩니다.
moveID 값
| ID | 값 | 동작 |
|---|---|---|
| moveMain | 0 | 루트 리스트의 특정 위치 (para, pos로 지정) |
| moveCurList | 1 | 현재 리스트의 특정 위치 (para, pos로 지정) |
| moveTopOfFile | 2 | 문서 시작 |
| moveBottomOfFile | 3 | 문서 끝 |
| moveTopOfList | 4 | 현재 리스트의 시작 |
| moveBottomOfList | 5 | 현재 리스트의 끝 |
| moveStartOfPara | 6 | 현재 문단의 시작 |
| moveEndOfPara | 7 | 현재 문단의 끝 |
| moveStartOfWord | 8 | 현재 단어의 시작 (현재 리스트 안에서만) |
| moveEndOfWord | 9 | 현재 단어의 끝 (현재 리스트 안에서만) |
| moveNextPara | 10 | 다음 문단의 시작 (현재 리스트 안에서만) |
| movePrevPara | 11 | 앞 문단의 끝 (현재 리스트 안에서만) |
| moveNextPos | 12 | 한 글자 뒤로 (서브 리스트를 넘나듦) |
| movePrevPos | 13 | 한 글자 앞으로 (서브 리스트를 넘나듦) |
| moveNextPosEx | 14 | 한 글자 뒤로 (서브 리스트를 넘나들며 머리말/꼬리말, 각주/미주, 글상자까지 포함) |
| movePrevPosEx | 15 | 한 글자 앞으로 (서브 리스트를 넘나들며 머리말/꼬리말, 각주/미주, 글상자까지 포함) |
| moveNextChar | 16 | 한 글자 뒤로 (현재 리스트 안에서만) |
| movePrevChar | 17 | 한 글자 앞으로 (현재 리스트 안에서만) |
| moveNextWord | 18 | 한 단어 뒤로 (현재 리스트 안에서만) |
| movePrevWord | 19 | 한 단어 앞으로 (현재 리스트 안에서만) |
| moveNextLine | 20 | 한 줄 아래로 |
| movePrevLine | 21 | 한 줄 위로 |
| moveStartOfLine | 22 | 현재 줄의 시작 |
| moveEndOfLine | 23 | 현재 줄의 끝 |
| moveParentList | 24 | 한 레벨 상위 리스트로 |
| moveTopLevelList | 25 | 탑레벨 리스트로 |
| moveRootList | 26 | 루트 리스트로 |
| moveCurrentCaret | 27 | 현재 캐럿 위치로 (캐럿 위치가 뷰 맨 위로 올라감, ver:0x0507013B, 0x06000105) |
| moveLeftOfCell | 100 | 현재 셀의 왼쪽 셀 |
| moveRightOfCell | 101 | 현재 셀의 오른쪽 셀 |
| moveUpOfCell | 102 | 현재 셀의 위쪽 셀 |
| moveDownOfCell | 103 | 현재 셀의 아래쪽 셀 |
| moveStartOfCell | 104 | 현재 셀이 있는 행(row)의 시작 |
| moveEndOfCell | 105 | 현재 셀이 있는 행(row)의 끝 |
| moveTopOfCell | 106 | 현재 셀이 있는 열(column)의 시작 |
| moveBottomOfCell | 107 | 현재 셀이 있는 열(column)의 끝 |
| moveScrPos | 200 | 한/글 문서 화면의 screen 좌표로 위치 설정 |
| moveScanPos | 201 | GetText() 실행 후의 위치로 이동 |
"리스트"가 뭔지 알아야 표가 읽힌다
표를 보면 "현재 리스트 안에서만", "서브 리스트를 넘나듦" 같은 말이 계속 나옵니다. 한글 문서에서 본문은 루트 리스트이고, 표의 각 셀이나 글상자, 각주, 머리말 같은 것은 그 안에 딸린 별도의 리스트(서브 리스트)로 취급됩니다. 그래서 표 셀 안에 캐럿이 있을 때 moveNextChar(16)는 셀 끝에서 더 나가지 못하고 멈추지만, moveNextPos(12)는 셀 경계를 넘어 다음 위치로 이어집니다. 머리말·각주·글상자까지 훑어야 한다면 moveNextPosEx(14)를 씁니다.
moveParentList(24)와 moveRootList(26)는 셀이나 글상자 안에서 바깥으로 빠져나올 때 씁니다. 이동한 뒤의 위치는 상위 리스트에서 그 서브 리스트를 담고 있는 컨트롤 코드(표나 글상자 자체)가 있는 자리입니다. 이미 루트 리스트에 있어서 더 올라갈 곳이 없으면 위치는 그대로인 채 반환되고, 이동할 때 선택 영역(셀렉션)은 무조건 풀립니다. 셀 내용을 다 채우고 표 다음에 이어서 글을 쓰려는데 계속 셀 안에 갇혀 있다면 이 두 값을 확인해 보면 됩니다.
para와 pos
para는 이동할 문단 번호, pos는 그 문단 안의 문자 위치입니다. 둘 다 moveMain(0)이나 moveCurList(1)일 때만 의미가 있고, 나머지 moveID에서는 무시됩니다.
예외가 moveScrPos(200)입니다. 이때 para는 문단 번호가 아니라 화면 좌표로 해석되며, 하위 워드(LOWORD)가 x, 상위 워드(HIWORD)가 y입니다. 마우스 커서의 (x, y) 좌표를 그대로 넘기면 그 지점으로 캐럿이 갑니다. moveScanPos(201)는 문서를 검색(GetText로 훑는 중)하면서 캐럿을 옮기려 할 때만 쓸 수 있습니다.
호출 예
문서 끝으로 가서 내용을 덧붙이거나, 첫 문단 처음으로 돌아가는 정도가 가장 흔한 용도입니다.
// 문서 끝으로 이동
HwpCtrl.MovePos(3);
// 루트 리스트의 첫 문단(0), 첫 글자(0)로 이동
HwpCtrl.MovePos(0, 0, 0);
상수 이름(moveBottomOfFile 등)이 스크립트에서 정의돼 있지 않은 환경이 있으니 숫자로 넘기는 편이 안전합니다. 그리고 반환값이 false인데 그냥 넘어가면 엉뚱한 위치에 글자가 들어가는 일이 생기므로, 표 안을 이동하는 반복문에서는 결과를 확인하고 멈추는 조건으로 쓰는 게 좋습니다.