TAB과 다른 방식으로 Ci를 바인딩하는 방법은 무엇입니까?


16

기본적으로 Xcode가 이미 근육 기억을 구축했기 때문에 Control-i수행 하고 싶습니다 indent-region.

나는 그것을 실현 Control-itab아스키 및 16 진수 의미에서 구별 할 수 있지만 키 코드의 의미에 있습니다.

나는 명백한 것을 시도했다 :

(global-unset-key (kbd "C-i"))
(global-set-key (kbd "C-i") 'indent-region)

아무 소용이 없습니다-를 누르면 현재 컨텍스트에서 키가 Control-i수행하는 모든 작업을 계속 수행합니다 tab. Emacs가 탭 버튼을 다르게 취급하도록 도울 수있는 방법이 Control-i있습니까?

업데이트 : 지역을 선택할 때 tab/ Control-i프레스가 하는 일을 다시 매핑 할 수 있으면 동등한 결과가 달성 될 것 같습니다 .


1
이것은 GUI 프레임 또는 터미널 프레임에서 발생합니까? 터미널에 대해 재정의 할 수 있는지 모르겠습니다.
dgtized

좋은 Q, 일반적으로 GUI 프레임,하지만 난 :) 물론 자식 공유 emacs.d로 (터미널 때로는에있는 서버 및 사용 이맥스로 원격 수행
마크 Aufflick

답변:


15

나는 이것이 터미널에서 달성 될 수 있다고 생각하지 않지만 GUI 모드에서는 이것을 시도 할 수 있습니다 :

(define-key input-decode-map [?\C-i] [C-i])
(global-set-key (kbd "<C-i>") 'indent-region)

나는 똑같은 일을 C-m하여 구별 할 수 있습니다.RET

편집하다:

GUI 또는 TTY 모드에 관계없이 다음이 작동합니다.

;; Unbind <C-i> from the TAB key and bind it to indent-region.
;; Since TAB and <C-i> cannot be differentiated in TTY emacs,
;; the workaround is to conditionally bind TAB to indent-region
;; when there is an active region selected.
(if (window-system)
  ; IF we are not in a TTY, unbind C-i from TAB
    (progn
      (define-key input-decode-map [?\C-i] [C-i])
      ; ... and remap it to indent-region
      (global-set-key (kbd "<C-i>") 'indent-region))
  ; ELSE IF we are in a TTY, create a replacement for TAB
  (defun my/tab-replacement (&optional START END)
    (interactive "r")
    (if (use-region-p)
      ; IF active region, use indent-region
        (indent-region START END)
      ; ELSE IF no active region, use default tab command
      (indent-for-tab-command)))
  ; Bind our quick-and-dirty TAB replacement to the TAB key
  (global-set-key (kbd "TAB") 'my/tab-replacement))

예쁘지는 않지만 일을하는 것처럼 보입니다. 필요에 따라이 코드를 수정하거나 수정 한 것을 환영합니다.


1
완벽하게 작동합니다! ++ emacs stackexchange를 다시 구매할 것입니다 :)
Mark Aufflick

방금 생각한 사소한 문제는 이제 창 시스템으로 시작한 Emacs에 대해 터미널 emacsclient를 가져올 수 있다는 것입니다. 지연이 보이지 않으면 모든 경우에 탭 교체 기능을 사용합니다.
Mark Aufflick

1
나는 <C-i>and 를 추가하고 and [C-i]같은 임의의 식별자 일 수 <foobar>있으며 [foobar]여전히 작동 할 것입니다. 그냥 호출하지 않습니다 tab또는backspace
xdavidliu

나는에 당신의 대답에 편집 된 코드 조각을 추가 한 .emacs파일 만 모두 TAB하고 C-i있다 재배치 :-( @nispio
alper

@ alper, 아마도 이것은 로드 될 때 (window-system)반환 된 것을 의미합니다 . 그래픽이 아닌 Emacs 인스턴스를 실행 중이거나 Emacs 데몬을 실행 중일 수 있습니다. nil.emacs
nispio

13

GUI 프레임

GUI 프레임 (X11, Windows, OSX 등)에서 Emacs는 Tab키를 tab기능 키로 읽습니다 . 그러나 Tab터미널 의 키는 전통적으로 ^I( Control + I) 문자를 전송 하기 때문에 Emacs는 tab기능 키를 Control + I 문자 (문자 9)로 변환 TAB합니다. 이 번역은을 통해 수행됩니다 function-key-map.

다른 기능 키에서도 비슷한 변환이 수행됩니다. ( BackspaceDelete있는 가시의 경우 내가 여기에 구체적으로 논의되지 않습니다.)

Function key    Translated to character         Notes
                Number  Name  Decomposition
backspace       127     DEL   Ctrl+?            May be translated to C-h instead
tab               9     TAB   Ctrl+I
linefeed         10     LFD   Ctrl+J            Few keyboards have this key
return           13     RET   Ctrl+M
escape           27     ESC   Ctrl+[

당신이 구분합니다 Tab에서 Ctrl+ I모두의 바인딩을 제거 function-key-map:

(define-key function-key-map [tab] nil)

그러나 이는 function-key-map모드 별 키맵 또는 전역 맵의 바인딩으로 입력 항목 이 재정의 되므로 유용하지 않습니다 . 다른이의 바인딩을 정의 할 경우 그래서 tab, 그냥 해 (Elisp에서가 아니라 대화 형 프롬프트 읽기 키가 적용되기 때문에 function-key-map당신이 리 바인딩 끝장 있도록 번역을 TAB하지 tab) :

(global-set-key [tab] '…)
(define-key some-mode-map [tab] '…)

의 행동 수정 모든 표준 모드 Tab키를 수정하여 그것을 할 TAB의 별명입니다 키, C-i키 조합에 의해 생성 된 문자 Ctrl+를 I. 표준 바인딩을 tab대신 에 적용하려면 키맵을 C-i그대로두고 function-key-map모드를 바꾸고 대신 Ctrl+ I를 다른 키로 리디렉션하십시오 .

(define-key input-decode-map [(control ?i)] [control-i])
(define-key input-decode-map [(control ?I)] [(shift control-i)])
(define-key some-mode-map [control-i] '…)

이제 Emacs는 Ctrl+ I를 " <control-i>(에서 번역됨 TAB)"으로보고합니다. 이쁘지는 않지만 피할 수는 없습니다 TAB. Emacs 소스 코드에 내장 된 9 번째 문자를 예쁘게 인쇄 합니다.

터미널 프레임

터미널 프레임에서는 문제가 더 어렵고 종종 불가능합니다. 터미널은 키를 전송하지 않고 문자를 전송합니다 (보다 정확하게는 바이트를 전송 함). Tab컨트롤 + I입니다, 키 조합 것과 같은 - 키는 탭 문자로 전송됩니다 Ctrl+가 I생성됩니다. 해당 문자가없는 기능 키 (예 : 커서 키)는 이스케이프 시퀀스, 즉 ESC= Control + [로 시작하는 문자 시퀀스로 전송됩니다. 따라서 Emacs는 escape프리픽스 키로 정의합니다 – ESC프리픽스 여야합니다). 키보드 입력 및 텍스트 출력어떻게 작동합니까?를 참조하십시오 . 더 많은 배경.

기능 키에 대해 서로 다른 키 시퀀스를 보내도록 구성 할 수있는 터미널이 몇 개 있지만 많지는 않습니다. 두 LeoNerd의 libtermkey / libtickit토마스 당나귀의 xterm을 (버전 216 이후)이 지원합니다. Xterm에서이 기능은 선택 사항이며 modifyOtherKeys리소스를 통해 활성화됩니다 . 그러나 이것을 지원하는 xterm 이외의 인기있는 터미널 에뮬레이터, 특히 libvte에 빌드 된 많은 에뮬레이터는 알지 못합니다 . 일부 터미널 에뮬레이터를 사용하면 키 코드에서 이스케이프 시퀀스에 이르는 사용자 정의 대응을 통해 수동으로이 작업을 수행 할 수 있습니다.

이 메커니즘을 통해 탭 / Ci, 리턴 / Cm 및 이스케이프 / C- [뿐만 아니라 많은 키 조합을 구별 할 수 있습니다. 자세한 설명은 터미널 사용시 키 바인딩 문제를 참조하십시오 .

기본 xterm 기능은 Emacs 24.4부터 지원됩니다. 그러나 기초는 (특히 Tab, Return, Escape, Backspace그의는 어떤 응용 프로그램이 예상 때문에) 여전히 전통적인 제어 문자를 보낼 수 있습니다. 제어 문자 대신 Ctrl+ letter가 이스케이프 시퀀스를 보내는 모드가 있습니다 . 따라서 CtrlEmacs 24.4 의 기능 키와 기능 키를 구별하려면 modifyOtherKeys리소스를 1 대신 2로 설정하여이 모드를 사용하도록 지원을 수정 하십시오.

;; xterm with the resource ?.VT100.modifyOtherKeys: 2
;; GNU Emacs >=24.4 sets xterm in this mode and define
;; some of the escape sequences but not all of them.
(defun character-apply-modifiers (c &rest modifiers)
  "Apply modifiers to the character C.
MODIFIERS must be a list of symbols amongst (meta control shift).
Return an event vector."
  (if (memq 'control modifiers) (setq c (if (or (and (<= ?@ c) (<= c ?_))
                                                (and (<= ?a c) (<= c ?z)))
                                            (logand c ?\x1f)
                                          (logior (lsh 1 26) c))))
  (if (memq 'meta modifiers) (setq c (logior (lsh 1 27) c)))
  (if (memq 'shift modifiers) (setq c (logior (lsh 1 25) c)))
  (vector c))
(defun my-eval-after-load-xterm ()
  (when (and (boundp 'xterm-extra-capabilities) (boundp 'xterm-function-map))
    ;; Override the standard definition to set modifyOtherKeys to 2 instead of 1
    (defun xterm-turn-on-modify-other-keys ()
      "Turn the modifyOtherKeys feature of xterm back on."
      (let ((terminal (frame-terminal)))
        (when (and (terminal-live-p terminal)
                   (memq terminal xterm-modify-other-keys-terminal-list))
          (send-string-to-terminal "\e[>4;2m" terminal))))
    (let ((c 32))
      (while (<= c 126)
        (mapc (lambda (x)
                (define-key xterm-function-map (format (car x) c)
                  (apply 'character-apply-modifiers c (cdr x))))
              '(;; with ?.VT100.formatOtherKeys: 0
                ("\e\[27;3;%d~" meta)
                ("\e\[27;5;%d~" control)
                ("\e\[27;6;%d~" control shift)
                ("\e\[27;7;%d~" control meta)
                ("\e\[27;8;%d~" control meta shift)
                ;; with ?.VT100.formatOtherKeys: 1
                ("\e\[%d;3~" meta)
                ("\e\[%d;5~" control)
                ("\e\[%d;6~" control shift)
                ("\e\[%d;7~" control meta)
                ("\e\[%d;8~" control meta shift)))
        (setq c (1+ c)))))
  (define-key xterm-function-map "")
  t)
(eval-after-load "xterm" '(my-eval-after-load-xterm))

"Emacs 24.24"라고 말하면 "Emacs 24.4"를 의미합니까?
tarsius

1
@tarsius init 파일에서 복사 한 코드의 주석은“24.4”라고 표시되어 있으므로이 답변에 쓴 텍스트의“24.24”는“24.4”의 오타였습니다.
질 'SO-정지 존재 악마'
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.