emacs enters gibberish into the buffer, opens describe-prefix-bindings, fails to launch kkp randomly
Hello! Thanks for this package, it's tremendously useful. I have been running into an issue that, while I'm not sure if it is a kkp issue, seems like it might be.
Randomly (about 50% of the time?) when I open emacs in the terminal, the text 0u62;c is inserted into the start of the buffer, this describe-prefix-bindings buffer pops up, and kkp fails to launch (not necessarily in that order).
I do not know what could be causing this. I am going to continue and try to debug and get a reproducible / minimal init.el, but wanted to open an issue in case you recognize what might be causing the issue. The 0u62;c makes me think there is some failed capability negotiation going on, that gets translated into text+bindings, and somehow triggers describe-prefix-bindings.
This is a screenshot of my terminal after one of these failed launches. Note the partially entered C-h is just a result of me typing C-h k and then C-<backspace> to check if kkp is active. It's not, so Emacs recognizes C-<backspace> as the C-h prefix.
If you have an idea of how to track this down it'd be much appreciated!
I'm experiencing the same issue. When this happens kkp seems to be broken, eg. I can't use <Super> until I restart Emacs. Eg. pressing s-. inserts the . character. Toggling kkp-global-mode on and off doesn't help.
My current fix is to activate kkp-global-mode manually after Emacs has started.
The weird characters sometimes still get inserted but after activating kkp-global-mode kkp seems to work properly.
I tried WezTerm, Alactritty and Ghostty and they all show this behavior.
I'm connecting via ssh to a remote machine and running Emacs there. Not sure if this could play into the problem. @omentic I assume you're starting Emacs on your local machine since you didn't mention ssh?
I'm seeing this too, running in foot without ssh. I can repro it intentionally 100% simply by starting emacs and then typing a key quickly.
The key doesn't seem to matter. When it happens, emacs processes the key (pasting it, or running its binding if bound), then also inserts the kkp setup protocol response at point except with \e[?parts omitted, and opens a help buffer showing "Input decoding map translations Starting With M-[" (which is what you get if you indeed type M-[ aka \e[, and then type ? for help at the prompt). For example, when typing a, the following is inserted: a0u62;4;22;28;52c.
That looks like the ("\e[?" . kkp--terminal-setup) binding added by kkp is somehow not firing.
With this modified version of the setup code:
(defun kkp--query-terminal-async (query handlers terminal)
"Send QUERY string to TERMINAL and register HANDLERS for a response.
HANDLERS is an alist with elements of the form (STRING . FUNCTION).
We run the first FUNCTION whose STRING matches the input events.
This function code is copied from `xterm--query'."
(with-selected-frame (car (frames-on-display-list terminal))
(let ((register
(lambda (handlers)
(dolist (handler handlers)
(define-key input-decode-map (car handler)
(lambda (&optional _prompt)
(message "lambda")
;; Unregister the handler, since we don't expect
;; further answers.
(dolist (handler handlers)
(define-key input-decode-map (car handler) nil))
(funcall (cdr handler))
[]))))))
(funcall register handlers)
(message "kkp")
(describe-keymap input-decode-map)
(with-current-buffer (generate-new-buffer "input-decode-map")
(insert-buffer "*Help*"))
(send-string-to-terminal (kkp--csi-escape query) terminal))))
I can see that the setup function is installing the \e[? binding as expected, but then the binding is indeed missing from a manual describe-keymap run after startup is done. And my lambda message is firing in the good case (i.e. if I don't type anything during startup) but not the bad case, so I don't think it's disappearing due to the intentional self-remove. To make sure it's not some weird quirk of message, I also tried a (kill-emacs) in the lamda and likewise saw emacs get killed only in the good case.
So seems like the early input is triggering something else to remove the kkp query response binding from input-decode-map.
Apparently, it's the xterm feature negotiation in xterm.el, which also binds the problem key sequence (and uses the same basic self-removal approach - iiuc kkp,el is based on that code).
(xterm--query "\e[>0c"
;; Some terminals (like macOS's Terminal.app) respond to
;; this query as if it were a "Primary Device Attributes"
;; query instead, so we should handle that too.
'(("\e[?" . xterm--version-handler)
("\e[>" . xterm--version-handler))
This prints only in the bad case:
(defadvice xterm--version-handler (before break-on-xterm activate)
(message "xterm")
)
I don't know why typing a char too early triggers that code. My TERM is foot.
The term setup logic intentionally treats foot like xterm - probably there's some backcompat logic to its color processing:
(defcustom term-file-aliases
'(("apollo" . "vt100")
("vt102" . "vt100")
("vt125" . "vt100")
("vt201" . "vt200")
("vt220" . "vt200")
("vt240" . "vt200")
("vt300" . "vt200")
("vt320" . "vt200")
("vt400" . "vt200")
("vt420" . "vt200")
("alacritty" . "xterm")
("foot" . "xterm")
("contour" . "xterm"))
"Alist of terminal type aliases.
Entries are of the form (TYPE . ALIAS), where both elements are strings.
This means to treat a terminal of type TYPE as if it were of type ALIAS."
:type '(alist :key-type (string :tag "Terminal")
:value-type (string :tag "Alias"))
:group 'terminals
:version "25.1")
Hence calling it via this stack, which respects that var:
Debugger entered: nil
ad-Advice-terminal-init-xterm(#<subr terminal-init-xterm>)
apply(ad-Advice-terminal-init-xterm #<subr terminal-init-xterm> nil)
terminal-init-xterm()
tty-run-terminal-initialization(#<frame F1 0x55f46f191550> nil t)
command-line()
normal-top-level()
I still haven't tried to investigate how/why these are racing, which is probably necessary for a real fix. I suppose the early input triggers xterm--init to run between the time that kkp installs its key handler and the time that the term actually responds to it. @benotn , maybe you might have some opinions on how to correctly order kkp with xterm.el?
But the diff adding xterm.el"s use of "\e[?" really looks like it was trying to fix a terminal.app-specific issue. I don't use it, so it probably suffices for me to work around this by just omitting it from xterm-query handling:
(advice-add
'xterm--query
:around
(progn
(defun xterm--query-rm-kkp-conflict (orig-fun type alist &rest args)
"Disable a circa-2013 workaround for OS X terminal.app that is liable to race with kkp.el's own
use of this escape sequence to negotiate kkp support, causing flaky kkp-not-supported state if input
comes in too soon."
(apply orig-fun type (assoc-delete-all "\e[?" alist) args))
'xterm--query-rm-kkp-conflict))
Oh, I guess it probably has to do with xterm's branching on (input-pending-p). Maybe it always runs in the bad window (after kkp), but it's usually not a problem because it only uses the async key handler approach when an early user input makes (input-pending-p) true.
I can't think of any easy fix. I guess this is the problem with using key events as rpcs - a moral fix would need kkp and xterm.el's handlers to know exactly which request they're seeing a response to, which seems like a huge pain in a system designed for handling hotkeys. I guess kkp should just arrange to run after xterm, so that it is the binding trasher rather than the trashee, or productize that advice workaround above (wrap a non-internal function, and just save/restore the binding directly).