Skip to content

Instantly share code, notes, and snippets.

@Pitometsu
Last active November 15, 2019 18:58
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Pitometsu/f2f68d5e81862ceffb0d76d277376cf1 to your computer and use it in GitHub Desktop.
Save Pitometsu/f2f68d5e81862ceffb0d76d277376cf1 to your computer and use it in GitHub Desktop.
Workaround for conflict bentween escaped keystrokes in TTY and ESC.
;; Esc in TTY
(defvar evil-esc-mode nil
"Non-nil if `evil-esc-mode' is enabled.")
(defcustom evil-intercept-esc 'always
"Whether evil should intercept the ESC key.
In terminal, a plain ESC key and a meta-key-sequence both
generate the same event. In order to distinguish both evil
modifies `input-decode-map'. This is necessary in terminal but
not in X mode. However, the terminal ESC is equivalent to C-[, so
if you want to use C-[ instead of ESC in X, then Evil must
intercept the ESC event in X, too. This variable determines when
Evil should intercept the event."
:type '(radio (const :tag "Never" :value nil)
(const :tag "In terminal only" :value t)
(const :tag "Always" :value always))
:group 'evil)
(defvar evil-inhibit-esc nil
"If non-nil, the \\e event will never be translated to 'escape.")
(defcustom evil-esc-delay 0.01
"Time in seconds to wait for another key after ESC."
:type 'number
:group 'evil)
(defun evil-esc-mode (&optional arg)
"Toggle interception of \\e (escape).
Enable with positive ARG and disable with negative ARG.
When enabled, `evil-esc-mode' modifies the entry of \\e in
`input-decode-map'. If such an event arrives, it is translated to
a plain 'escape event if no further event occurs within
`evil-esc-delay' seconds. Otherwise no translation happens and
the ESC prefix map (i.e. the map originally bound to \\e in
`input-decode-map`) is returned."
(cond
((or (null arg) (eq arg 0))
(evil-esc-mode (if evil-esc-mode -1 +1)))
((> arg 0)
(unless evil-esc-mode
(setq evil-esc-mode t)
(add-hook 'after-make-frame-functions #'evil-init-esc)
(mapc #'evil-init-esc (frame-list))))
((< arg 0)
(when evil-esc-mode
(remove-hook 'after-make-frame-functions #'evil-init-esc)
(mapc #'evil-deinit-esc (frame-list))
(setq evil-esc-mode nil)))))
(defun evil-init-esc (frame)
"Update `input-decode-map' in terminal with FRAME."
(with-selected-frame frame
(let ((term (frame-terminal frame)))
(when (and
(or (eq evil-intercept-esc 'always)
(and evil-intercept-esc
(eq (terminal-live-p term) t))) ; only patch tty
(not (terminal-parameter term 'evil-esc-map)))
(let ((evil-esc-map (lookup-key input-decode-map [?\e])))
(set-terminal-parameter term 'evil-esc-map evil-esc-map)
(define-key input-decode-map [?\e]
`(menu-item "" ,evil-esc-map :filter ,#'evil-esc)))))))
(defun evil-deinit-esc (frame)
"Restore `input-decode-map' in terminal with FRAME."
(with-selected-frame frame
(let ((term (frame-terminal frame)))
(when (terminal-live-p term)
(let ((evil-esc-map (terminal-parameter term 'evil-esc-map)))
(when evil-esc-map
(define-key input-decode-map [?\e] evil-esc-map)
(set-terminal-parameter term 'evil-esc-map nil)))))))
(defun evil-esc (map)
"Translate \\e to 'escape if no further event arrives in MAP.
This function is used to translate a \\e event either to 'escape
or to the standard ESC prefix translation map. If \\e arrives,
this function waits for `evil-esc-delay' seconds for another
event. If no other event arrives, the event is translated to
'escape, otherwise it is translated to the standard ESC prefix
map stored in `input-decode-map'. If `evil-inhibit-esc' is
non-nil or if evil is in Emacs state, the event is always
translated to the ESC prefix.
The translation to 'escape happens only if the current command
has indeed been triggered by \\e. In other words, this will only
happen when the keymap is accessed from `read-key-sequence'. In
particular, if it is access from `define-key' the returned
mapping will always be the ESC prefix map."
(if (and (not evil-inhibit-esc)
;; (or evil-local-mode (evil-ex-p))
;; (not (evil-emacs-state-p))
(let ((keys (this-single-command-keys)))
(and (> (length keys) 0)
(= (aref keys (1- (length keys))) ?\e)))
(sit-for evil-esc-delay))
(prog1 [escape]
(when defining-kbd-macro
(end-kbd-macro)
(setq last-kbd-macro (vconcat last-kbd-macro [escape]))
(start-kbd-macro t t)))
map))
(evil-esc-mode 1)
@zenobht
Copy link

zenobht commented Aug 28, 2019

Thanks. This is what I was searching from last 2 hours. I had to type escape twice in terminal.

@Pitometsu
Copy link
Author

Pitometsu commented Aug 28, 2019

@jbharat glad to be helpful. Looks like that just was copy-pasted from an evil-mode. And did it long time ago, so even do not even remember that =D.
In case it can be helpful, here url to the rest of my setup: https://bitbucket.org/Kamiel/.emacs.d/


Also you could find useful https://gist.github.com/Pitometsu/b9950e8d7466ecdde1f087dcd0b26a29#file-xresources

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment