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)
|
||||
(cl-tty.select:select-prev sel)
|
||||
(cl-tty.select:select-next sel)))
|
||||
((member ch '(:enter 13 10))
|
||||
(let* ((filtered (cl-tty.select:select-filtered-options sel))
|
||||
(idx (cl-tty.select:select-selected-index sel))
|
||||
(item (when (< idx (length filtered))
|
||||
(third (nth idx filtered)))))
|
||||
(when item
|
||||
(let ((cb (cl-tty.select:select-on-select sel)))
|
||||
(when cb (funcall cb item))))))
|
||||
((let ((chr (if (characterp ch) ch
|
||||
(and (integerp ch) (<= 32 ch 126)
|
||||
(code-char ch)))))
|
||||
(and chr (graphic-char-p chr))
|
||||
(setf (cl-tty.select:select-filter sel)
|
||||
(concatenate 'string
|
||||
(or (cl-tty.select:select-filter sel) "")
|
||||
(string chr)))))
|
||||
((member ch '(:backspace 127 8))
|
||||
((member ch '(:enter))
|
||||
(let* ((filtered (cl-tty.select:select-filtered-options sel))
|
||||
(idx (cl-tty.select:select-selected-index sel))
|
||||
(item (when (< idx (length filtered))
|
||||
(third (nth idx filtered)))))
|
||||
(when item
|
||||
(let ((cb (cl-tty.select:select-on-select sel)))
|
||||
(when cb (funcall cb item))))))
|
||||
((let ((chr (if (characterp ch) ch (code-char ch))))
|
||||
(and chr (graphic-char-p chr))
|
||||
(setf (cl-tty.select:select-filter sel)
|
||||
(concatenate 'string
|
||||
(or (cl-tty.select:select-filter sel) "")
|
||||
(string chr)))))
|
||||
((member ch '(:backspace))
|
||||
(let ((f (cl-tty.select:select-filter sel)))
|
||||
(when (> (length f) 0)
|
||||
(setf (cl-tty.select:select-filter sel)
|
||||
(subseq f 0 (1- f))))))))
|
||||
(on-key ch))))))))
|
||||
;; Keyboard reader via read-raw-byte (proven CSI detection)
|
||||
(handler-case
|
||||
(let* ((b (cl-tty.input::read-raw-byte :timeout 0.1))
|
||||
(esc-seq (and b (= b 27)
|
||||
(let ((b2 (cl-tty.input::read-raw-byte :timeout 0.15)))
|
||||
(when (and b2 (= b2 91))
|
||||
(let ((t2 (cl-tty.input::read-raw-byte :timeout 0.15)))
|
||||
(and t2 (case t2
|
||||
(65 :up) (66 :down)
|
||||
(67 :right) (68 :left)
|
||||
(72 :home) (70 :end)
|
||||
(otherwise :escape)))))))))
|
||||
(when b
|
||||
(queue-event
|
||||
(list :type :key
|
||||
:payload (list :code b
|
||||
:ch (or esc-seq
|
||||
(cond
|
||||
((= b 13) :enter)
|
||||
((= b 10) :enter)
|
||||
((= b 27) :escape)
|
||||
((= b 9) :tab)
|
||||
((or (= b 127) (= b 8)) :backspace)
|
||||
((and (>= b 1) (<= b 26))
|
||||
(intern
|
||||
(string-upcase
|
||||
(format nil "CTRL-~a"
|
||||
(code-char (+ #x60 b))))
|
||||
:keyword))
|
||||
(t b))))))))
|
||||
(error (c)
|
||||
(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)
|
||||
;; Keyboard reader via cl-tty.input:read-event (handles CSI, SS3, UTF-8, resize)
|
||||
(handler-case
|
||||
(multiple-value-bind (ev resize-data)
|
||||
(cl-tty.input:read-event be :timeout 0.1)
|
||||
(cond
|
||||
((eq ev :resize)
|
||||
(let ((new-size resize-data))
|
||||
(setq w (car new-size) h (cdr new-size))
|
||||
(setf (st :dirty) (list t t t))))
|
||||
((cl-tty.input:key-event-p ev)
|
||||
(let* ((k (cl-tty.input:key-event-key ev))
|
||||
(ctrl (cl-tty.input:key-event-ctrl ev))
|
||||
(code (cl-tty.input:key-event-code ev))
|
||||
(ch (cond
|
||||
;; Ctrl+letter → :CTRL-X keyword (compatible with case dispatch)
|
||||
(ctrl (let ((c (char (symbol-name k) 0)))
|
||||
(intern (string-upcase (format nil "CTRL-~a" c)) :keyword)))
|
||||
;; PageUp/PageDown → :ppage/:npage
|
||||
((eq k :page-up) :ppage)
|
||||
((eq k :page-down) :npage)
|
||||
;; Single-char keyword → printable character
|
||||
((and (keywordp k) (= (length (symbol-name k)) 1))
|
||||
(code-char code))
|
||||
;; Everything else → pass keyword through
|
||||
(t k))))
|
||||
(queue-event
|
||||
(list :type :key
|
||||
:payload (list :code (or code 0) :ch ch)))))))
|
||||
(error (c)
|
||||
(add-msg :system (format nil "* Reader error: ~a *" c))))
|
||||
;; 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)
|
||||
h (or (and (numberp h) (> h 0) h) 24))
|
||||
(unless (st :dialog-stack)
|
||||
|
||||
Reference in New Issue
Block a user