| 1 | ;;; -*- Log: hemlock.log; Package: Hemlock-Internals -*-
|
|---|
| 2 | ;;;
|
|---|
| 3 | ;;; **********************************************************************
|
|---|
| 4 | ;;; This code was written as part of the CMU Common Lisp project at
|
|---|
| 5 | ;;; Carnegie Mellon University, and has been placed in the public domain.
|
|---|
| 6 | ;;;
|
|---|
| 7 | #+CMU (ext:file-comment
|
|---|
| 8 | "$Header$")
|
|---|
| 9 | ;;;
|
|---|
| 10 | ;;; **********************************************************************
|
|---|
| 11 | ;;;
|
|---|
| 12 | ;;; This file contains the code that handles input to Hemlock.
|
|---|
| 13 | ;;;
|
|---|
| 14 | (in-package :hemlock-internals)
|
|---|
| 15 |
|
|---|
| 16 | ;;;
|
|---|
| 17 | ;;; INPUT-WAITING is exported solely as a hack for the kbdmac definition
|
|---|
| 18 | ;;; mechanism.
|
|---|
| 19 | ;;;
|
|---|
| 20 |
|
|---|
| 21 |
|
|---|
| 22 | ;;; These are public variables users hand to the four basic editor input
|
|---|
| 23 | ;;; routines for method dispatching:
|
|---|
| 24 | ;;; GET-KEY-EVENT
|
|---|
| 25 | ;;; UNGET-KEY-EVENT
|
|---|
| 26 | ;;; LISTEN-EDITOR-INPUT
|
|---|
| 27 | ;;; CLEAR-EDITOR-INPUT
|
|---|
| 28 | ;;;
|
|---|
| 29 | (defvar *editor-input* nil
|
|---|
| 30 | "A structure used to do various operations on terminal input.")
|
|---|
| 31 |
|
|---|
| 32 | (defvar *real-editor-input* ()
|
|---|
| 33 | "Useful when we want to read from the terminal when *editor-input* is
|
|---|
| 34 | rebound.")
|
|---|
| 35 |
|
|---|
| 36 |
|
|---|
| 37 | |
|---|
| 38 |
|
|---|
| 39 | ;;;; editor-input structure.
|
|---|
| 40 |
|
|---|
| 41 | (defstruct (editor-input (:print-function
|
|---|
| 42 | (lambda (s stream d)
|
|---|
| 43 | (declare (ignore s d))
|
|---|
| 44 | (write-string "#<Editor-Input stream>" stream))))
|
|---|
| 45 | get ; A function that returns the next key-event in the queue.
|
|---|
| 46 | unget ; A function that puts a key-event at the front of the queue.
|
|---|
| 47 | listen ; A function that tells whether the queue is empty.
|
|---|
| 48 | clear ; A function that empties the queue.
|
|---|
| 49 | ;;
|
|---|
| 50 | ;; Queue of events on this stream. The queue always contains at least one
|
|---|
| 51 | ;; one element, which is the key-event most recently read. If no event has
|
|---|
| 52 | ;; been read, the event is a dummy with a nil key-event.
|
|---|
| 53 | head
|
|---|
| 54 | tail)
|
|---|
| 55 |
|
|---|
| 56 |
|
|---|
| 57 | ;;; These are the elements of the editor-input event queue.
|
|---|
| 58 | ;;;
|
|---|
| 59 | (defstruct (input-event (:constructor make-input-event ()))
|
|---|
| 60 | next ; Next queued event, or NIL if none.
|
|---|
| 61 | hunk ; Screen hunk event was read from.
|
|---|
| 62 | key-event ; Key-event read.
|
|---|
| 63 | x ; X and Y character position of mouse cursor.
|
|---|
| 64 | y
|
|---|
| 65 | unread-p)
|
|---|
| 66 |
|
|---|
| 67 | (defvar *free-input-events* ())
|
|---|
| 68 |
|
|---|
| 69 | (defun new-event (key-event x y hunk next &optional unread-p)
|
|---|
| 70 | (let ((res (if *free-input-events*
|
|---|
| 71 | (shiftf *free-input-events*
|
|---|
| 72 | (input-event-next *free-input-events*))
|
|---|
| 73 | (make-input-event))))
|
|---|
| 74 | (setf (input-event-key-event res) key-event)
|
|---|
| 75 | (setf (input-event-x res) x)
|
|---|
| 76 | (setf (input-event-y res) y)
|
|---|
| 77 | (setf (input-event-hunk res) hunk)
|
|---|
| 78 | (setf (input-event-next res) next)
|
|---|
| 79 | (setf (input-event-unread-p res) unread-p)
|
|---|
| 80 | res))
|
|---|
| 81 |
|
|---|
| 82 | ;;; This is a public variable.
|
|---|
| 83 | ;;;
|
|---|
| 84 | (defvar *last-key-event-typed* ()
|
|---|
| 85 | "This variable contains the last key-event typed by the user and read as
|
|---|
| 86 | input.")
|
|---|
| 87 |
|
|---|
| 88 | ;;; This is a public variable. SITE-INIT initializes this.
|
|---|
| 89 | ;;;
|
|---|
| 90 | (defvar *key-event-history* nil
|
|---|
| 91 | "This ring holds the last 60 key-events read by the command interpreter.")
|
|---|
| 92 |
|
|---|
| 93 | (declaim (special *input-transcript*))
|
|---|
| 94 |
|
|---|
| 95 | ;;; DQ-EVENT is used in editor stream methods for popping off input.
|
|---|
| 96 | ;;; If there is an event not yet read in Stream, then pop the queue
|
|---|
| 97 | ;;; and return the character. If there is none, return NIL.
|
|---|
| 98 | ;;;
|
|---|
| 99 | (defun dq-event (stream)
|
|---|
| 100 | (hemlock-ext:without-interrupts
|
|---|
| 101 | (let* ((head (editor-input-head stream))
|
|---|
| 102 | (next (input-event-next head)))
|
|---|
| 103 | (if next
|
|---|
| 104 | (let ((key-event (input-event-key-event next)))
|
|---|
| 105 | (setf (editor-input-head stream) next)
|
|---|
| 106 | (shiftf (input-event-next head) *free-input-events* head)
|
|---|
| 107 | (ring-push key-event *key-event-history*)
|
|---|
| 108 | (setf *last-key-event-typed* key-event)
|
|---|
| 109 | (when *input-transcript*
|
|---|
| 110 | (vector-push-extend key-event *input-transcript*))
|
|---|
| 111 | key-event)))))
|
|---|
| 112 |
|
|---|
| 113 | ;;; Q-EVENT is used in low level input fetching routines to add input to the
|
|---|
| 114 | ;;; editor stream.
|
|---|
| 115 | ;;;
|
|---|
| 116 | (defun q-event (stream key-event &optional x y hunk)
|
|---|
| 117 | (hemlock-ext:without-interrupts
|
|---|
| 118 | (let ((new (new-event key-event x y hunk nil))
|
|---|
| 119 | (tail (editor-input-tail stream)))
|
|---|
| 120 | (setf (input-event-next tail) new)
|
|---|
| 121 | (setf (editor-input-tail stream) new))))
|
|---|
| 122 |
|
|---|
| 123 | (defun un-event (key-event stream)
|
|---|
| 124 | (hemlock-ext:without-interrupts
|
|---|
| 125 | (let* ((head (editor-input-head stream))
|
|---|
| 126 | (next (input-event-next head))
|
|---|
| 127 | (new (new-event key-event (input-event-x head) (input-event-y head)
|
|---|
| 128 | (input-event-hunk head) next t)))
|
|---|
| 129 | (setf (input-event-next head) new)
|
|---|
| 130 | (unless next (setf (editor-input-tail stream) new)))))
|
|---|
| 131 |
|
|---|
| 132 |
|
|---|
| 133 | |
|---|
| 134 |
|
|---|
| 135 | ;;;; Keyboard macro hacks.
|
|---|
| 136 |
|
|---|
| 137 | (defvar *input-transcript* ()
|
|---|
| 138 | "If this variable is non-null then it should contain an adjustable vector
|
|---|
| 139 | with a fill pointer into which all keyboard input will be pushed.")
|
|---|
| 140 |
|
|---|
| 141 | ;;; INPUT-WAITING -- Internal
|
|---|
| 142 | ;;;
|
|---|
| 143 | ;;; An Evil hack that tells us whether there is an unread key-event on
|
|---|
| 144 | ;;; *editor-input*. Note that this is applied to the real *editor-input*
|
|---|
| 145 | ;;; rather than to a kbdmac stream.
|
|---|
| 146 | ;;;
|
|---|
| 147 | (defun input-waiting ()
|
|---|
| 148 | "Returns true if there is a key-event which has been unread-key-event'ed
|
|---|
| 149 | on *editor-input*. Used by the keyboard macro stuff."
|
|---|
| 150 | (let ((next (input-event-next
|
|---|
| 151 | (editor-input-head *real-editor-input*))))
|
|---|
| 152 | (and next (input-event-unread-p next))))
|
|---|
| 153 |
|
|---|
| 154 |
|
|---|
| 155 | |
|---|
| 156 |
|
|---|
| 157 | ;;;; Input method macro.
|
|---|
| 158 |
|
|---|
| 159 | (defvar *in-hemlock-stream-input-method* nil
|
|---|
| 160 | "This keeps us from undefined nasties like re-entering Hemlock stream
|
|---|
| 161 | input methods from input hooks and scheduled events.")
|
|---|
| 162 |
|
|---|
| 163 | (declaim (special *screen-image-trashed*))
|
|---|
| 164 |
|
|---|
| 165 | ;;; These are the characters GET-KEY-EVENT notices when it pays attention
|
|---|
| 166 | ;;; to aborting input. This happens via EDITOR-INPUT-METHOD-MACRO.
|
|---|
| 167 | ;;;
|
|---|
| 168 | (defparameter editor-abort-key-events (list #k"Control-g" #k"Control-G"))
|
|---|
| 169 |
|
|---|
| 170 | #+clx
|
|---|
| 171 | (defun cleanup-for-wm-closed-display(closed-display)
|
|---|
| 172 | ;; Remove fd-handlers
|
|---|
| 173 | (hemlock-ext:disable-clx-event-handling closed-display)
|
|---|
| 174 | ;; Close file descriptor and note DEAD.
|
|---|
| 175 | (xlib:close-display closed-display)
|
|---|
| 176 | ;;
|
|---|
| 177 | ;; At this point there is not much sense to returning to Lisp
|
|---|
| 178 | ;; as the editor cannot be re-entered (there are lots of pointers
|
|---|
| 179 | ;; to the dead display around that will cause subsequent failures).
|
|---|
| 180 | ;; Maybe could switch to tty mode then (save-all-files-and-exit)?
|
|---|
| 181 | ;; For now, just assume user wanted an easy way to kill the session.
|
|---|
| 182 | (hemlock-ext:quit))
|
|---|
| 183 |
|
|---|
| 184 | (defmacro abort-key-event-p (key-event)
|
|---|
| 185 | `(member ,key-event editor-abort-key-events))
|
|---|
| 186 |
|
|---|
| 187 | ;;; EDITOR-INPUT-METHOD-MACRO -- Internal.
|
|---|
| 188 | ;;;
|
|---|
| 189 | ;;; WINDOWED-GET-KEY-EVENT and TTY-GET-KEY-EVENT use this. Somewhat odd stuff
|
|---|
| 190 | ;;; goes on here because this is the place where Hemlock waits, so this is
|
|---|
| 191 | ;;; where we redisplay, check the time for scheduled events, etc. In the loop,
|
|---|
| 192 | ;;; we call the input hook when we get a character and leave the loop. If
|
|---|
| 193 | ;;; there isn't any input, invoke any scheduled events whose time is up.
|
|---|
| 194 | ;;; Unless SERVE-EVENT returns immediately and did something, (serve-event 0),
|
|---|
| 195 | ;;; call redisplay, note that we are going into a read wait, and call
|
|---|
| 196 | ;;; SERVE-EVENT with a wait or infinite timeout. Upon exiting the loop, turn
|
|---|
| 197 | ;;; off the read wait note and check for the abort character. Return the
|
|---|
| 198 | ;;; key-event we got. We bind an error condition handler here because the
|
|---|
| 199 | ;;; default Hemlock error handler goes into a little debugging prompt loop, but
|
|---|
| 200 | ;;; if we got an error in getting input, we should prompt the user using the
|
|---|
| 201 | ;;; input method (recursively even).
|
|---|
| 202 | ;;;
|
|---|
| 203 | (eval-when (:compile-toplevel :execute)
|
|---|
| 204 |
|
|---|
| 205 | (defmacro editor-input-method-macro ()
|
|---|
| 206 | `(handler-bind
|
|---|
| 207 | ((error
|
|---|
| 208 | (lambda (condition)
|
|---|
| 209 | (when (typep condition 'stream-error)
|
|---|
| 210 | (let* ((stream (stream-error-stream condition))
|
|---|
| 211 | (display *editor-windowed-input*)
|
|---|
| 212 | (display-stream
|
|---|
| 213 | #+CLX
|
|---|
| 214 | (and display (xlib::display-input-stream display))))
|
|---|
| 215 | (when (eq stream display-stream)
|
|---|
| 216 | ;;(format *error-output* "~%Hemlock: Display died!~%~%")
|
|---|
| 217 | (cleanup-for-wm-closed-display display)
|
|---|
| 218 | (exit-hemlock nil))
|
|---|
| 219 | (let ((device
|
|---|
| 220 | (device-hunk-device (window-hunk (current-window)))))
|
|---|
| 221 | (funcall (device-exit device) device))
|
|---|
| 222 | (invoke-debugger condition)))))
|
|---|
| 223 | #+(and CLX )
|
|---|
| 224 | (xlib:closed-display
|
|---|
| 225 | (lambda(condition)
|
|---|
| 226 | (let ((display (xlib::closed-display-display condition)))
|
|---|
| 227 | (format *error-output*
|
|---|
| 228 | "Closed display on stream ~a~%"
|
|---|
| 229 | (xlib::display-input-stream display)))
|
|---|
| 230 | (exit-hemlock nil)))
|
|---|
| 231 | )
|
|---|
| 232 | ; (when *in-hemlock-stream-input-method*
|
|---|
| 233 | ; (error "Entering Hemlock stream input method recursively!"))
|
|---|
| 234 | (let ((*in-hemlock-stream-input-method* t)
|
|---|
| 235 | (nrw-fun (device-note-read-wait
|
|---|
| 236 | (device-hunk-device (window-hunk (current-window)))))
|
|---|
| 237 | key-event)
|
|---|
| 238 | (loop
|
|---|
| 239 | (when (setf key-event (dq-event stream))
|
|---|
| 240 | (dolist (f (variable-value 'hemlock::input-hook)) (funcall f))
|
|---|
| 241 | (return))
|
|---|
| 242 | (invoke-scheduled-events)
|
|---|
| 243 | (unless (or (hemlock-ext:serve-event 0)
|
|---|
| 244 | (internal-redisplay))
|
|---|
| 245 | (internal-redisplay)
|
|---|
| 246 | (when nrw-fun (funcall nrw-fun t))
|
|---|
| 247 | (let ((wait (next-scheduled-event-wait)))
|
|---|
| 248 | (if wait (hemlock-ext:serve-event wait) (hemlock-ext:serve-event)))))
|
|---|
| 249 | (when nrw-fun (funcall nrw-fun nil))
|
|---|
| 250 | (when (and (abort-key-event-p key-event)
|
|---|
| 251 | ;; ignore-abort-attempts-p must exist outside the macro.
|
|---|
| 252 | ;; in this case it is bound in GET-KEY-EVENT.
|
|---|
| 253 | (not ignore-abort-attempts-p))
|
|---|
| 254 | (beep)
|
|---|
| 255 | (throw 'editor-top-level-catcher nil))
|
|---|
| 256 | key-event)))
|
|---|
| 257 | ) ;eval-when
|
|---|
| 258 |
|
|---|
| 259 |
|
|---|
| 260 | |
|---|
| 261 |
|
|---|
| 262 | ;;;; Editor input from windowing system.
|
|---|
| 263 | #+clx
|
|---|
| 264 | (defstruct (windowed-editor-input
|
|---|
| 265 | (:include editor-input
|
|---|
| 266 | (get #'windowed-get-key-event)
|
|---|
| 267 | (unget #'windowed-unget-key-event)
|
|---|
| 268 | (listen #'windowed-listen)
|
|---|
| 269 | (clear #'windowed-clear-input))
|
|---|
| 270 | (:print-function
|
|---|
| 271 | (lambda (s stream d)
|
|---|
| 272 | (declare (ignore s d))
|
|---|
| 273 | (write-string "#<Editor-Window-Input stream>" stream)))
|
|---|
| 274 | (:constructor make-windowed-editor-input
|
|---|
| 275 | (&optional (head (make-input-event)) (tail head))))
|
|---|
| 276 | hunks) ; List of bitmap-hunks which input to this stream.
|
|---|
| 277 |
|
|---|
| 278 | #+clx
|
|---|
| 279 | ;;; There's actually no difference from the TTY case...
|
|---|
| 280 | (defun windowed-get-key-event (stream ignore-abort-attempts-p)
|
|---|
| 281 | (tty-get-key-event stream ignore-abort-attempts-p))
|
|---|
| 282 |
|
|---|
| 283 | #+clx
|
|---|
| 284 | (defun windowed-unget-key-event (key-event stream)
|
|---|
| 285 | (un-event key-event stream))
|
|---|
| 286 |
|
|---|
| 287 | #+clx
|
|---|
| 288 | (defun windowed-clear-input (stream)
|
|---|
| 289 | (loop (unless (hemlock-ext:serve-event 0) (return)))
|
|---|
| 290 | (hemlock-ext:without-interrupts
|
|---|
| 291 | (let* ((head (editor-input-head stream))
|
|---|
| 292 | (next (input-event-next head)))
|
|---|
| 293 | (when next
|
|---|
| 294 | (setf (input-event-next head) nil)
|
|---|
| 295 | (shiftf (input-event-next (editor-input-tail stream))
|
|---|
| 296 | *free-input-events* next)
|
|---|
| 297 | (setf (editor-input-tail stream) head)))))
|
|---|
| 298 |
|
|---|
| 299 | #+clx
|
|---|
| 300 | (defun windowed-listen (stream)
|
|---|
| 301 | (loop
|
|---|
| 302 | ;; Don't service anymore events if we just got some input.
|
|---|
| 303 | (when (input-event-next (editor-input-head stream))
|
|---|
| 304 | (return t))
|
|---|
| 305 | ;;
|
|---|
| 306 | ;; If nothing is pending, check the queued input.
|
|---|
| 307 | (unless (hemlock-ext:serve-event 0)
|
|---|
| 308 | (return (not (null (input-event-next (editor-input-head stream))))))))
|
|---|
| 309 |
|
|---|
| 310 | |
|---|
| 311 |
|
|---|
| 312 | ;;;; Editor input from a tty.
|
|---|
| 313 |
|
|---|
| 314 | (defstruct (tty-editor-input
|
|---|
| 315 | (:include editor-input
|
|---|
| 316 | (get #'tty-get-key-event)
|
|---|
| 317 | (unget #'tty-unget-key-event)
|
|---|
| 318 | (listen #'tty-listen)
|
|---|
| 319 | (clear #'tty-clear-input))
|
|---|
| 320 | (:print-function
|
|---|
| 321 | (lambda (obj stream n)
|
|---|
| 322 | (declare (ignore obj n))
|
|---|
| 323 | (write-string "#<Editor-Tty-Input stream>" stream)))
|
|---|
| 324 | (:constructor make-tty-editor-input
|
|---|
| 325 | (fd &optional (head (make-input-event)) (tail head))))
|
|---|
| 326 | fd)
|
|---|
| 327 |
|
|---|
| 328 | (defun tty-get-key-event (stream ignore-abort-attempts-p)
|
|---|
| 329 | (editor-input-method-macro))
|
|---|
| 330 |
|
|---|
| 331 | (defun tty-unget-key-event (key-event stream)
|
|---|
| 332 | (un-event key-event stream))
|
|---|
| 333 |
|
|---|
| 334 | (defun tty-clear-input (stream)
|
|---|
| 335 | (hemlock-ext:without-interrupts
|
|---|
| 336 | (let* ((head (editor-input-head stream))
|
|---|
| 337 | (next (input-event-next head)))
|
|---|
| 338 | (when next
|
|---|
| 339 | (setf (input-event-next head) nil)
|
|---|
| 340 | (shiftf (input-event-next (editor-input-tail stream))
|
|---|
| 341 | *free-input-events* next)
|
|---|
| 342 | (setf (editor-input-tail stream) head)))))
|
|---|
| 343 |
|
|---|
| 344 | ;;; Note that we never return NIL as long as there are events to be served with
|
|---|
| 345 | ;;; SERVE-EVENT. Thus non-keyboard input (i.e. process output)
|
|---|
| 346 | ;;; effectively causes LISTEN to block until either all the non-keyboard input
|
|---|
| 347 | ;;; has happened, or there is some real keyboard input.
|
|---|
| 348 | ;;;
|
|---|
| 349 | (defun tty-listen (stream)
|
|---|
| 350 | (loop
|
|---|
| 351 | ;; Don't service anymore events if we just got some input.
|
|---|
| 352 | (when (or (input-event-next (editor-input-head stream))
|
|---|
| 353 | (editor-tty-listen stream))
|
|---|
| 354 | (return t))
|
|---|
| 355 | ;; If nothing is pending, check the queued input.
|
|---|
| 356 | (unless (hemlock-ext:serve-event 0)
|
|---|
| 357 | (return (not (null (input-event-next (editor-input-head stream))))))))
|
|---|
| 358 |
|
|---|
| 359 | |
|---|
| 360 |
|
|---|
| 361 | ;;;; GET-KEY-EVENT, UNGET-KEY-EVENT, LISTEN-EDITOR-INPUT, CLEAR-EDITOR-INPUT.
|
|---|
| 362 |
|
|---|
| 363 | ;;; GET-KEY-EVENT -- Public.
|
|---|
| 364 | ;;;
|
|---|
| 365 | (defun get-key-event (editor-input &optional ignore-abort-attempts-p)
|
|---|
| 366 | "This function returns a key-event as soon as it is available on
|
|---|
| 367 | editor-input. Editor-input is either *editor-input* or *real-editor-input*.
|
|---|
| 368 | Ignore-abort-attempts-p indicates whether #k\"C-g\" and #k\"C-G\" throw to
|
|---|
| 369 | the editor's top-level command loop; when this is non-nil, this function
|
|---|
| 370 | returns those key-events when the user types them. Otherwise, it aborts the
|
|---|
| 371 | editor's current state, returning to the command loop."
|
|---|
| 372 | (funcall (editor-input-get editor-input) editor-input ignore-abort-attempts-p))
|
|---|
| 373 |
|
|---|
| 374 | ;;; UNGET-KEY-EVENT -- Public.
|
|---|
| 375 | ;;;
|
|---|
| 376 | (defun unget-key-event (key-event editor-input)
|
|---|
| 377 | "This function returns the key-event to editor-input, so the next invocation
|
|---|
| 378 | of GET-KEY-EVENT will return the key-event. If the key-event is #k\"C-g\"
|
|---|
| 379 | or #k\"C-G\", then whether GET-KEY-EVENT returns it depends on its second
|
|---|
| 380 | argument. Editor-input is either *editor-input* or *real-editor-input*."
|
|---|
| 381 | (funcall (editor-input-unget editor-input) key-event editor-input))
|
|---|
| 382 |
|
|---|
| 383 | ;;; CLEAR-EDITOR-INPUT -- Public.
|
|---|
| 384 | ;;;
|
|---|
| 385 | (defun clear-editor-input (editor-input)
|
|---|
| 386 | "This function flushes any pending input on editor-input. Editor-input
|
|---|
| 387 | is either *editor-input* or *real-editor-input*."
|
|---|
| 388 | (funcall (editor-input-clear editor-input) editor-input))
|
|---|
| 389 |
|
|---|
| 390 | ;;; LISTEN-EDITOR-INPUT -- Public.
|
|---|
| 391 | ;;;
|
|---|
| 392 | (defun listen-editor-input (editor-input)
|
|---|
| 393 | "This function returns whether there is any input available on editor-input.
|
|---|
| 394 | Editor-input is either *editor-input* or *real-editor-input*."
|
|---|
| 395 | (funcall (editor-input-listen editor-input) editor-input))
|
|---|
| 396 |
|
|---|
| 397 |
|
|---|
| 398 | |
|---|
| 399 |
|
|---|
| 400 | ;;;; LAST-KEY-EVENT-CURSORPOS and WINDOW-INPUT-HANDLER.
|
|---|
| 401 |
|
|---|
| 402 | ;;; LAST-KEY-EVENT-CURSORPOS -- Public
|
|---|
| 403 | ;;;
|
|---|
| 404 | ;;; Just look up the saved info in the last read key event.
|
|---|
| 405 | ;;;
|
|---|
| 406 | (defun last-key-event-cursorpos ()
|
|---|
| 407 | "Return as values, the (X, Y) character position and window where the
|
|---|
| 408 | last key event happened. If this cannot be determined, Nil is returned.
|
|---|
| 409 | If in the modeline, return a Y position of NIL and the correct X and window.
|
|---|
| 410 | Returns nil for terminal input."
|
|---|
| 411 | (let* ((ev (editor-input-head *real-editor-input*))
|
|---|
| 412 | (hunk (input-event-hunk ev))
|
|---|
| 413 | (window (and hunk (device-hunk-window hunk))))
|
|---|
| 414 | (when window
|
|---|
| 415 | (values (input-event-x ev) (input-event-y ev) window))))
|
|---|
| 416 |
|
|---|
| 417 | ;;; WINDOW-INPUT-HANDLER -- Internal
|
|---|
| 418 | ;;;
|
|---|
| 419 | ;;; This is the input-handler function for hunks that implement windows. It
|
|---|
| 420 | ;;; just queues the events on *real-editor-input*.
|
|---|
| 421 | ;;;
|
|---|
| 422 | (defun window-input-handler (hunk char x y)
|
|---|
| 423 | (q-event *real-editor-input* char x y hunk))
|
|---|
| 424 |
|
|---|
| 425 |
|
|---|
| 426 | |
|---|
| 427 |
|
|---|
| 428 | ;;;; Random typeout input routines.
|
|---|
| 429 |
|
|---|
| 430 | (defun wait-for-more (stream)
|
|---|
| 431 | (let ((key-event (more-read-key-event)))
|
|---|
| 432 | (cond ((logical-key-event-p key-event :yes))
|
|---|
| 433 | ((or (logical-key-event-p key-event :do-all)
|
|---|
| 434 | (logical-key-event-p key-event :exit))
|
|---|
| 435 | (setf (random-typeout-stream-no-prompt stream) t)
|
|---|
| 436 | (random-typeout-cleanup stream))
|
|---|
| 437 | ((logical-key-event-p key-event :keep)
|
|---|
| 438 | (setf (random-typeout-stream-no-prompt stream) t)
|
|---|
| 439 | (maybe-keep-random-typeout-window stream)
|
|---|
| 440 | (random-typeout-cleanup stream))
|
|---|
| 441 | ((logical-key-event-p key-event :no)
|
|---|
| 442 | (random-typeout-cleanup stream)
|
|---|
| 443 | (throw 'more-punt nil))
|
|---|
| 444 | (t
|
|---|
| 445 | (unget-key-event key-event *editor-input*)
|
|---|
| 446 | (random-typeout-cleanup stream)
|
|---|
| 447 | (throw 'more-punt nil)))))
|
|---|
| 448 |
|
|---|
| 449 | (declaim (special *more-prompt-action*))
|
|---|
| 450 |
|
|---|
| 451 | (defun maybe-keep-random-typeout-window (stream)
|
|---|
| 452 | (let* ((window (random-typeout-stream-window stream))
|
|---|
| 453 | (buffer (window-buffer window))
|
|---|
| 454 | (start (buffer-start-mark buffer)))
|
|---|
| 455 | (when (typep (hi::device-hunk-device (hi::window-hunk window))
|
|---|
| 456 | 'hi::bitmap-device)
|
|---|
| 457 | (let ((*more-prompt-action* :normal))
|
|---|
| 458 | (update-modeline-field buffer window :more-prompt)
|
|---|
| 459 | (random-typeout-redisplay window))
|
|---|
| 460 | (buffer-start (buffer-point buffer))
|
|---|
| 461 | (let* ((xwindow (make-xwindow-like-hwindow window))
|
|---|
| 462 | (window (make-window start :window xwindow)))
|
|---|
| 463 | (unless window
|
|---|
| 464 | #+clx(xlib:destroy-window xwindow)
|
|---|
| 465 | (editor-error "Could not create random typeout window."))))))
|
|---|
| 466 |
|
|---|
| 467 | (defun end-random-typeout (stream)
|
|---|
| 468 | (let ((*more-prompt-action* :flush)
|
|---|
| 469 | (window (random-typeout-stream-window stream)))
|
|---|
| 470 | (update-modeline-field (window-buffer window) window :more-prompt)
|
|---|
| 471 | (random-typeout-redisplay window))
|
|---|
| 472 | (unless (random-typeout-stream-no-prompt stream)
|
|---|
| 473 | (let* ((key-event (more-read-key-event))
|
|---|
| 474 | (keep-p (logical-key-event-p key-event :keep)))
|
|---|
| 475 | (when keep-p (maybe-keep-random-typeout-window stream))
|
|---|
| 476 | (random-typeout-cleanup stream)
|
|---|
| 477 | (unless (or (logical-key-event-p key-event :do-all)
|
|---|
| 478 | (logical-key-event-p key-event :exit)
|
|---|
| 479 | (logical-key-event-p key-event :no)
|
|---|
| 480 | (logical-key-event-p key-event :yes)
|
|---|
| 481 | keep-p)
|
|---|
| 482 | (unget-key-event key-event *editor-input*)))))
|
|---|
| 483 |
|
|---|
| 484 | ;;; MORE-READ-KEY-EVENT -- Internal.
|
|---|
| 485 | ;;;
|
|---|
| 486 | ;;; This gets some input from the type of stream bound to *editor-input*. Need
|
|---|
| 487 | ;;; to loop over SERVE-EVENT since it returns on any kind of event (not
|
|---|
| 488 | ;;; necessarily a key or button event).
|
|---|
| 489 | ;;;
|
|---|
| 490 | ;;; Currently this does not work for keyboard macro streams!
|
|---|
| 491 | ;;;
|
|---|
| 492 | (defun more-read-key-event ()
|
|---|
| 493 | (clear-editor-input *editor-input*)
|
|---|
| 494 | (let ((key-event (loop
|
|---|
| 495 | (let ((key-event (dq-event *editor-input*)))
|
|---|
| 496 | (when key-event (return key-event))
|
|---|
| 497 | (hemlock-ext:serve-event)))))
|
|---|
| 498 | (when (abort-key-event-p key-event)
|
|---|
| 499 | (beep)
|
|---|
| 500 | (throw 'editor-top-level-catcher nil))
|
|---|
| 501 | key-event))
|
|---|