Bash 쉘을 사용할 때 (마우스를 사용하는 대신) Shift+를 사용하여 입력한 명령을 강조 표시하고 복사해 보았습니다. LEFT그런데 C를 많이 받았어요. 나중에 나는 Shift+ UP가 만들고 A
, Shift+ DOWN가 만들고 B
, Shift+ RIGHT도 만든다는 것을 깨달았습니다 D
.
왜 이런 일이 발생합니까?
^[[A
원시 키 입력 데이터( , ^[[B
, ^[[C
및 ) 에서 나온 줄 알았는데 ^[[D
대문자일 뿐입니다( ^[[
처음에는 아무 것도 없음).
답변1
이것은 1980년대로 거슬러 올라가는 키보드 입력 프로토콜이며 쉘은아니요M. Vazquez-Abrams의 답변에서 알 수 있듯이 "터미널 드라이버"(무엇이든 상관없이)가 올바르게 처리하지 못합니다. 게다가 이는 완전히 유효한 제어 시퀀스입니다.
배경
터미널은 기능 키와 확장 키에 대한 제어 시퀀스를 발행합니다. CSI가 도입한 제어 시퀀스인 DECFNK 제어 시퀀스, CSI가 도입한 세 번째 유형의 시퀀스인 SCO 콘솔 기능 키 제어 시퀀스인 Linux 기능 키 제어 시퀀스를 실행할 수 있습니다. ; Shift SS3이 앞에 붙는 단일 문자 또는 이 예에서와 같이 다양한 항목에 대한 ECMA-48 표준 시퀀스입니다.
(SS3 및 CSI는 C1 범위의 제어 문자입니다. Single Shift 3 및 제어 시퀀스 리더입니다.)
IBM Model M 또는 이와 유사한 키보드에는 계산기 키보드와 커서 키보드라는 두 가지 특정 키보드가 있습니다. DEC VT 스타일 터미널 에뮬레이터(커널 내 터미널 에뮬레이터부터 unicode-rxvt까지 접할 수 있는 대부분의 터미널 에뮬레이터)는 두 키보드 모두 개별적으로 전환 가능한 응용 프로그램/일반 모델을 갖는 모델을 따릅니다. 전체 화면 TUI 애플리케이션, libedit 또는 GNU readline 라이브러리(또는 ZLE)(예: 셸)를 사용하는 애플리케이션 및 일부 기타 유형의 애플리케이션은 원하는 모드를 지정한 다음 버스트 번호를 읽어 터미널에서 제어 시퀀스 문자를 수신합니다. 인간은 터미널만큼 빨리 완전한 ECMA-48 제어 시퀀스를 입력할 수 없거나 터미널 에뮬레이터가 제어 시퀀스를 보낼 수 있으므로 모든 우발 상황은 Esc사용자 키 입력과 ␛ 문자로 시작하는 제어 시퀀스를 보내는 터미널 에뮬레이터 간의 차이입니다.
- 애플리케이션 모드에서 키보드의 각 화살표 키는 SS3라는 접두어가 붙은 이동된 단일 문자를 생성합니다. ECMA-35 및 ECMA-48은 단일 후속 문자에만 작동하도록 SS2 및 SS3을 정의하기 때문에 수정자는 실제로 어떤 효과도 가질 수 없습니다(XTerm이 문제를 일으키기는 하지만). 그러나 반면에 계산기와 커서 키보드는 서로 다른 SS3 이동 문자를 생성하므로 두 키보드를 서로 구별할 수 있습니다.
- 일반 모드에서는 키보드의 각 화살표 키가 다음을 생성합니다.동일한CSI에서 도입한 제어 시퀀스는 ECMA-48에서 나왔습니다.DEC VT에 의해 강화됨. 특히 커서 키는 ECMA-48 제어 시퀀스 CUU, CUD, CUR 및 CUL(CUrsor Up, CUrsor Down, CUrsor Right 및 CUrsor Left)을 보냅니다. ECMA-48 제어 시퀀스에 대한 DEC의 향상된 기능은 제어 시퀀스에 현재 수정자 상태가 포함된다는 점입니다.
따라서 어떤 수정자 키를 눌렀는지 알 수 없지만 두 개의 왼쪽 화살표 키를 구별할 수 있는 응용 프로그램 모드와 두 화살표 키의 차이는 알 수 없지만 어떤 수정자 키를 눌렀는지 알 수 있는 일반 모드 중에서 선택할 수 있습니다. 눌렀습니다.
더 자세히 설명하면 ECMA-48 제어 시퀀스의 DEC 개선 사항은 제어 시퀀스에 두 개의 매개변수가 있다는 점입니다.
- ECMA-48에 따르면 첫 번째 매개변수는 CUU, CUD, CUR 또는 CUL이 실제로 가질 수 있는 첫 번째 매개변수와 유사합니다. 발생 횟수이므로 항상 1입니다.
- 두 번째 매개변수는 흥미롭습니다. 여기에는 (생략 시 CSI에 의해 도입된 제어 시퀀스의 매개변수가 작동하는 방식과 관련된 이유로) 다양한 수정자 키에 대한 비트 플래그 세트에 1을 더한 10진수로 인코딩된 수정자 키 상태가 포함됩니다.
이것이 바로 DEC VT Terminal이 1980년대부터 해왔던 일입니다. 최근 몇 년 동안 여러 터미널 에뮬레이터가 마침내 동일한 기능을 도입했습니다. 앞서 언급한 것처럼 XTerm은 이 기능을 상당히 잘못 수행합니다.
어떻게 지내요?
문제는 GNU readline 라이브러리, libedit, ZLE 등에 있습니다.실제로 프로토콜을 올바르게 처리하지 않음. 그들에게 전적으로 책임이 있는 것은 아닙니다. 그들은 termcap과 terminfo 시스템에 의존하는데, 이는 여기서의 작업에 적합하지 않습니다. termcap과 terminfo에는 실제로 입력 제어 시퀀스에 대한 개념이 없습니다.다를 수 있습니다, 다중 모드 키보드는 말할 것도 없습니다.
:help xterm-modifier-keys
이를 위해서는 위 프로토콜( Vim 참조)에 따라 제어 시퀀스를 지정하기 위해 terminfo를 특수하게 재정의하여 프로그래밍할 수 있는 Vim이나 다음을 사용하는 NeoVIM과 같은 도구를 찾아야 합니다.Paul Evans의 libtermkey그리고 그것의CSI 드라이버. libtermkey용 CSI 드라이버는 DEC VT와 같은 터미널 에뮬레이터의 키보드 입력을 올바르게 처리하는 방법입니다. 제어 시퀀스를 올바르게 디코딩하는 실제 ECMA-48 상태 머신 파서입니다.
그러나 쉘이 수행하는 작업은 terminfo에서 화살표 키 항목을 찾는 것입니다.해당 특정 제어 시퀀스만 일치.
구체적으로:
kcub1
쉘은 terminfo 레코드에서 터미널 기능을 찾고 있습니다 . 이것은에서 온 것입니다teken
기록, 예를 들어:% tput -T teken kcub1|hexdump -C 00000000 1b 5b 44 |.[D| 00000003 %
- 이것은오직해당 특정 입력 시퀀스를 ← Left Arrow.
- ⇧ Level 2 Shift+를 누르면 ← Left Arrow터미널 에뮬레이터가 제어 시퀀스 CSI를 전송합니다
1
;
2
D
. 대신 7비트 대안을 사용하고 7비트 문자 인코딩으로 CSI를 보냅니다␛
[
1
;
2
D
.␛
[
- 쉘은 이를 terminfo의 알려진 고정 입력 시퀀스와 일치시킬 수 없으며 처리를 중단합니다. 내 Bourne Again 쉘에서는 결국 처음 두 문자를 먹고 를 누른 것처럼 작동합니다 ; 2 D. Bourne Again 쉘에서는 결국 처음 4자를 먹고 마치 를 누른 것처럼 동작합니다 D.
실패 모드는 패턴 일치를 시도하는 정확한 입력 시퀀스 세트에 따라 달라집니다. 이는 가능한 일치 항목이 없다고 결정하기 전에 삼키는 문자 수를 결정하기 때문입니다. 물론 이는 터미널의 terminfo/termcap 레코드에 실제로 포함된 내용과 쉘에 사용하도록 지시한 터미널 유형에 따라 달라집니다.
수리하다
이러한 유형의 문제에 대한 기본 해결 방법은 셸에서 키 바인딩을 사용하여 창의력을 발휘하는 것입니다. 예를 들어, s에서 Z 쉘을 사용하여 이런 종류의 작업을 수행하는 사람들을 찾는 이유는 다음과 같습니다 .zshrc
.
바인드키 "\e[1;5D" 역방향 단어 바인드키 "\e[1;5C" 앞으로 단어
불행하게도 기본이 아닌 수정 사항은 없습니다. 여기에는 쉘의 입력 처리를 다시 작성하는 작업이 포함됩니다. 이 재구성은 오래 전에 이루어졌습니다. (네오빔을 목격하세요.) 하지만 아직까지 이 문제를 해결한 사람은 아무도 없습니다.
추가 읽기
- 문자 코드 구조 및 확장 기술 . ECMA-35. 6판. 1994. ECMA 인터내셔널.
- 문자 세트 인코딩을 위한 제어 기능. ECMA-48. 5판. 1991. ECMA 인터내셔널.
- "ANSI, 짧은 ANSI 및 PC 키보드 코드". VT420 프로그래머 참조 매뉴얼. EK-VT420-RM-002. 1992년 2월. 숫자.
DECFNK
. "ANSI 제어 기능". VT510 터미널 프로그래머 정보. EK-VT510-RM. 1993년 11월. 숫자.- VT520/VT525 비디오 터미널 프로그래머 정보. EK-VT520-RM. 1994년 7월. 숫자.
- https://github.com/fish-shell/fish-shell/issues/2139#issuecomment-388706768
- https://unix.stackexchange.com/a/238932/5132
답변2
Ctrl+를 누르면 V다음 키 입력이 문자 그대로 입력됩니다. Shift+ 의 경우 ↑결과는 "^[[1;2A"입니다. 터미널 드라이버는 "^[[1;2"를 잘못된 이스케이프 시퀀스로 사용하고 "A"만 남깁니다.