v0.8.0: replace inline read-raw-byte reader with cl-tty.input:read-event
The old inline reader only handled basic CSI sequences (up/down/left/right/ home/end) and treated everything else as Escape. cl-tty.input:read-event handles CSI sequences with modifiers, SS3 function keys, kitty keyboard protocol (disambiguate escape codes), UTF-8 input, and terminal resize. Key-event structs are converted back to the keyword/integer format that the existing case ch dispatch and on-key expect: - Ctrl+letter → :CTRL-X keyword - :page-up/:page-down → :ppage/:npage - Single-char keywords → printable character via code-char - Everything else → pass keyword through Removed the separate resize check block since read-event handles it.
This commit is contained in:
@@ -953,69 +953,57 @@ Returns T on success, nil on failure. Does NOT wait or retry."
|
|||||||
(if (eql ch :up)
|
(if (eql ch :up)
|
||||||
(cl-tty.select:select-prev sel)
|
(cl-tty.select:select-prev sel)
|
||||||
(cl-tty.select:select-next sel)))
|
(cl-tty.select:select-next sel)))
|
||||||
((member ch '(:enter 13 10))
|
((member ch '(:enter))
|
||||||
(let* ((filtered (cl-tty.select:select-filtered-options sel))
|
(let* ((filtered (cl-tty.select:select-filtered-options sel))
|
||||||
(idx (cl-tty.select:select-selected-index sel))
|
(idx (cl-tty.select:select-selected-index sel))
|
||||||
(item (when (< idx (length filtered))
|
(item (when (< idx (length filtered))
|
||||||
(third (nth idx filtered)))))
|
(third (nth idx filtered)))))
|
||||||
(when item
|
(when item
|
||||||
(let ((cb (cl-tty.select:select-on-select sel)))
|
(let ((cb (cl-tty.select:select-on-select sel)))
|
||||||
(when cb (funcall cb item))))))
|
(when cb (funcall cb item))))))
|
||||||
((let ((chr (if (characterp ch) ch
|
((let ((chr (if (characterp ch) ch (code-char ch))))
|
||||||
(and (integerp ch) (<= 32 ch 126)
|
(and chr (graphic-char-p chr))
|
||||||
(code-char ch)))))
|
(setf (cl-tty.select:select-filter sel)
|
||||||
(and chr (graphic-char-p chr))
|
(concatenate 'string
|
||||||
(setf (cl-tty.select:select-filter sel)
|
(or (cl-tty.select:select-filter sel) "")
|
||||||
(concatenate 'string
|
(string chr)))))
|
||||||
(or (cl-tty.select:select-filter sel) "")
|
((member ch '(:backspace))
|
||||||
(string chr)))))
|
|
||||||
((member ch '(:backspace 127 8))
|
|
||||||
(let ((f (cl-tty.select:select-filter sel)))
|
(let ((f (cl-tty.select:select-filter sel)))
|
||||||
(when (> (length f) 0)
|
(when (> (length f) 0)
|
||||||
(setf (cl-tty.select:select-filter sel)
|
(setf (cl-tty.select:select-filter sel)
|
||||||
(subseq f 0 (1- f))))))))
|
(subseq f 0 (1- f))))))))
|
||||||
(on-key ch))))))))
|
(on-key ch))))))))
|
||||||
;; Keyboard reader via read-raw-byte (proven CSI detection)
|
;; Keyboard reader via cl-tty.input:read-event (handles CSI, SS3, UTF-8, resize)
|
||||||
(handler-case
|
(handler-case
|
||||||
(let* ((b (cl-tty.input::read-raw-byte :timeout 0.1))
|
(multiple-value-bind (ev resize-data)
|
||||||
(esc-seq (and b (= b 27)
|
(cl-tty.input:read-event be :timeout 0.1)
|
||||||
(let ((b2 (cl-tty.input::read-raw-byte :timeout 0.15)))
|
(cond
|
||||||
(when (and b2 (= b2 91))
|
((eq ev :resize)
|
||||||
(let ((t2 (cl-tty.input::read-raw-byte :timeout 0.15)))
|
(let ((new-size resize-data))
|
||||||
(and t2 (case t2
|
(setq w (car new-size) h (cdr new-size))
|
||||||
(65 :up) (66 :down)
|
(setf (st :dirty) (list t t t))))
|
||||||
(67 :right) (68 :left)
|
((cl-tty.input:key-event-p ev)
|
||||||
(72 :home) (70 :end)
|
(let* ((k (cl-tty.input:key-event-key ev))
|
||||||
(otherwise :escape)))))))))
|
(ctrl (cl-tty.input:key-event-ctrl ev))
|
||||||
(when b
|
(code (cl-tty.input:key-event-code ev))
|
||||||
(queue-event
|
(ch (cond
|
||||||
(list :type :key
|
;; Ctrl+letter → :CTRL-X keyword (compatible with case dispatch)
|
||||||
:payload (list :code b
|
(ctrl (let ((c (char (symbol-name k) 0)))
|
||||||
:ch (or esc-seq
|
(intern (string-upcase (format nil "CTRL-~a" c)) :keyword)))
|
||||||
(cond
|
;; PageUp/PageDown → :ppage/:npage
|
||||||
((= b 13) :enter)
|
((eq k :page-up) :ppage)
|
||||||
((= b 10) :enter)
|
((eq k :page-down) :npage)
|
||||||
((= b 27) :escape)
|
;; Single-char keyword → printable character
|
||||||
((= b 9) :tab)
|
((and (keywordp k) (= (length (symbol-name k)) 1))
|
||||||
((or (= b 127) (= b 8)) :backspace)
|
(code-char code))
|
||||||
((and (>= b 1) (<= b 26))
|
;; Everything else → pass keyword through
|
||||||
(intern
|
(t k))))
|
||||||
(string-upcase
|
(queue-event
|
||||||
(format nil "CTRL-~a"
|
(list :type :key
|
||||||
(code-char (+ #x60 b))))
|
:payload (list :code (or code 0) :ch ch)))))))
|
||||||
:keyword))
|
(error (c)
|
||||||
(t b))))))))
|
(add-msg :system (format nil "* Reader error: ~a *" c))))
|
||||||
(error (c)
|
;; Guard w and h before render (resize or other code may have set them to nil)
|
||||||
(add-msg :system (format nil "* Reader error: ~a *" c))))
|
|
||||||
;; Check for terminal resize (SIGWINCH sets this flag)
|
|
||||||
(when (boundp 'cl-tty.input::*terminal-resized-p*)
|
|
||||||
(when cl-tty.input::*terminal-resized-p*
|
|
||||||
(setf cl-tty.input::*terminal-resized-p* nil)
|
|
||||||
(multiple-value-setq (w h) (cl-tty.backend:backend-size be))
|
|
||||||
(setq w (or (and (numberp w) (> w 0) w) 80)
|
|
||||||
h (or (and (numberp h) (> h 0) h) 24))
|
|
||||||
(setf (st :dirty) (list t t t))))
|
|
||||||
;; Guard w and h before render (resize or other code may have set them to nil)
|
|
||||||
(setq w (or (and (numberp w) (> w 0) w) 80)
|
(setq w (or (and (numberp w) (> w 0) w) 80)
|
||||||
h (or (and (numberp h) (> h 0) h) 24))
|
h (or (and (numberp h) (> h 0) h) 24))
|
||||||
(unless (st :dialog-stack)
|
(unless (st :dialog-stack)
|
||||||
|
|||||||
Reference in New Issue
Block a user