Skip to content

Commit 43220db

Browse files
committed
Fix Meta key combinations not forwarded to terminal
M-f, M-b, M-d etc. were intercepted by Emacs global bindings (forward-word, backward-word, kill-word) instead of being sent to the terminal. Two fixes: bind M-<letter> keys in ghostel-mode-map via ghostel--send-event, and add ESC+char fallback in ghostel--raw-key-sequence for when the native encoder doesn't produce output. Fix #48
1 parent cd3031d commit 43220db

2 files changed

Lines changed: 26 additions & 1 deletion

File tree

ghostel.el

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -621,6 +621,12 @@ Used for prompt navigation and optional re-application after full redraws.")
621621
(let ((code (- c 96)))
622622
(lambda () (interactive)
623623
(ghostel--send-key (string code)))))))))
624+
;; Meta keys — bind all M-<letter> so they reach the terminal
625+
;; instead of running Emacs commands like forward-word.
626+
(dolist (c (number-sequence ?a ?z))
627+
(let ((key-str (format "M-%c" c)))
628+
(unless (member key-str ghostel-keymap-exceptions)
629+
(define-key map (kbd key-str) #'ghostel--send-event))))
624630
;; C-@ (NUL, same as C-SPC) — used by programs like Emacs-in-terminal
625631
(define-key map (kbd "C-@")
626632
(lambda () (interactive) (ghostel--send-key "\x00")))
@@ -749,6 +755,11 @@ Returns the sequence string, or nil for unknown keys."
749755
(<= ?a (aref key-name 0)) (<= (aref key-name 0) ?z)
750756
(> (logand mod-num 4) 0)) ; ctrl bit
751757
(string (- (aref key-name 0) 96))) ; ctrl-a=1, ctrl-z=26
758+
;; Meta + single letter → ESC + char
759+
((and (= (length key-name) 1)
760+
(<= ?a (aref key-name 0)) (<= (aref key-name 0) ?z)
761+
(> (logand mod-num 2) 0)) ; alt/meta bit
762+
(format "\e%c" (aref key-name 0)))
752763
;; Simple special keys (CSI u encoding for modified variants)
753764
((string= key-name "backspace") (if (> mod-num 0) (format "\e[127;%du" (1+ mod-num)) "\x7f"))
754765
((string= key-name "return") (if (> mod-num 0) (format "\e[13;%du" (1+ mod-num)) "\r"))

test/ghostel-test.el

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1430,6 +1430,19 @@ cell, so the visual line width must equal the terminal column count."
14301430
;; C-@ should also be bound (sends NUL)
14311431
(should (lookup-key ghostel-mode-map (kbd "C-@"))))
14321432

1433+
(ert-deftest ghostel-test-meta-key-bindings ()
1434+
"All non-exception M-<letter> keys should be bound in ghostel-mode-map."
1435+
(dolist (c (number-sequence ?a ?z))
1436+
(let* ((key-str (format "M-%c" c))
1437+
(key-vec (kbd key-str))
1438+
(binding (lookup-key ghostel-mode-map key-vec)))
1439+
(unless (eq c ?y) ; M-y is ghostel-yank-pop
1440+
(if (member key-str ghostel-keymap-exceptions)
1441+
(should-not (eq binding #'ghostel--send-event))
1442+
(should (eq binding #'ghostel--send-event))))))
1443+
;; M-y should be bound to ghostel-yank-pop, not send-event
1444+
(should (eq (lookup-key ghostel-mode-map (kbd "M-y")) #'ghostel-yank-pop)))
1445+
14331446
(defconst ghostel-test--elisp-tests
14341447
'(ghostel-test-raw-key-sequences
14351448
ghostel-test-modifier-number
@@ -1458,7 +1471,8 @@ cell, so the visual line width must equal the terminal column count."
14581471
ghostel-test-input-flush-sends-buffered
14591472
ghostel-test-send-encoded-sets-send-time
14601473
ghostel-test-send-encoded-no-send-time-on-fallback
1461-
ghostel-test-control-key-bindings)
1474+
ghostel-test-control-key-bindings
1475+
ghostel-test-meta-key-bindings)
14621476
"Tests that require only Elisp (no native module).")
14631477

14641478
(defun ghostel-test-run-elisp ()

0 commit comments

Comments
 (0)