PuTTY 한글/영문 글꼴 분리하기
오늘도 삽질 하나. 날씨도 너무 덥고 텍스트큐브 코딩도 안 되고(?) 해서 PuTTY를 뜯었다.;; 그동안 오랜 숙원사업(?)이었던 한글/영문 글꼴의 완전한 분리에 성공했다.
스크린샷. 전체 사이즈 보려면 여기 클릭.
PuTTY 소스코드가 생각보다 난잡(...)해서 찾는 데 좀 시간이 걸렸지만 더위는 이열치열(?)이라는 생각으로 삽질을 해주니 마침내 어디를 고쳐야 하는지 찾을 수 있었다.
방법은 간단히 다음과 같이 window.c를 패치해주고 컴파일하면 끝.;; 보다시피 급조한 거라 글꼴 설정은 소스코드에 하드코딩되어 있다; 기준 소스는 0.60 최신 버전. 아참, 생성만 하고 소멸시키지 않는 것처럼 보이나 다른 부분에 보면 FONT_MAXNO까지 배열을 순회하며 DeleteObject를 호출해주는 부분이 있으므로 걱정 안 해도 된다.
//...
#define FONT_OEMBOLDUND 0x23
#define FONT_NONLATIN 0x30
#define FONT_MAXNO 0x30 //0x2F
//...
static void init_fonts(int pick_width, int pick_height)
{
//...
f(FONT_NORMAL, cfg.font.charset, fw_dontcare, FALSE);
fonts[FONT_NONLATIN] = CreateFont (font_height, font_width, 0, 0, fw_dontcare, FALSE, FALSE, FALSE, \
cfg.font.charset, OUT_DEFAULT_PRECIS, \
CLIP_DEFAULT_PRECIS, FONT_QUALITY(cfg.font_quality), \
FIXED_PITCH | FF_DONTCARE, "Dotum");
SelectObject(hdc, fonts[FONT_NORMAL]);
GetTextMetrics(hdc, &tm);
//...
}
void do_text_internal(Context ctx, int x, int y, wchar_t *text, int len,
unsigned long attr, int lattr)
{
//...
} else {
/* And 'normal' unicode characters */
static WCHAR *wbuf = NULL;
static int wlen = 0;
int i;
if (wlen < len) {
sfree(wbuf);
wlen = len;
wbuf = snewn(wlen, WCHAR);
}
for (i = 0; i < len; i++)
wbuf[i] = text[i];
/* EXTRA PATCH for non-latin font replacing... */
SelectObject(hdc, fonts[FONT_NONLATIN]);
text_adjust = 1;
/* print Glyphs as they are, without Windows' Shaping*/
general_textout(hdc, x, y - font_height * (lattr == LATTR_BOT) + text_adjust,
&line_box, wbuf, len, IpDx, !(attr & TATTR_COMBINING));
//...
}
유니코드 렌더링 부분을 바꾼 것이기 때문에 CP949나 윈도98과 같은 환경에서는 어떻게 나오는지 모르겠지만 일단 나는 유니코드 터미널만 쓰고 있으므로 패스; =3
내가 VS2005로 컴파일한 바이너리는 KLDP를 참조하기 바란다.
추가: 앞으로 원활한 개발을 위해 공개 subversion 저장소를 생성하였다. ViewVC를 통해 살펴보려면 이 링크를 참조하기 바란다. SVN 프로토콜로 접근하려면 경로에서 view를 빼면 된다.
Supreme Commander 한글입력기 구현하기
드디어 슈프림 커맨더(Supreme Commander)의 한글입력기를 구현했다. 이 게임은 오리지날 버전(영어권에서는 Vanilla라고 부른다)은 한글화 번역이 이루어져 출시가 되었으나 번역의 질이 굉장히 낮았고 특히 한글 채팅이 전혀 지원되지 않아 많은 유저들의 불만을 샀다. 그나마 많이 팔리지도 않아 확장팩인 Forged Alliance의 경우 아예 국내 출시조차 이루어지지 않았고, 결국 나(...)를 비롯한 매니아들은 해외 직수입 게임 전문점이나 지인을 통한 구매대행 등을 이용할 수밖에 없는 상황이다.
아무튼 그동안 한국 유저들의 오랜 갈망이었던 한글 채팅을 User Interface mod 형식으로 구현하는 데 성공했다. 슈컴이 워낙에 modding 확장성이 좋다고 알려져 있기는 했지만, 실제로 이번 기회를 통해 만져보니 정말 잘 만들었음을 알 수 있었다. 게임의 핵심적인 구동 엔진을 제외하고 나머지 다른 부분들—유닛의 움직임, 게임 시나리오, UI, 인공지능 등등—상당히 많은 부분이 lua 스크립트 언어를 통해 만들어져 있다. 게임 데이터들은 *.scd라는 파일에 들어있는데 이것은 실상 그냥 zip 압축파일이라서 누구든지 풀어볼 수 있도록 하고 있다. (별도의 복잡한 암호화 이런 거 없다.)
실제로 이번에 한글입력기 mod를 제작해보니 게임 내부가 어떤 로직으로 돌아가는지 거의 다 들여볼 수 있을 정도로 개방적이었다. 그만큼 게임 품질에 자신감이 있다는 뜻일 수도 있겠다.
요즘 게임 내부 스크립트 엔진용으로 많이 쓰이는 lua는 그러나 약간 실망이었다. 함수형 언어의 특징을 강하게 가지고 있는 lua는 어찌보면 ruby와도 상당히 비슷하다. 하지만 실제로는 매우 단순화된 언어로, 자료 구조라고는 오직 dictionary와 비슷한 table밖에 지원하지 않고, 비트연산자 등 다른 언어에는 당연히 있을 만한 기능들이 없는 경우가 꽤 있다. 유니코드 인코딩도 지원하지 않아 결국 utf-8 인코딩 루틴까지 직접 다 짜야했다. 대신 그 table 자료구조가 굉장히 강력하여(metatable이라는 개념을 제공한다) 함수형 언어의 특징과 결합해 이것만으로 class라는 개념을 언어에 도입하는 것이 가능할 정도이다.
오토마타 루틴은 예전에 CS322 과목 프로젝트로 Python으로 구현한 한글입력기(정확히는, 영타로 입력된 문자열을 한타로 변환하여 한글 문자열로 만들어주는..)를 lua로 그대로 포팅하였다. 둘의 문법이 비슷하여 큰 어려움은 없었고, 다만 lua에서는 table의 index가 0이 아니라 1부터 시작한다는 점 때문에 조금 헷갈리는 정도였다.
걸림돌이 되었던 부분은 오토마타의 결과물로 나온 unicode 숫자 배열을 실제의 utf-8 문자열로 변환하는 것이었는데, 이 과정에서 나머지 연산과 shift 연산이 필요하여 결국 수동으로 구현해야 했다. 특히 lua의 숫자는 무조건 double이고 라이브러리에서 필요시 unsigned long으로 바꾸는 식이기 때문에 나눗셈을 수행할 때 항상 math.floor를 해줘야 한다.
local function modulo(a, b)
return a - math.floor(a/b) * b
end
와 같이 구현할 수 있고, right shift 연산의 경우 간단하게 2의 제곱승으로 나눠주면 된다.
혹시 필요한 분들을 위해, unicode 숫자가 순서대로 담긴 table을 입력으로 받아 utf-8로 인코딩된 문자열로 내놓는 함수를 소개한다. (테스트는 엄밀하게 해보지 않았지만 적어도 한글은 잘 나온다. =3=3)
function conv2utf8(unicode_list)
local result = ''
local w,x,y,z = 0,0,0,0
local function modulo(a, b)
return a - math.floor(a/b) * b
end
for i,v in ipairs(unicode_list) do
if v ~= 0 and v ~= nil then
if v <= 0x7F then -- same as ASCII
result = result .. string.char(v)
elseif v >= 0x80 and v <= 0x7FF then -- 2 bytes
--[[
y = (v & 0x0007C0) >> 6
z = v & 0x00003F
]]--
y = math.floor(modulo(v, 0x000800) / 64)
z = modulo(v, 0x000040)
result = result .. string.char(0xC0 + y, 0x80 + z)
elseif (v >= 0x800 and v <= 0xD7FF) or (v >= 0xE000 and v <= 0xFFFF) then -- 3 bytes
--[[
x = (v & 0x00F000) >> 12
y = (v & 0x000FC0) >> 6
z = v & 0x00003F
]]--
x = math.floor(modulo(v, 0x010000) / 4096)
y = math.floor(modulo(v, 0x001000) / 64)
z = modulo(v, 0x000040)
result = result .. string.char(0xE0 + x, 0x80 + y, 0x80 + z)
elseif (v >= 0x10000 and v <= 0x10FFFF) then -- 4 bytes
--[[
w = (v & 0x1C0000) >> 18
x = (v & 0x03F000) >> 12
y = (v & 0x000FC0) >> 6
z = v & 0x00003F
]]--
w = math.floor(modulo(v, 0x200000) / 262144)
x = math.floor(modulo(v, 0x040000) / 4096)
y = math.floor(modulo(v, 0x001000) / 64)
z = modulo(v, 0x000040)
result = result .. string.char(0xF0 + w, 0x80 + x, 0x80 + y, 0x80 + z)
end
end
end
return result
end
MacOSX Leopard에서 MacVim 사용시 언어 자동전환 문제
맥에서 기본으로 제공하는 콘솔용 vim이 있긴 하지만 윈도우에서도 gvim을 쓰고 있었고 Finder와 연동하기도 불편하다는 문제가 있어 대안을 찾던 중 MacVim이라는 훌륭한 포팅이 있음을 발견했다. git를 이용해 소스를 내려받아 직접 컴파일해야 되지만 그냥 써있는대로 따라하면 되기에 큰 어려움은 없었다. (단, macports와 xcode가 설치되어 있는 것이 편하다.)
문제는 MacVim을 실행 후 입력모드에 들어갈 때마다 IM 언어가 한글로 자동으로 바뀌는데 그 상태에서 키보드를 치면 영문이 입력되고 실제 한글을 입력하려면 Cmd+Space를 수 차례 눌러주어야 했다는 점이다. 뭐 소스코드도 있겠다 한 번 문제를 들여다보았더니 원인은 GetScriptManagerVariable이라는 MacOSX의 Carbon API에 문제가 있는 것으로 판명되었다.
즉, 원래 제작자의 구현이 제대로 동작한다면, 명령 모드에서는 영문 입력 상태가 유지되고 입력 모드에 들어가고 나올 때 입력모드에서 사용하던 입력 상태를 기억하여 자동으로 전환되어야 한다. (윈도우용 gvim 7.1에서는 잘 됨을 확인했다.) 나름대로 이것을 그대로 구현하기 위해 IM 상태를 저장하는 함수를 별도로 만들어보는 등 삽질을 해봤지만 OSX의 호환성 문제인지 잘 되지 않았다. 무엇보다 IM 상태를 얻거나 변경하는 방법만 3가지(Script manager로 바꾸는 방법, Class/Layout component로 바꾸는 방법, 최신 API인 TIS*+CoreFoundation 계열)나 존재해서 어떤 것을 써야 제대로 동작하는지 알 수도 없었고 각 API가 크게 다른 모습을 가지고 있어 어떤 시맨틱을 써야 좋을지도 헷갈렸다. (윈도API는 그러고보면 버전에 따라 심하게 바뀌는 일이 별로 없으니 좋은 거다.)
그래서 결론은, MacVim 소스에서 src/MacVim/gui_macvim.m 파일의 im_set_active 함수에서 호출되는 KeyScript API에 smKeyRoman을 항상 넘겨주게 하면 입력모드 들어갈 때 무조건 영문 상태로 들어가게 된다. (보통 명령 모드는 항상 영문으로 쓰니 겉으로 보기에 바뀌는 것으로 보이진 않을 것이다) 대신 한글 상태에서 입력모드를 쓰다가 Esc를 눌렀을 때 다시 입력모드로 들어가면 영문으로 되어 있으므로 한영전환을 매번 해줘야 한다는 불편이 생기지만, 한글 입력 상태로 표시되면서 영문으로 입력되는 등의 모호한 상태는 없어진다.
PNG Color Profile Removal Tool
이거 상당히 오래된 주제이긴 한데, 막상 필요할 때 대충 찾아서 쓰려고 해보니 윈도 전용으로 나온 것이 많아 cross platform으로 간단히 쓸 수 있도록 python 스크립트로 짰다.
주요 기능은 PNG 파일 포맷에서 색상 calibration 정보를 나타내는 필드들을 삭제해버림으로써 IE 및 Safari에서 gamma 값을 해석하지 않아 발생하는 색상 불일치 문제를 해결하는 것이다. 사용법은 python pngtool.py --help해보면 알 수 있다.

이올린에 북마크하기
이올린에 추천하기



