@@ -657,6 +657,74 @@ variable re-enables automatic renaming for the next title update.")
657657 " List of prompt positions as (buffer-line . exit-status) pairs.
658658Used for prompt navigation and optional re-application after full redraws." )
659659
660+ (defvar-local ghostel--scroll-intercept-active nil
661+ " Non-nil when ghostel's scroll-event intercept is active.
662+ Used as the activation key in `emulation-mode-map-alists' ." )
663+
664+
665+
666+ ; ;; Scroll intercept via emulation-mode-map-alists
667+ ; ;
668+ ; ; We need highest-priority interception of wheel events so that terminal
669+ ; ; mouse tracking (vim, htop, etc.) receives scroll events. When mouse
670+ ; ; tracking is off, we fall through to whatever scroll package the user
671+ ; ; has configured (ultra-scroll, pixel-scroll-precision-mode, etc.).
672+
673+ (defun ghostel--scroll-intercept-up (event )
674+ " Intercept wheel-up EVENT for terminal mouse tracking.
675+ If the terminal is tracking mouse events, forward as button 4.
676+ Otherwise, re-dispatch EVENT through the normal event loop so the
677+ user's scroll package handles it."
678+ (interactive " e" )
679+ (unless (ghostel--forward-scroll-event event 4 )
680+ (ghostel--redispatch-scroll-event event)))
681+
682+ (defun ghostel--scroll-intercept-down (event )
683+ " Intercept wheel-down EVENT for terminal mouse tracking.
684+ If the terminal is tracking mouse events, forward as button 5.
685+ Otherwise, re-dispatch EVENT through the normal event loop so the
686+ user's scroll package handles it."
687+ (interactive " e" )
688+ (unless (ghostel--forward-scroll-event event 5 )
689+ (ghostel--redispatch-scroll-event event)))
690+
691+ (defun ghostel--redispatch-scroll-event (event )
692+ " Re-dispatch scroll EVENT through the event loop without our intercept.
693+ Temporarily disables the emulation-map intercept and pushes the event
694+ back as unread input. The next key-lookup therefore skips our map and
695+ finds the user's scroll handler. A `pre-command-hook' re-enables the
696+ intercept before that handler runs, so subsequent events are intercepted
697+ again."
698+ (setq ghostel--scroll-intercept-active nil )
699+ (push event unread-command-events)
700+ ; ; pre-command-hook fires *after* key lookup but *before* the command,
701+ ; ; so the re-dispatched event is looked up with our intercept disabled
702+ ; ; and the intercept is back on before the next event after that.
703+ (add-hook 'pre-command-hook #'ghostel--reenable-scroll-intercept nil t ))
704+
705+ (defun ghostel--reenable-scroll-intercept ()
706+ " Re-enable the scroll-event intercept after a re-dispatched event."
707+ (setq ghostel--scroll-intercept-active t )
708+ (remove-hook 'pre-command-hook #'ghostel--reenable-scroll-intercept t ))
709+
710+ (defvar ghostel--scroll-intercept-map
711+ (let ((map (make-sparse-keymap )))
712+ (define-key map [mouse-4] #'ghostel--scroll-intercept-up )
713+ (define-key map [mouse-5] #'ghostel--scroll-intercept-down )
714+ (define-key map [wheel-up] #'ghostel--scroll-intercept-up )
715+ (define-key map [wheel-down] #'ghostel--scroll-intercept-down )
716+ map)
717+ " Keymap for `emulation-mode-map-alists' to intercept scroll events.
718+ Active only in ghostel buffers where `ghostel--scroll-intercept-active'
719+ is non-nil." )
720+
721+ (defvar ghostel--emulation-alist
722+ `((ghostel--scroll-intercept-active . ,ghostel--scroll-intercept-map ))
723+ " Alist for `emulation-mode-map-alists' ." )
724+
725+ (unless (memq 'ghostel--emulation-alist emulation-mode-map-alists)
726+ (push 'ghostel--emulation-alist emulation-mode-map-alists))
727+
660728
661729
662730; ;; Keymap
@@ -723,11 +791,6 @@ Used for prompt navigation and optional re-application after full redraws.")
723791 ; ; Prompt navigation (OSC 133)
724792 (define-key map (kbd " C-c C-n" ) #'ghostel-next-prompt )
725793 (define-key map (kbd " C-c C-p" ) #'ghostel-previous-prompt )
726- ; ; Mouse wheel for scrollback
727- (define-key map (kbd " <mouse-4>" ) #'ghostel--scroll-up )
728- (define-key map (kbd " <mouse-5>" ) #'ghostel--scroll-down )
729- (define-key map (kbd " <wheel-up>" ) #'ghostel--scroll-up )
730- (define-key map (kbd " <wheel-down>" ) #'ghostel--scroll-down )
731794 ; ; Mouse click events (for terminal mouse tracking)
732795 (define-key map (kbd " <down-mouse-1>" ) #'ghostel--mouse-press )
733796 (define-key map (kbd " <mouse-1>" ) #'ghostel--mouse-release )
@@ -1111,22 +1174,6 @@ Return non-nil if the event was forwarded (mouse tracking is active)."
11111174 row col
11121175 (ghostel--mouse-mods event)))))
11131176
1114- (defun ghostel--scroll-up (&optional event )
1115- " Scroll the Emacs window up (toward older scrollback).
1116- When the terminal has mouse tracking enabled, forward EVENT as a
1117- scroll event to the running application instead."
1118- (interactive " e" )
1119- (unless (ghostel--forward-scroll-event event 4 ) ; button 4 = scroll up
1120- (scroll-down 3 )))
1121-
1122- (defun ghostel--scroll-down (&optional event )
1123- " Scroll the Emacs window down (toward newer content).
1124- When the terminal has mouse tracking enabled, forward EVENT as a
1125- scroll event to the running application instead."
1126- (interactive " e" )
1127- (unless (ghostel--forward-scroll-event event 5 ) ; button 5 = scroll down
1128- (scroll-up 3 )))
1129-
11301177
11311178(defun ghostel-copy-mode-previous-line ()
11321179 " Move to the previous line in copy mode."
@@ -1240,11 +1287,6 @@ scroll event to the running application instead."
12401287 ; ; Prompt navigation works in copy mode too
12411288 (define-key map (kbd " C-c C-n" ) #'ghostel-next-prompt )
12421289 (define-key map (kbd " C-c C-p" ) #'ghostel-previous-prompt )
1243- ; ; Scrollback
1244- (define-key map (kbd " <mouse-4>" ) #'ghostel--scroll-up )
1245- (define-key map (kbd " <mouse-5>" ) #'ghostel--scroll-down )
1246- (define-key map (kbd " <wheel-up>" ) #'ghostel--scroll-up )
1247- (define-key map (kbd " <wheel-down>" ) #'ghostel--scroll-down )
12481290 (define-key map (kbd " C-n" ) #'ghostel-copy-mode-next-line )
12491291 (define-key map (kbd " C-p" ) #'ghostel-copy-mode-previous-line )
12501292 (define-key map (kbd " M-<" ) #'ghostel-copy-mode-beginning-of-buffer )
@@ -2303,13 +2345,13 @@ PROCESS is the shell process, WINDOWS is the list of windows."
23032345 (setq-local scroll-conservatively 101 )
23042346 (setq-local line-spacing 0 )
23052347 (add-function :after after-focus-change-function #'ghostel--focus-change )
2306- (ghostel--suppress-interfering-modes))
2348+ (ghostel--suppress-interfering-modes)
2349+ (setq ghostel--scroll-intercept-active t ))
23072350
23082351(defun ghostel--suppress-interfering-modes ()
23092352 " Disable global minor modes that interfere with ghostel.
23102353Suppresses `global-hl-line-mode' (and buffer-local `hl-line-mode' ) to
2311- prevent redraw flicker, and `pixel-scroll-precision-mode' so that
2312- wheel events reach ghostel's own scroll commands."
2354+ prevent redraw flicker."
23132355 ; ; global-hl-line-mode: opt this buffer out by setting the variable
23142356 ; ; buffer-locally to nil (as documented in the hl-line.el commentary).
23152357 (when (bound-and-true-p global-hl-line-mode)
@@ -2320,12 +2362,7 @@ wheel events reach ghostel's own scroll commands."
23202362 ; ; Buffer-local hl-line-mode
23212363 (when (bound-and-true-p hl-line-mode)
23222364 (setq ghostel--saved-hl-line-mode t )
2323- (hl-line-mode -1 ))
2324- ; ; pixel-scroll-precision-mode: setting the variable buffer-locally to nil
2325- ; ; makes Emacs skip its minor-mode-map-alist entry for this buffer, so
2326- ; ; wheel-up/wheel-down reach ghostel-mode-map instead.
2327- (when (bound-and-true-p pixel-scroll-precision-mode)
2328- (setq-local pixel-scroll-precision-mode nil )))
2365+ (hl-line-mode -1 )))
23292366
23302367
23312368; ;; Entry point
0 commit comments