Ghostty 개발 일지 003
안녕하세요! Ghostty 👻의 세 번째 공식 개발 일지에 오신 것을 환영합니다!
이전 개발 일지를 놓치셨거나 Ghostty가 무엇인지 더 자세히 알고 싶으시다면, 이 웹사이트의 Ghostty 페이지를 참고해 주세요.
커뮤니티 소식: 공개 Discord!
공개 Discord 서버를 열게 되어 정말 기쁩니다! 누구나 자유롭게 참여해 Ghostty에 대해 질문하고, 터미널 에뮬레이터나 시스템 프로그래밍, GPU 프로그래밍 등에 대해 이야기 나누실 수 있습니다. 베타 프로그램도 Discord를 통해 확대하고 있으니, 베타 참여에 관심이 있으시다면 Discord 서버에 가입해 활발히 활동해 주세요.
다음으로, 9월 5일에 Zig Showtime에서 Ghostty에 대해 발표할 예정입니다. 정확한 시간과 링크는 Zig Showtime 웹사이트나 트위터, 마스토돈 등에서 확인해 주세요. 발표는 아직 준비 중이지만, Ghostty 구현을 빠르게 훑어보면서 흥미로운 지점 몇 가지를 짚어보는 내용이 될 것입니다. 어쨌든 Zig Showtime인 만큼 Ghostty의 Zig 관련 부분에 더 집중할 예정입니다.
키보드 입력 처리는 당신을 증오합니다 (#282)1
저는 그저 멍청한 미국 표준 키보드 레이아웃을 쓰는 평범한 미국인일 뿐입니다. 미국 표준 키보드에서는 a를 누르면 “a”가 나오고, '(아포스트로피)를 누르면 “'”가 나옵니다. shift+a를 누르면 “A”가 나오죠. 정말 간단합니다. 당신은 거짓의 왕좌 위에 앉아 있는 겁니다.
문제의 첫 번째 징후는 Dvorak이나 Colemak 같은 비표준이지만 영어 중심인 키보드 레이아웃입니다. 미국 표준 물리 키보드에서 Dvorak 사용자는 s를 누르면 “o”가 나오길 기대하고, ctrl+i를 누르면 ctrl+c와 같은 동작을 기대합니다.
두 번째 징후는 유니코드 조합입니다. Mac에서 미국 표준 레이아웃으로 alt+a를 누르면 å가 입력됩니다. 최근 베타 그룹에 합류한 노르웨이 사용자 한 분이 이 부분이 특히 중요하다고 알려주셨는데, 미국 표준 레이아웃을 선호하면서도 alt 조합으로 노르웨이어 단어를 입력하기 때문이라고 합니다.
세 번째 징후는 비표준 키보드 레이아웃입니다. 데드 키 조합이 무엇인지 아시나요? 저는 몰랐습니다(기억하시겠지만 저는 그냥 멍청한 미국 표준 사용자니까요). 미국 표준 레이아웃에서는 모든 키 입력이 상태를 갖지 않는 방식에 익숙합니다. 문자를 대문자로 바꾸려면 shift+A를 동시에 누르죠. 데드 키 조합에서는 shift를 눌렀다 떼고 a를 누르면 A가 나타납니다(이건 실제 데드 키 조합이 아니라 데드 키가 어떻게 동작하는지 보여주는 예시입니다). 실제 데드 키 조합의 예로, US international 레이아웃에서는 '를 눌렀다 떼고 a를 누르면 á가 됩니다.
키보드의 키를 누르면 몇 가지 일이 일어납니다. 키보드는 물리적 스캔코드를 전송합니다. 소프트웨어 키보드 레이아웃 처리(예: QWERTY 키보드에서 Dvorak 레이아웃을 사용하는 경우)는 이 스캔코드를 다른 스캔코드로 변환합니다(“i”가 Dvorak에서는 “c”처럼 동작합니다). 그리고 ctrl, alt 같은 수식 키와 다른 키(예: 문자)의 조합은 하나 이상의 문자를 생성할 수도, 생성하지 않을 수도 있습니다(예: macOS에서 alt+p를 누르면 “π”가 나오지만, 미국 물리 키보드에서 Dvorak을 쓸 때는 alt+r에 해당합니다).
마지막으로, 모든 수식 키가 소모되는 것은 아니며, 이는 키 바인딩과 관련이 있습니다. 예를 들어 미국 레이아웃에서 ctrl+=을 바인딩하면, 노르웨이 레이아웃에서는 ctrl+shift+0에 해당합니다. shift+0이 =을 만들었지만 ctrl을 소모하지는 않았으므로 최종 입력은 ctrl+=이 된다는 것을 알아야 합니다. 그런데 사용자가 ctrl+shift+0도 함께 바인딩했다면 어느 것을 사용해야 할까요? 🤔
이 설명들은 모두 매우 두루뭉술하고 세부 사항이 빠져 있습니다. 키보드 레이아웃, 입력 처리, 터미널 키보드 “프로토콜”, OS 수준 API라는 기괴하고 끔찍한 세계에 대해서는 별도의 블로그 글로 자세히 다룰 예정이니, 이번 개발 일지에서는 세부 사항을 생략하겠습니다. 기대해 주세요!
Ghostty는 (비 미국 표준 키보드 사용자가 실제로 존재한다는 사실 때문에) 이러한 사용 사례를 반드시 처리해야 할 뿐만 아니라, 이미 macOS와 Linux에서 동작하고 Windows 지원도 계획 중인 만큼 이를 크로스 플랫폼으로 처리해야 합니다. 😰 이제 Ghostty는 그렇게 동작합니다.
시각적으로 보여드릴 수 있는 것은 데드 키 상태 처리뿐이며, 이제 마지막으로 대기 중인 데드 키가 함께 렌더링됩니다. 나머지는 제대로 동작한다고 믿어 주셔야 합니다.
위 내용에 더해, Ghostty는 이제 선택적인 명시적 물리적 키 매핑을 지원합니다. 키 바인딩을 ctrl+physical:0처럼 지정하면(physical: 접두사에 주목하세요), 물리적인 0 키를 눌렀을 때만 해당 바인딩이 동작합니다. 일부 키보드 레이아웃에서는 이 바인딩을 아예 사용할 수 없게 될 수도 있습니다. 기본적으로 키 바인딩은 논리적(변환된) 키를 기준으로 동작합니다.
Kitty 키보드 프로토콜 외 (#292, #295)
키보드 입력에 대한 이야기가 지겹다면 이 섹션은 건너뛰셔도 됩니다.
키보드 키를 문자 입력으로 매핑하는 것을 넘어, 키보드 이벤트는 터미널에서 실행 중인 프로그램이 어떤 키를 눌렀는지 알 수 있도록 이스케이프 시퀀스로도 매핑되어야 합니다.
원래 터미널 프로토콜은 키보드 키로 생성된 문자를 그대로 전송했습니다. “a”를 입력하면 “a”가, “A”(shift+A)를 입력하면 “A”가 전송되는 식입니다. 이 방식에는 많은 한계가 있습니다. 예를 들어 터미널 프로그램은 ctrl-i와 ctrl-shift-i를 구분할 수 없었는데, 두 입력이 동일한 데이터를 생성했기 때문입니다.
이러한 단점을 해결하기 위해 여러 추가 키보드 프로토콜이 개발되었습니다. xterm은 modified keys 시퀀스를, Paul Evans는 fixterms 프로토콜을, Kovid Goyal(Kitty 제작자)은 Kitty Keyboard Protocol을 개발했습니다. 이들 프로토콜의 핵심은 키를 눌렀을 때 터미널이 실행 중인 프로그램에 무엇을 전송할지를 정의한다는 점입니다.
이건 가상의 문제가 아닙니다. 이 프로토콜들은 tmux, neovim 등 주요 프로그램에서 구현되어 있어, 그렇지 않았을 때보다 수백 개 더 많은 키 바인딩을 사용할 수 있게 해줍니다.
Ghostty는 이제 이 모든 것을 구현했습니다.
제가 아는 한, 이 모든 프로토콜을 구현한 터미널은 극소수에 불과합니다. xterm modified keys와 Kitty를 모두 구현한 곳은 iTerm, Foot, 그리고 아마 WezTerm 정도라고 생각합니다. Kitty 프로토콜 자체를 구현한 곳도 그들과 Kitty뿐인 것으로 알고 있습니다. 대부분의 터미널(Terminal.app, Windows Terminal, Alacritty, Warp)은 키보드 프로토콜을 전혀 구현하지 않습니다.2
Kitty 키보드 프로토콜이 동작하는 영상입니다:
그리고 xterm modified keys 프로토콜이 동작하는 영상입니다:
데스크톱 Linux의 해 (GTK)
지난 베타 사용자 모집으로 상시 Linux 사용자 수가 기존 2~3명에서 5~6명 정도로 늘었고, 그 덕분에 Linux 경험이 크게 개선되었습니다.
첫째, GTK 단일 인스턴스 모드(#247)가 이제 활성화되어 지원됩니다. GTK에서 Ghostty는 이제 단일 프로세스로 실행됩니다. Ghostty를 두 번째로 실행하면 기존 Ghostty 프로세스에 새 창이 열립니다. 이는 표준 그래픽 데스크톱 환경과도 잘 어우러지며, 첫 실행 이후 Ghostty 실행 속도를 엄청나게 빠르게 만들어 줍니다.
다음으로, Ghostty는 이제 주(primary, selection) 클립보드 지원(#266)을 제공합니다. Linux 데스크톱에는 여러 클립보드가 있습니다. “primary”(또는 “selection”) 클립보드는 텍스트를 선택하면 자동으로 복사되고, 보통 가운데 마우스 버튼으로 붙여넣기를 하는 클립보드입니다. 이 클립보드는 ctrl+shift+c와 ctrl+shift+v로 오가는 클립보드와는 별개의 클립보드이므로, 클립보드에 여러 항목을 동시에 유지할 수 있습니다. 이 기능은 때로 논란이 되기도 하니, 걱정 마세요. copy-on-select 설정으로 비활성화할 수 있습니다. 아래 영상에서 동작을 확인하실 수 있습니다. 키보드 바인딩을 전혀 누르지 않았다는 점에 주목해 주세요. selection 클립보드만 사용한 것입니다.
이제 Linux에서도 자동 셸 통합(#245)을 지원합니다. Devlog 001에서 셸 통합에 대해 이야기한 바 있습니다. 이전에는 Linux 사용자가 Ghostty의 share 디렉터리를 가리키는 환경 변수를 설정해야 했습니다. 이제 Linux 애플리케이션은 ghostty 실행 파일을 기준으로 상위 디렉터리를 탐색하며 올바른 폴더 구조를 갖춘 share 디렉터리를 찾습니다. Ghostty를 표준 FHS 디렉터리 레이아웃(Ghostty가 패키지로 제공하는 표준 레이아웃)으로 설치하면, Ghostty가 자동으로 셸을 찾아 설정합니다.
그 외에도 Ghostty 앱 아이콘이 제대로 표시되고(#251), GTK 애플리케이션이 미국 외 키보드 레이아웃을 처리하며(#271), GTK 애플리케이션이 반투명 창 배경을 지원(#264)하는 등 많은 개선이 있었습니다.
저는 Ghostty가 GTK 기반 Linux 터미널 중 최고 수준이 되기를 바랍니다. 저는 GTK를 상시로 사용하지 않기 때문에 훌륭한 경험을 만들기 위해 테스터 분들의 피드백에 크게 의존하고 있습니다. Ghostty가 GTK에서도 정말 훌륭하게 동작하고 있다는 소식을 전하게 되어 매우 기쁩니다! GTK 애플리케이션은 아직 macOS 경험에는 뒤처져 있지만, 동등한 수준으로 끌어올릴 수 있기를 기대하고 있습니다!
맺음말
최근 베타 테스터 분들께서는 정말 놀라운 활약을 해주셨습니다. 드러난 키보드 레이아웃과 매핑 문제를 샅샅이 파헤치고 모두 수정하도록 이끌어 주신 @hovsater 님께 감사드립니다. @cryptocode 님께서는 와이드 문자, 다중 코드포인트 그래핌(grapheme)과 선택 및 소프트 래핑과의 상호작용과 관련된 수많은 엣지 케이스 버그를 찾아주셨습니다. 그리고 Linux 개선에 기여해 주신 여러 새로운 테스터 분들께도 감사드립니다. 감사합니다!
최신 소식을 받아보고 싶으시다면 트위터나 마스토돈에서 저를 팔로우해 주세요(링크는 하단 푸터에 있습니다). 이 블로그에는 RSS 피드도 있습니다.
Boo. 👻
각주
이 글은 훌륭한 블로그 글인 Text Rendering Hates You를 참고한 것으로, 일독을 강력히 추천합니다. ↩
이 터미널 에뮬레이터 저자 분들 모두를 깊이 존경하며, 이 내용이 비난으로 비치지 않기를 바랍니다. 각 터미널이 어떤 기능을 지원하고 지원하지 않는지 사실대로 전달하려는 의도일 뿐입니다. 제가 틀렸다면 알려주시면 바로 수정하겠습니다. ↩
글을 무작위로 읽기