WSL의 Claude Code에서 Ctrl+V로 이미지가 붙여넣기 되지 않는 이유와 해결 방법
요약
WSL 환경의 Windows Terminal에서 Claude Code 사용 시 이미지 붙여넣기가 실패하는 기술적 원인과 해결 방법을 다룹니다. WSLg의 클립보드 동기화 문제와 Windows Terminal의 키 입력 가로채기 문제를 분석하고 이를 우회하는 워크플로우를 제안합니다.
핵심 포인트
- WSLg가 이미지를 구식 BMP 형식으로만 동기화하는 문제
- Linux 클립보드에 넣은 PNG가 WSLg에 의해 BMP로 덮어씌워지는 현상
- Windows Terminal이 Ctrl+V 입력을 가로채는 문제
- PNG 변환 프로그램 및 Linux 스크립트를 활용한 우회 해결책
요약(tl;dr): Windows Terminal 내의 WSL에서 Claude Code를 사용하시나요? Windows에서 이미지를 복사하고 Claude Code에서 Ctrl+V를 눌러도 작동하지 않습니다. 세 가지 문제가 발생합니다: (1) WSL이 Windows 이미지를 Claude Code가 읽을 수 없는 오래된 BMP 형식으로만 Linux 측에 전달합니다; (2) WSL이 잠시 후 사용자의 수정을 조용히 덮어씁니다; (3) Windows Terminal이 Claude Code가 인식하기 전에 Ctrl+V를 가로챕니다. 해결 방법은 이미지를 PNG로 변환하는 작은 Windows 프로그램, 이미지를 Linux 클립보드에 넣는 Linux 스크립트(그리고 WSL이 덮어쓴 후 한 번 더 재확인하는 기능), 그리고 키 입력이 프로그램에 실제로 도달할 수 있도록 Claude Code를 위한 추가 키 바인딩(keybinding) 하나를 사용하는 것입니다.
Windows에서 이미지를 복사합니다. Windows Terminal에서 실행된 WSL 터미널 내부의 Claude Code를 엽니다. Ctrl+V를 누릅니다. 아무 일도 일어나지 않습니다.
Windows 클립보드와 Claude Code의 채팅 입력창 사이에는 세 가지 작은 문제가 있습니다. 각각은 단독으로는 해롭지 않습니다. 하지만 이들이 모이면 이미지 붙여넣기가 완전히 실패하게 만듭니다. 업스트림(upstream) 수정이 이루어질 때까지 제가 구축한 우회 방법과 그 원인은 다음과 같습니다.
실제로 무엇이 고장 났는가
1. Windows-to-Linux 클립보드 동기화가 고대의 이미지 형식만 인식함
WSL에는 WSLg(
2. 동일한 Windows-to-Linux 동기화가 당신의 해결책을 조용히 덮어씌움
당신은 이렇게 생각할지도 모릅니다. '좋아, 이미지를 위해 WSLg를 우회하면 돼. Windows 클립보드를 직접 읽어서 이미지를 PNG로 변환한 다음, 그 PNG를 Linux 클립보드에 바로 밀어 넣는 거야. 그러면 Claude Code가 이미지를 찾을 때 PNG를 발견할 것이고, 붙여넣기도 작동하겠지.'
클립보드에 무언가를 넣기 위한 표준 Linux 명령어도 존재합니다: wl-copy.
그래서 당신은 정확히 그렇게 수행합니다 — Windows 이미지 → PNG → wl-copy --type image/png.
작동합니다. 잠시 동안은요. 그러다 다시 작동을 멈춥니다. WSL이 당신에게 행하는 방식은 다음과 같습니다:
- 당신이 Linux 클립보드에 PNG를 넣습니다.
- WSLg는 Linux 클립보드가 변경된 것을 감지하고, 의무적으로 이를 다시 Windows로 동기화합니다. 이제 Windows 클립보드는 "PNG"를 반영합니다.
- Windows 클립보드가 방금 변경되었습니다. 이 이벤트가 WSLg의 나머지 절반 — 즉, Windows의 변경 사항을 Linux로 밀어 넣는 절반 — 을 작동시킵니다. 문제 #1에서 알 수 있듯이, 이 절반은 BMP를 밀어 넣는 방법만 알고 있습니다.
- 따라서 Linux 쪽에 잘 넣어둔 PNG는, 넣은 직후 곧바로 고장 난 BMP로 덮어씌워집니다.
가장 잔인한 부분은 이겁니다: Windows 클립보드를 감시하기 위해 당신이 작성한 프로그램은 4단계가 발생하는 것을 전혀 보지 못합니다. WSLg는 Linux 클립보드에 직접 기록하며, 이를 수행하기 위해 Windows 클립보드를 거치지 않습니다. 따라서 감시자(watcher)의 관점에서는, Linux 클립보드가 아무런 반응을 유도할 수 없는 상태에서 조용히 변이(mutate)해 버리는 것입니다.
3. Windows Terminal이 Claude Code가 인식하기 전에 Ctrl+V를 가로챔
위의 모든 문제를 해결했고, 실제 PNG가 Linux 클립보드에 안정적으로 놓여 있다고 가정해 봅시다. Claude Code에서 Ctrl+V를 누릅니다. 여전히 아무 일도 일어나지 않습니다.
이유는 다음과 같습니다: 당신이 타이핑하고 있는 프로그램인 Windows Terminal은 Ctrl+V에 대해 자체적인 의미를 가지고 있습니다. 그것은 표준적인 "Windows 클립보드에서 텍스트 붙여넣기" 단축키입니다. 따라서 Windows Terminal 내부에서 Ctrl+V를 누르면:
- Windows Terminal이 해당 키 입력을 먼저 감지합니다.
- Windows Terminal은 Windows 클립보드 내용을 텍스트로 터미널 입력창에 붙여넣습니다 (또는 붙여넣기를 시도합니다).
- 이 키 입력은 Linux 측까지 도달하지 못합니다.
- Claude Code의 이미지 붙여넣기 코드(
chat:imagePaste)가 실행되지 않습니다.
터미널은 Claude Code보다 한 단계 상위 계층에 있습니다. 터미널은 하위 프로그램이 반응하기 전에 입력을 가로챕니다.
해결 방법
아래 다이어그램에 표시된 것처럼, 각 실패 원인에 대응하는 세 가지 작은 구성 요소가 있습니다.
clip-listener.exe — Windows에서 실행되며, Windows 자체의 GDI+를 통해 클립보드의 각 이미지를 실제 PNG로 인코딩합니다. BMP 문제(#1)를 우회합니다.
wsl-clip-bridge — WSL에서 실행되며, wl-copy를 사용하여 PNG를 Linux 클립보드에 밀어 넣습니다. 만약 WSLg가 우리의 PNG를 깨진 BMP로 덮어쓴다면, 0.5초 후에 다시 재확인(re-assert)합니다. 무음 덮어쓰기(silent clobber) 문제(#2)를 처리합니다.
~/.claude/keybindings.json의 Alt+V 키 바인딩 (Alt+V keybinding) — Windows Terminal이 가로챌 Ctrl+V를 거치지 않고 Claude Code의 chat:imagePaste 핸들러를 트리거합니다. #3 문제를 우회합니다.
브릿지가 설치되었을 때 변화하는 점: 브릿지가 없을 때(상단)는 이미지가 깨진 BMP 형태로 Claude Code에 직접 전달되어 붙여넣기에 실패합니다. 브릿지가 있을 때(하단)는 Windows 리스너가 실제 PNG를 인코딩하고, Linux 스크립트가 이를 Linux 클립보드에 넣으며, WSLg의 덮어쓰기 이후 한 번 더 재확인합니다. 사용자는 Windows Terminal을 우회하기 위해 Ctrl+V 대신 Alt+V를 누릅니다.
전체 과정: Windows에서 이미지를 캡처하고, Claude Code에서 Alt+V를 누르면 이미지가 첨부됩니다.
전체 소스 코드 — Go 리스너, bash 브릿지, 설치 스크립트 및 더 자세한 가이드 — 는 github.com/rajveerb/wsl-clip-bridge 에 있습니다.
직접 시도해보기
전제 조건: WSLg가 포함된 WSL2 (Windows 11 또는 최신 Windows 10 + WSL 업데이트), Windows 바이너리 교차 컴파일을 위한 Linux 측의 Go 1.20 이상.
git clone https://github.com/rajveerb/wsl-clip-bridge.git
cd wsl-clip-bridge
sudo apt install wl-clipboard
...
마지막 명령은 네 가지 작업을 수행합니다: Windows 측 리스너를 교차 컴파일합니다 (GOOS=windows GOARCH=amd64
), 바이너리를 ~/.local/share/wsl-clip-bridge/ 및 ~/.local/bin/에 저장하고, 새로운 WSL 셸이 시작될 때마다 브릿지 (bridge)를 실행하도록 ~/.bashrc에 스니펫 (snippet)을 추가하며, alt+v → chat:imagePaste 설정이 포함된 ~/.claude/keybindings.json을 작성합니다.
새로운 WSL 터미널을 엽니다. 브릿지가 백그라운드에서 시작됩니다. 다음을 확인하세요:
# Windows에서 아무 이미지나 복사 (Win+Shift+S)
wl-paste -l # image/png가 출력되어야 함
그 다음 Claude Code에서 Alt+V를 누릅니다. 이미지가 첨부됩니다.
리포지토리 (repo)의 README에는 각 단계(설치 스크립트 없이 실행하기, 브릿지 중지 또는 제거하기, 로그를 통한 디버깅)에 대한 더 자세한 설명이 나와 있습니다.
누구의 문제인가?
네 가지 요소가 실패에 기여합니다. 위에서 언급한 첫 번째 문제("오래된 이미지 형식")는 실제로는 두 개의 별개 이슈이므로, 표에서는 이를 분리했습니다:
| # | 실패 원인 | 누구의 문제인가 |
|---|---|---|
| 1 | WSLg가 Windows 이미지를 Linux로 보낼 때 image/bmp로만 전송함 | Microsoft (WSLg) |
| 2 | Claude Code가 실제로 수신한 BMP를 읽을 수 없음 | Claude Code — 하나의 PR로 수정 가능 |
| 3 | WSLg가 Windows로부터 Linux 클립보드를 조용히 덮어씀 | Microsoft (WSLg); #1과 #2 때문에 문제가 됨 |
| 4 | Windows Terminal이 WSL 프로그램이 인식하기 전에 Ctrl+V를 가로챔 | Microsoft (Windows Terminal); Claude Code가 이를 우회할 수 있음 |
#1은 WSLg의 클립보드 브릿지(Microsoft의 Weston 포크 내 rdpclip.c)에 하드코딩되어 있습니다. 정확히 다섯 개의 Windows→Linux 형식 매핑이 존재하며, 유일한 이미지 매핑은 CF_DIB → image/bmp입니다. 소스 코드에는 image/png 및 image/jpeg 문자열이 나타나지 않습니다. 업스트림 이슈(upstream issue) microsoft/wslg#833은 2022년 9월부터 열려 있는 상태입니다.
#2는 위 포스트가 암시하는 것보다 범위가 넓으며, 제가 처음에 생각했던 것보다 수정하기 더 쉽습니다. Claude Code는 WebAssembly 빌드에서 이미지 라이브러리로 sharp를 번들링합니다. 해당 빌드에 포함된 libvips에는 BMP 로더 (loader)가 전혀 없습니다. 단순히 BI_BITFIELDS 변형이 없는 수준이 아니라, 어떤 종류의 BMP 지원도 없습니다. Claude Code는 클립보드에서 BMP를 감지하고 sharp(bmpBuffer).png().toBuffer()를 통해 변환을 시도합니다.
, 하지만 해당 호출은 “Input buffer contains unsupported image format.”이라는 오류와 함께 중단됩니다. 사용자에게는 BMP가 지원되는 것처럼 보이지만, sharp의 WASM 빌드는 어떠한 BMP도 읽을 수 없습니다. 실제 업스트림(upstream) 해결책은 다음과 같습니다: BMP를 지원하는 sharp의 네이티브 libvips 빌드를 배포하거나, sharp를 전혀 거치지 않는 작은 BMP→PNG 변환기를 배포하거나, 감지 실패 시 ImageMagick 또는 GDI+를 호출하는 것입니다. 이 중 어느 것이라도 적용된다면 이 브릿지(bridge) 전체는 불필요해집니다.
#3은 가설이 아닙니다. 이 기기에서 브릿지의 로그를 보면, 캡처 도구(Snipping Tool)로 캡처할 때마다 re-asserted clip-1.png (was: image/bmp,)와 같이 타임스탬프가 찍힌 라인과 함께 직접적으로 나타납니다.
흥미롭게도, PowerShell을 통한 합성 Clipboard::SetImage 호출은 이를 트리거하지 않았습니다. 오직 캡처 도구 경로만이 이를 트리거했는데, 이는 WSLg가 캡처 도구가 쓰기 작업을 완료하는 방식의 특정 요소를 기반으로 작동함을 시사합니다. +0.5초 시점의 단 한 번의 재확인(re-assertion)이 이를 안정적으로 포착하며, 이전에 시도했던 세 번의 추가 재시도는 전혀 실행되지 않았습니다.
#4는 제가 놀랐던 위치에 하드코딩되어 있습니다. Windows Terminal의 Ctrl+V 핸들러는 defaults.json에 있지 않습니다 (that file은 Ctrl+Shift+V만 바인딩합니다). 이는 ConHost의 windowio.cpp에 있으며, 여기서 IsInVirtualTerminalInputMode 및 ShouldTakeOverKeyboardShortcuts와 함께 'V'에 대한 inputKeyInfo 체크가 내부 프로그램이 키 입력을 확인하기도 전에 키 입력을 삼켜버립니다. microsoft/terminal#5790에서 추적 중이며, 2020년부터
- WSL이 Linux로 PNG를 전송하기 시작함 → Windows 리스너(listener)가 더 이상 필요하지 않음.
- Claude Code가 BMP 변형을 읽는 법을 배움 → Windows 리스너(listener)가 더 이상 필요하지 않음.
- Windows Terminal이 Ctrl+V를 가로채는 것을 중단함 → 커스텀 키 바인딩(custom keybinding)이 더 이상 필요하지 않음.
이 세 가지 현상이 모두 발생하면, 임시 방편(workaround)을 제거하는 과정은 pkill 한 번,
rm 몇 번, 그리고 .bashrc와 ~/.claude/keybindings.json에서 관련 코드 조각(snippets)을 제거하는 것이 전부입니다. 시스템의 다른 어떤 부분도 이 설정에 의존하지 않습니다.
AI 자동 생성 콘텐츠
본 콘텐츠는 HN Claude Code의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기