Delete와 Backspace 키가 제대로 동작하도록 하는 것이 그리 간단한
문제는 아니다. 특히 콘솔, X
, bash
, emacs
, 원격 로그인 등
여러가지가 혼합된 환경에서는 더더욱 그러하다. 아마도 사용자가 원하는
바를 정확히 수행하도록 관계된 프로그램 모두에게 전달하려면 여러개의
환경설정화일을 편집해야 될지도 모른다. 한편으로는 키가 발생시키는
코드가 무엇인지도 (그리고 kermit
이나 emacs
등에서
이러한 코드가 어떤 규칙으로 다시 매핑되는지도) 문제가 되고,
다른 한편으로는 각 코드에 연결된 기능이 무엇인지도 문제가 된다.
사람들이 종종 `백스페이스 키가 작동하지 않는다.'고 불평하는데, 이것은 마치 이 키에 `이전의 문자를 지우는' 내장된 기능이 있는 것처럼 말하는 것이다. 하지만 불행히도 이 키가 하는 일이라곤 코드 하나를 발생하는 것뿐이며, 커널 tty 드라이버와 모든 어플리케이션 프로그램이 백스페이스 키가 실제로 `이전 문자를 지우는' 동작을 하도록 설정되어 있기를 고대하는 것이 전부이다.
모든 유닉스 프로그램은 `요리된' 모드에서 커널 tty 드라이버를 통해
tty 입력을 받고, 단순한 stty
명령이 삭제 문자를 결정한다.
하지만 bash
나 emacs
, X
같은 프로그램은 독자적으로
입력을 다루며 하나씩 올바로 동작하는지 확인해야 한다.
% stty erase ^?
글자가 지워지긴 하지만 이상한 방법으로 지워진다면 사용자의 tty 설정에
뭔가 잘못된 것이 있는 것이다. echoprt
가 설정되어 있다면 지워진
문자는 \
와 /
로 둘러싸여진다. echoe
가 설정되어
있지 않으면 삭제 문자가 화면에 찍힐 것이다. (#과 같이 화면에
표시되는 문자인 경우라면 당연하다고 생각할 것이다.)
보통의 경우는 stty echoe -echoprt
상태를 원한다. stty sane
이라고
하면 이런 상태가 되며, 그 이외에도 몇가지를 더 설정한다. stty -a
라고
명령을 내리면 현재 설정 상태를 화면에 보여준다. 사용자가 올바른 getty
를
사용하면 디폴트로 적절한 상태로 되어 있다.
bash
나 emacs
등등 많은 프로그램이 독자적인 키바인딩을 가지고 있음에
유의하라. (~/.inputrc
, ~/.emacs
등에 정의되어 있다.)
이런 프로그램들은 삭제 문자 설정등에는 영향을 받지 않는다.
표준 유닉스 tty 드라이버는 (화살표 같은) 키를 커서의 현재 위치를 이동하는
뜻으로 인식하지 않는다. 따라서 `현재 문자 삭제' 명령도 없다. 하지만
콘솔상의 bash
에서 아래와 같이
set editing-mode emacs
"\e[3~":delete-char
를 ~/.inputrc
에 넣어주면 Delete 키를 인식하도록 할 수 있다.
옛날에는 콘솔 드라이버가 DEL (\177
)를 받으면 BS Space BS
(\010\040\010
)를 수행하도록 해두었다. 하지만 지금은
DEL은 무시된다. (이것이 당연한 것이 드라이버는 vt100을 흉내내기 때문이다.)
DEL을 출력하지 않는 최신의 getty를 구해서 사용하라.
첫번째 로그인 시도는 getty
와 이야기하는 것이지만, 두번째 시도는 login
과
이야기하는 것이다. 서로 다른 프로그램이다.
콘솔에서, 정확히 말하자면 raw 모드가 아닌 경우에는
% loadkeys mykeys.map
이라고 하면 된다. X 환경에서는
% xmodmap mykeys.xmap
를 사용하면 된다. (XFree86-2.1 이래로) X는 처음 시작시에 X keymap을
초기화할 때, 리눅스 keymap 설정을 읽는다는 사실에 유의하라. 비록 두
시스템이 100% 호환되지는 않지만 이러한 사실은 많은 경우에
xmodmap
이 보다 영향력이 있다는 것을 의미하기 때문이다.
예를 들어, 사용자가 백스페이스 키에 BackSpace (^H, 8진수 010)을
보내도록 하려 하고, 회색 Delete 키로는 DEL (8진수로 0177)을 보내려
한다면, /etc/rc.local
(또는 사용자만의 부팅 설정화일에)
/usr/bin/loadkeys << EOF
keycode 14 = BackSpace
keycode 111 = Delete
EOF
라고 첨가하면 된다. 이 설정은 다른 설정을 바꾸지 않았다면 두개의
키 설정만 바꾼다는 사실에 유의할 필요가 있다. (다른 키맵에서도
키 설정을 바꾸고 싶다면, 어느 키맵을 바꿀지 키맵 라인을 지정해
주어야 한다.) 리눅스 커널은 디폴트로 Ctrl-Backspace 키가 BackSpace를
발생하도록 되어 있다. 이것은 때때로 DEL 코드만 생기는 위급 상황에서
빠져나가는데 유용하다.
왼쪽 Alt 키는 종종 메타키라고 부른다. 디폴트로 왼쪽 Alt-X 키조합은
MetaX로 설정되어 있다. 그렇다면 MetaX는 어떤 키 시퀀스인가?
그것은 (각각의 tty에서) 메타 플래그에 의해서 결정된다. 이것은
setmetamode
명령으로 설정할 수 있다. ESC X를 치는 것과
0200과 OR연산을 한 X를 치는 두가지 방법이 존재한다.
(i) 왜냐하면 VT100에는 Delete 키가 Enter 키 위에 있었기 때문이다.
(ii) 또한 리누스가 그렇게 정했기 때문이다.
% xmodmap -e "keysym BackSpace = Delete" -e "keysym Delete = BackSpace"
백스페이스 키가 BackSpace를 발생하도록 하려면
% xmodmap -e "keycode 22 = BackSpace"
Delete 키가 Delete를 발생하도록 하려면
% xmodmap -e "keycode 107 = Delete"
(하지만 보통 이미 디폴트로 되어 있을 것이다.)
사용자의 .emacs
화일에 다음 라인을 추가하면 된다.
(global-set-key "\?" 'help-command)
(global-set-key "\C-h" 'delete-backward-char)
물론 이런 방식으로 하면 다른 키에도 명령을 연결시킬 수 있다.
키 재정의 방식에는 여러가지 major 및 minor 방식이 있음을 유의할
필요가 있다. 예를 들어, incremental search 모드에서는 다음과
같은 코드가 있는 것을 발견할 수 있다.
(define-key map "\177" 'isearch-delete-char)
(define-key map "\C-h" 'isearch-mode-help)
이것을 보면 위의 두 명령을 global 키 설정으로 사용하는 것은
별로 좋은 방법이 아니라는 것을 알 수 있다. 많은 프로그램에서
^H = help와 DEL = delete라는 가정하에 키를 사용한다. 물론
반드시 백스페이스 키가 DEL을 발생하도록 키를 설정해야만 하는
것은 아니다. 그러나 키 설정이 이렇게 되어 있지 않으면
emacs에서 사용할 수 있는 가장 낮은 레벨에서는
이 키들을 재설정하는 것이 가장 쉬운 방법이다.
사용자의 .emacs
화일에 다음 라인을 추가하면 된다.
(setq keyboard-translate-table (make-string 128 0))
(let ((i 0))
(while (< i 128)
(aset keyboard-translate-table i i)
(setq i (1+ i))))
(aset keyboard-translate-table ?\b ?\^?)
(aset keyboard-translate-table ?\^? ?\b)
emacs의 최신 버전에서는 keyboard-translate
함수를 제공하기
때문에 간단하게 아래와 같이 해도 된다.
(keyboard-translate ?\C-h ?\C-?)
(keyboard-translate ?\C-? ?\C-h)
X 환경에서는 (콘솔에서 이 키가 어떤 코드를 만들던 간에) emacs가 Ctrl-h와
백스페이스 키를 구별할 수 있다. 그리고 emacs는 디폴트로 백스페이스 키를
DEL로 간주할 것이다. (물론 ^H에 연결된 도움말 기능이 아니라
문자를 지우는 일을 할 것이다.) 백스페이스와 Delete를 구분하여 사용하려면
다음과 같이 하면 된다.
(global-unset-key [backspace] )
(global-set-key [backspace] 'delete-backward-char)
(global-unset-key [delete] )
(global-set-key [delete] 'delete-char)
.kermrc
화일에 다음 라인을 추가하면 된다.
set key \127 \8
set key \8 \127
보통 xterm은 이것을 호출한 프로그램의 tty 모드를 상속받는다.
xdm
환경에서는 구형 유닉스 버전 6에서와 같이
디폴트로 설정된 지우기 및 죽이기 문자는 #
와 @
이다.
이 설정이 마음에 안들면 아래 내용을
/usr/lib/X11/app-defaults/XTerm
나
$HOME/.Xresources
에 넣으면 된다.
XTerm*ttymodes: erase ^? kill ^U intr ^C quit ^\ eof ^D \
susp ^Z start ^Q stop ^S eol ^@
물론 $HOME/.xinitrc
나 $HOME/.xsession
에
xrdb $HOME/.Xresources
라는 구절이 있어야 작동한다.
아래 내용을 $HOME/.Xresources
에 넣으면
해결될 것이다.
*XmText.translations: #override\n\
<Key>osfDelete: delete-previous-character()
*XmTextField.translations: #override\n\
<Key>osfDelete: delete-previous-character()
하지만 넷스케이프 FAQ에는 다음과 같은 내용이 있다.
왜 텍스트 필드에서 백스페이스 키가 말을 듣지 않는가? 디폴트로 리눅스와 XFree86에는 백스페이스와 Delete 키가 잘못 설정되어 있다. (넷스케이프 네비게이터를 포함한) 모든 모티프 프로그램에서 똑같이 잘못 작동될 것이다. 모티프 스펙에 보면 백스페이스는 이전 문자를 지우도록 되어 있고 Delete는 다음 문자를 지우도록 되어 있다. 리눅스와 XFree86은 백스페이스와 Delete 키가 모두 Delete를 발생하도록 설정되어 있다. 사용자는 xmodmap, xkeycaps, loadkeys중 하나를 사용하여 문제의 키가 Delete 대신에 BackSpace keysym을 발생하도록 할 수 있다. 다른 방법으로는 .motifbind 화일을 만들어 해결할 수 있다. man 페이지 VirtualBindings(3)을 참조하라. 주의: 이 문제를 해결하기위해 *XmText.translations나 *XmTextField.translations 리소스 화일을 사용하지 않는 것이 좋다. 아마도 이것을 건드리면 넷스케이프 네비게이터의 다른 텍스트 필드의 키 연결이 모두 망가질 것이다.
Ted Kandell (ted@tcg.net
)의 해결책은 다음과 같다.
사용자의 .profile 화일에 다음의 내용을 넣자.
stty erase ^H
bash
사용자라면 .inputrc
에 다음 라인을 추가한다.
"\C-?": delete-char
"\C-h": backward-delete-char
.xinitrc 화일에는 아래의 내용을 추가한다.
xmodmap <<-EOF
keycode 22 = BackSpace osfBackSpace
keycode 107 = Delete
EOF
# 윈도우 관리자를 실행시킨다.
#(fvwm) 2>&1 | tee /dev/tty /dev/console
stty sane
stty erase ^H
loadmap <<-EOF
keycode 14 = BackSpace
keycode 111 = Delete
EOF
이렇게 하면 리눅스/XFree86 기반의 PC 101 또는 102 키보드에서는 반드시 잘 동작할 것이다.
넷스케이프와 같은 모티프 프로그램이 잘 동작하도록 하는데 중요한 부분은 osfBackSpace를 BackSpace와 함께 키코드 22에 넣는 점이다.
= 기호 양쪽에는 반드시 공백이 있어야 한다는 점도 유의할 것.
사용자들이 백스페이스 문제에 부딪히면, 대개 터미널이 사용하는 termcap (또는 terminfo) 항목을 뒤적거린다. 물론 거기에 보면 kb (또는 kbs)라는 항목이 있고, 백스페이스 키가 만드는 코드에 대한 설명이 나온다. 하지만 그다지 많은 프로그램이 이것을 사용하는 것은 아니다. 따라서 만일 특정한 프로그램에서만 문제가 발생한다면 아마도 원인은 다른곳에 있을 가능성이 높다. 물론 termcap (terminfo) 항목을 고쳐서 문제를 해결하는 것도 좋은 생각이다. 뒤에 "TERM 변수" 부분을 참조하면 도움이 될 것이다.