이 CLI는 로그인된 PC 메신저의 창을 조작해 채팅방을 찾고 이미지를 주고받는다. 사람이 매번 화면을 찾아 누르는 대신, Rust 프로그램이 명령줄의 요청을 받아 키보드 입력과 Windows 메시지를 보낸다. 로그인된 앱과 사용할 수 있는 데스크톱은 여전히 필요하다.

제작은 직접 버튼을 누르지 않고 명령줄로만 조작할 수 있느냐는 질문에서 시작해 이미지 전송과 다운로드로 이어졌다. 당시 소스와 검증 기록에는 명령이 받는 요청과 실제 창에서 하는 일이 따로 드러난다. 이 글에서는 그 기록을 읽었으며 메신저를 열거나 대화·첨부를 다시 읽지는 않았다.

CLI가 호출하는 것은 Windows의 창 조작이다

이 구현의 조작 엔진은 Rust와 Windows API다. 열린 창과 자식 컨트롤을 찾고, 대상 창을 활성화하고, 필요한 입력을 보낸다. 메시지 서비스의 별도 API로 본문을 전송하는 구조가 아니다. 기존 PC 앱의 로그인 세션을 이용하며 로그인 정보 자체를 옮기지 않는다.

검증 기록의 ‘화면 클릭 도구를 쓰지 않았다’는 표현도 이 범위에서 읽어야 한다. 외부 클릭 도구 대신 CLI가 동작을 시작했지만, Rust 내부에서는 키보드 입력과 마우스 메시지를 사용했다. 명령 한 줄로 묶었다고 전면 창이나 포커스의 영향을 받지 않는 실행기로 바뀐 것은 아니다.

검색이 끝난 뒤에도 정확한 창을 다시 확인한다

열린 채팅방을 고를 때는 제목이 정확히 일치하고 입력 컨트롤이 있는 창이 하나인지 확인한다. 같은 이름의 열린 창이 여럿이면 중단한다. 검색으로 방을 열 때도 검색 입력창과 목록을 특정하고, 결과를 연 뒤 정확한 제목의 창이 전면에 왔는지 확인한다. 입력 직전에는 창 핸들, 프로세스와 제목이 그대로인지 다시 검사한다.

목록 명령이 보여 주는 것은 현재 열린 채팅방이고, 읽기 명령이 가져오는 것은 앱에 로드된 대화다. 전체 과거 대화 검색이나 상시 감시는 지원 범위로 볼 수 없다. 방을 열거나 읽으면 읽음 상태도 바뀔 수 있으므로, 조회 명령을 만들 때 이 영향까지 설명해야 한다.

작업 중 새로 복사한 내용은 덮지 않는다

텍스트 입력은 클립보드를 잠시 사용해 실제 붙여넣기를 수행한다. 소스는 지원하는 텍스트·HTML·RTF 형식을 메모리에 보관하고, 복원을 검증하지 않은 이미지나 파일 형식이 있으면 변경 전에 멈춘다. 문자열 하나를 저장해 모든 클립보드 내용을 보존했다고 처리하지 않았다.

복원할 때는 클립보드의 변경 번호를 확인한다. 작업 사이 다른 프로그램이 새 내용을 복사했다면 이전 내용을 덮어쓰지 않고 복원하지 못했다는 결과를 돌려준다. 입력 뒤 복원에 실패하면 전송도 중단한다. 다만 입력이 이미 진행됐을 수 있으므로 중단을 모든 화면 상태의 원상복구로 읽어서는 안 된다. 같은 CLI 사이의 실행 잠금도 다른 앱이나 사람의 키보드 조작까지 막지는 않는다.

최신 이미지라는 이름에도 화면 배치 조건이 있다

이미지 다운로드 명령은 대화 목록 끝으로 이동한 뒤 창의 화면 배율(DPI)에 맞춘 상대 위치에 마우스 메시지를 보내 이미지 뷰어를 연다. 대화 데이터의 첨부 식별자를 읽어 고르는 선택기는 아니다. 검증한 범위는 대화 맨 아래 오른쪽의 최신 발신 가로형 이미지이며, 당시 시험 자료는 1000×640 PNG였다.

그 기록을 수신 이미지나 다른 크기·배치까지 검증한 것으로 확대하지 않는다. 뷰어가 열린 뒤에는 별도의 저장 경로가 이어진다. 이름이 download-last-image라고 간단해도 이미지 선택 조건과 저장 동작은 다른 확인이다. 레이아웃이 바뀐 앱에 옮긴다면 먼저 같은 위치가 여전히 의도한 대상을 가리키는지 확인해야 한다.

파일 이름 입력 뒤 실제 경로와 바이트를 확인한다

저장 함수는 절대 경로를 요구하고 기존 파일이 있으면 덮어쓰지 않는다. 뷰어에 속한 저장 창을 찾은 뒤 경로를 붙여 넣고, 입력창에서 읽은 문자열이 요청한 경로와 같은지 확인한다. 저장 후에는 지정 경로에 파일이 생겼는지와 내용이 비어 있지 않은지 확인하고 바이트 수·SHA-256을 반환한다.

과거 검증에는 저장 창의 경로 반영 문제로 시험 파일이 기본 다운로드 폴더에 생긴 실패도 남아 있다. 이후 입력 처리를 수정해 지정 경로에 직접 저장되는 것을 확인했고, 보고서는 원본과 다운로드본의 바이트·해시가 같다고 기록했다. 전송은 CLI 단계별 동작으로 시험했고, 통합 다운로드 명령도 별도로 확인했다. 통합 전송 명령 전체를 같은 방식으로 다시 시험했다고 쓰지는 않는다.

명령의 성공과 실제 대화의 결과를 함께 읽는다

초기 텍스트 전송 시도는 입력창에만 남고 대화에는 나타나지 않았다. 이후 키보드 입력 경로를 수정했다는 기록이 있고, 읽은 소스는 실제 붙여넣기와 포커스 검사 후 Enter 입력을 사용한다. 입력 함수 종료만으로 전송을 확정하지 않고 대화에 시험 문구가 나타났는지도 별도로 읽었다. 그 관찰도 상대방의 수신·읽음 확인과는 다르다.

이 기록에서 실제 창 조작을 맡은 엔진은 Rust다. Python은 합성 시험 이미지를 만드는 보조 스크립트에 쓰였다. 이 글은 소스·시험 이미지 생성 스크립트·당시 집계 보고서를 대조했으며 원래 대화·첨부·클립보드와 앱을 조작하지 않았다. 현재 설치판, 다른 창 배치, 모든 파일 형식의 동작도 새로 검수하지 않았다. 다른 PC 앱에 적용할 때는 아래 조건부터 확인할 수 있다.

  1. 동작에 필요한 로그인·데스크톱·전면 창 조건을 적는다.
  2. 대상을 제목뿐 아니라 창과 프로세스의 관계로 다시 확인한다.
  3. 클립보드처럼 다른 작업과 공유하는 자원의 보존 범위를 정한다.
  4. 이미지 선택과 저장을 다른 단계로 검사한다.
  5. 명령 반환값, 앱 안의 변화, 실제 저장 파일을 각각 대조한다.