| Incremental Redisplay | Contents | Index | Presentation Types |
22 Extended Stream Input
CLIM provides a stream-oriented input layer that is implemented on top of the
sheet input architecture. The basic CLIM input stream protocol is based on the
character input stream protocol proposal submitted to the ANSI Common Lisp
committee by David Gray. This proposal was not approved by the committee, but
has been implemented by most Lisp vendors.
22.1 Basic Input Streams
CLIM provides an implementation of the basic input stream facilities (described
in more detail in Appendix Common Lisp Streams ), either by directly using the
underlying Lisp implementation, or by implementing the facilities itself.
| standard-input-stream | [Class] |
| stream-read-char | stream | [Generic function] |
| stream-read-char-no-hang | stream | [Generic function] |
| stream-unread-char | stream character | [Generic function] |
| stream-peek-char | stream | [Generic function] |
| stream-listen | stream | [Generic function] |
| stream-read-line | stream | [Generic function] |
| stream-clear-input | stream | [Generic function] |
22.2 Extended Input Streams
In addition to the basic input stream protocol, CLIM defines an extended input
stream protocol. This protocol extends the stream model to allow manipulation
of non-character user gestures, such as pointer button presses. The extended
input protocol provides the programmer with more control over input processing,
including the options of specifying input wait timeouts and auxiliary input test
functions.
| extended-input-stream | [Protocol Class] |
| extended-input-stream-p | object | [Predicate] |
| :input-buffer | [Init arg] |
| :pointer | [Init arg] |
| :text-cursor | [Init arg] |
| standard-extended-input-stream | [Class] |
Members of this class are mutable. 22.2.1 The Extended Input Stream Protocol
The following generic functions comprise the extended input stream protocol.
All extended input streams must implement methods for these generic functions.
| stream-input-buffer | stream | [Generic function] |
| (setf stream-input-buffer) | buffer stream | [Generic function] |
| stream-pointer-position | stream &key pointer | [Generic function] |
| (setf* stream-pointer-position) | x y stream &key pointer | [Generic function] |
For CLIM implementations that do not support setf* , the ``setter'' function for this is stream-set-pointer-position .
| stream-set-input-focus | stream | [Generic function] |
| with-input-focus | (stream) &body body | [Macro] |
The stream argument is not evaluated, and must be a symbol that is bound to a stream. If stream is t , *standard-input* is used. body may have zero or more declarations as its first forms.
| *input-wait-test* | [Variable] |
| *input-wait-handler* | [Variable] |
| *pointer-button-press-handler* | [Variable] |
| read-gesture | &key (stream *standard-input* ) timeout peek-p (input-wait-test *input-wait-test* ) (input-wait-handler *input-wait-handler* ) (pointer-button-press-handler *pointer-button-press-handler* ) | [Function] |
| stream-read-gesture | stream &key timeout peek-p (input-wait-test *input-wait-test* ) (input-wait-handler *input-wait-handler* ) (pointer-button-press-handler *pointer-button-press-handler* ) | [Generic function] |
If the user types an abort gesture (that is, a gesture that matches any of the gesture names in *abort-gestures* ), then the abort-gesture condition will be signalled.
If the user types an accelerator gesture (that is, a gesture that matches any of the gesture names in *accelerator-gestures* ), then the accelerator-gesture condition will be signalled.
stream-read-gesture works by invoking stream-input-wait on stream , input-wait-test , and timeout , and then processing the input, if there is any. :around methods on this generic function can be used to implement some sort of a gesture preprocessing mechanism on every gesture; CLIM's input editor will typically be implemented this way.
timeout is either nil or an integer that specifies the number of seconds that stream-read-gesture will wait for input to become available. If no input is available, stream-read-gesture will return two values, nil and :timeout .
If the boolean peek-p is true , then the returned gesture will be left in the stream's input buffer.
input-wait-test is a function of one argument, the stream. The function should return true when there is input to process, otherwise it should return false . This argument will be passed on to stream-input-wait . stream-read-gesture will bind *input-wait-test* to input-wait-test .
input-wait-handler is a function of one argument, the stream. It is called when stream-input-wait returns false (that is, no input is available). This option can be used in conjunction with input-wait-test to handle conditions other than keyboard gestures, or to provide some sort of interactive behavior (such as highlighting applicable presentations). stream-read-gesture will bind *input-wait-handler* to input-wait-handler .
pointer-button-press-handler is a function of two arguments, the stream and a pointer button press event. It is called when the user clicks a pointer button. stream-read-gesture will bind *pointer-button-press-handler* to pointer-button-press-handler .
input-wait-test , input-wait-handler , and pointer-button-press-handler have dynamic extent.
| stream-input-wait | stream &key timeout input-wait-test | [Generic function] |
| unread-gesture | gesture &key (stream *standard-input* ) | [Function] |
| stream-unread-gesture | stream gesture | [Generic function] |
22.2.2 Extended Input Stream Conditions
| *abort-gestures* | [Variable] |
| abort-gesture | [Condition] |
| abort-gesture-event | condition | [Generic function] |
| *accelerator-gestures* | [Variable] |
| accelerator-gesture | [Condition] |
| accelerator-gesture-event | condition | [Generic function] |
| accelerator-gesture-numeric-argument | condition | [Generic function] |
22.3 Gestures and Gesture Names
A gesture is some sort of input action by the user, such as typing a
character or clicking a pointer button. A keyboard gesture refers to
those gestures that are input by typing something on the keyboard. A
pointer gesture refers to those gestures that are input by doing
something with the pointer, such as clicking a button.
A gesture name is a symbol that gives a name to a set of similar
gestures. Gesture names are used in order to provide a level of abstraction
above raw device events; greater portability can thus be achieved by avoiding
referring directly to platform-dependent constructs, such as character objects
that refer to a particular key on the keyboard. For example, the :complete gesture is used to name the gesture that causes the complete-input complete
the current input string; on Genera, this may correspond to the Complete key on
the keyboard (which generates a
Note that gesture names participate in a one-to-many mapping, that is, a single gesture name can name a group of physical gestures. For example, an :edit might include both a pointer button click and a key press.
CLIM uses event objects to represent user gestures. Some of the more common events are those of the class pointer-button-event . Event objects store the sheet associated with the event, a timestamp, and the modifier key state (a quantity that indicates which modifier keys were held down on the keyboard at the time the event occurred). Pointer button event objects also store the pointer object, the button that was clicked on the pointer, the window the pointer was over and the x and y position within that window. Keyboard gestures store the key name.
In some contexts, the object used to represent a user gesture is referred to as an gesture object . An gesture object might be exactly the same as an event object, or might contain less information. For example, for a keyboard gesture that corresponds to a standard printing character, it may be enough to represent the gesture object as a character.
| define-gesture-name | name type gesture-spec &key (unique t ) | [Macro] |
If unique is true , all old gestures named by name are first removed. unique defaults to t .
None of the arguments to define-gesture-name is evaluated.
| add-gesture-name | name type gesture-spec &key unique | [Function] |
If unique is true , all old gestures named by name are first removed. unique defaults to nil .
When type is :keyboard , gesture-spec is a list of the form (key-name . modifier-key-names) . key-name is the name of a non-modifier key on the keyboard (see below). modifier-key-names is a (possibly empty) list of modifier key names (:shift , :control , :meta , :super , and :hyper ).
For the standard Common Lisp characters (the 95 ASCII printing characters
including
The names of the modifier keys have been chosen to be uniform across all platforms, even though not all platforms will have keys on the keyboard with these names. The per-port part of a CLIM implementation must simply choose a sensible mapping from the modifier key names to the names of the keys on the keyboard. For example, a CLIM implementation on the Macintosh might map :meta to the Command shift key, and :super to the Option shift key.
When type is :pointer-button , :pointer-button-press , or :pointer-button-release , gesture-spec is a list of the form (button-name . modifier-key-names) . button is the name of a pointer button (:left , :middle , or :right ), and modifier-key-names is as above.
CLIM implementations are permitted to have other values of type as an extension, such as :pointer-motion or :timer .
As an example, the :edit gesture name above could be defined as follows using define-gesture-name :
(define-gesture-name :edit :pointer-button (:left :meta)) (define-gesture-name :edit :keyboard (#e :control))
| delete-gesture-name | name | [Function] |
| event-matches-gesture-name-p | event gesture-name | [Function] |
For pointer button events, the event matches the gesture name when the pointer button from the event matches the name of the pointer button one of the gesture specifications named by gesture-name , and the modifier key state from the event matches the names of the modifier keys in that same gesture specification.
For keyboard events, the event matches the gesture name when the key name from the event matches the key name of one of the gesture specifications named by gesture-name , and the modifier key state from the event matches the names of the modifier keys in that same gesture specification.
| modifier-state-matches-gesture-name-p | modifier-state gesture-name | [Function] |
| make-modifier-state | &rest modifiers | [Function] |
22.3.1 Standard Gesture Names
Every CLIM implementation must provide a standard set of gesture names that
correspond to a common set of gestures. These gesture names must have a
meaningful mapping for every port type.
Here are the required, standard keyboard gesture names:
| pointer | [Protocol Class] |
| pointerp | object | [Predicate] |
| :port | [Init arg] |
| standard-pointer | [Class] |
| pointer-sheet | pointer | [Generic function] |
| (setf pointer-sheet) | sheet pointer | [Generic function] |
| pointer-button-state | pointer | [Generic function] |
| pointer-position | pointer | [Generic function] |
| (setf* pointer-position) | x y pointer | [Generic function] |
For CLIM implementations that do not support setf* , the ``setter'' function for this is pointer-set-position .
| pointer-cursor | pointer | [Generic function] |
| (setf pointer-cursor) | cursor pointer | [Generic function] |
| port | (pointer standard-pointer ) | [Method] |
| tracking-pointer | (sheet &key pointer multiple-window transformp context-type highlight) &body body | [Macro] |
The pointer argument specifies a pointer to track. It defaults to the primary pointer for the sheet, (port-pointer (port sheet )) .
When the boolean multiple-windows is true , then the pointer will be tracked across multiple windows, otherwise is will be tracked only in the window corresponding to sheet .
When the boolean transformp is true , then the coordinates supplied to the :pointer-motion clause will be in the ``user'' coordinate system rather than in stream coordinates, that is, the medium's transformation will be applied to the coordinates.
context-type is used to specify the presentation type of presentations that will be ``visible'' to the tracking code for purposes of highlighting and for the :presentation , :presentation-button-press , and :presentation-button-release clauses. Supplying context-type is only useful when sheet is an output recording stream. context-type defaults to t , meaning that all presentations are visible.
When highlight is true , tracking-pointer will highlight applicable presentations as the pointer is positioned over them. highlight defaults to true when any of the :presentation , :presentation-button-press , or :presentation-button-release clauses is supplied, otherwise it defaults to false . See Chapter Output Recording for a complete discussion of presentations.
The body of tracking-pointer consists of a list of clauses. Each clause is
of the form
(clause-keyword arglist . clause-body)
and defines a local function to be run upon occurrence of each type of event.
The possible values for clause-keyword and the associated arglist are:
When both :presentation and :pointer-motion clauses are provided, the two clauses are mutually exclusive. The :presentation clause will run only if the pointer is over an applicable presentation, otherwise the :pointer-motion clause will run.
x and y are the transformed x and y positions of the pointer. These will be different from pointer-event-x and pointer-event-y if the user transformation is not the identity transformation.
When both :presentation-button-press and :pointer-button-press clauses are provided, the two clauses are mutually exclusive. The :presentation-button-press clause will run only if the pointer is over an applicable presentation, otherwise the :pointer-button-press clause will run.
x and y are the transformed x and y positions of the pointer. These will be different from pointer-event-x and pointer-event-y if the user transformation is not the identity transformation.
When both :presentation-button-release and :pointer-button-release clauses are provided, the two clauses are mutually exclusive. The :presentation-button-release clause will run only if the pointer is over an applicable presentation, otherwise the :pointer-button-release clause will run.
| drag-output-record | stream output-record &key repaint erase feedback finish-on-release multiple-window | [Generic function] |
The returned values are the final x and y position of the pointer.
The boolean repaint allows the programmer to control the appearance of windows as the pointer is dragged. If repaint is true (the default), displayed contents of windows are not disturbed as the output record is dragged over them (that is, those regions of the screen are repainted). If it is false , then no repainting is done as the output record is dragged.
erase allows the programmer to identify a function that will be called to erase the output record as it is dragged. It must be a function of two arguments, the output record to erase and the stream; it has dynamic extent. The default is erase-output-record .
feedback allows the programmer to identify a ``feedback'' function. feedback must be a is a function of seven arguments: the output record, the stream, the initial x and y position of the pointer, the current x and y position of the pointer, and a drawing argument (either :erase or :draw ). It has dynamic extent. The default is nil , meaning that the feedback behavior will be for the output record to track the pointer. (The feedback argument is used when the programmer desires more complex feedback behavior, such as drawing a ``rubber band'' line as the user moves the mouse.) Note that if feedback is supplied, erase is ignored.
If the boolean finish-on-release is false (the default), drag-output-record is exited when the user presses a pointer button. When it is true , drag-output-record is exited when the user releases the pointer button currently being held down.
multiple-window is as for tracking-pointer .
| dragging-output | (&optional stream &key repaint finish-on-release multiple-window) &body body | [Macro] |
The returned values are the final x and y position of the pointer.
The stream argument is not evaluated, and must be a symbol that is bound to an output recording stream stream. If stream is t (the default), *standard-output* is used. body may have zero or more declarations as its first forms.
repaint , finish-on-release , and multiple-window are as for drag-output-record .
| Incremental Redisplay | Contents | Index | Presentation Types |