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]
This class provides an implementation of the CLIM's basic input stream protocol based on CLIM's input kernel. It defines a handle-event method for keystroke events and queues the resulting characters in a per-stream input buffer. Members of this class are mutable.
stream-read-charstream[Generic function]
Returns the next character available in the input stream stream , or :eof if the stream is at end-of-file. If no character is available this function will wait until one becomes available.

stream-read-char-no-hangstream[Generic function]
Like stream-read-char , except that if no character is available the function returns false .

stream-unread-charstream character[Generic function]
Places the character character back into the input stream stream 's input buffer. The next call to read-char on stream will return the unread character. The character supplied must be the most recent character read from the stream.

stream-peek-charstream[Generic function]
Returns the next character available in the input stream stream . The character is not removed from the input buffer. Thus, the same character will be returned by a subsequent call to stream-read-char .

stream-listenstream[Generic function]
Returns true if there is input available on the input stream stream , false if not.

stream-read-linestream[Generic function]
Reads and returns a string containing a line of text from the input stream stream , delimited by the #\Newline character.

stream-clear-inputstream[Generic function]
Clears any buffered input associated with the input stream stream , and returns false .

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]
The protocol class for CLIM extended input streams. This is a subclass of input-stream . If you want to create a new class that behaves like an extended input stream, it should be a subclass of extended-input-stream. Subclasses of extended-input-stream must obey the extended input stream protocol.
extended-input-stream-pobject[Predicate]
Returns true if object is a CLIM extended input stream , otherwise returns false .

:input-buffer[Init arg]
:pointer[Init arg]
:text-cursor[Init arg]
All subclasses of extended-input-stream must handle these initargs, which are used to specify, respectively, the input buffer, pointer, and text cursor for the extended input stream.

standard-extended-input-stream[Class]
This class provides an implementation of the CLIM extended input stream protocol based on CLIM's input kernel. The extended input stream maintains the state of the display's pointing devices (such as a mouse) in pointer objects associated with the stream. It defines a handle-event methods for keystroke and pointer motion and button press events and updates the pointer object state and queues the resulting events in a per-stream input buffer.

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-bufferstream[Generic function]
(setf stream-input-buffer)buffer stream[Generic function]
The functions provide access to the stream's input buffer. Normally programs do not need to manipulate the input buffer directly. It is sometimes useful to cause several streams to share the same input buffer so that input that comes in on one of them is available to an input call on any of the streams. The input buffer must be vector with a fill pointer capable of holding general input gesture objects (such as characters and event objects).

stream-pointer-positionstream &key pointer[Generic function]
Returns the current position of the pointing device pointer for the extended input stream stream as two values, the x and y positions in the stream's drawing surface coordinate system. If pointer is not supplied, it defaults to port-pointer of the stream's port.

(setf* stream-pointer-position)x y stream &key pointer[Generic function]
Sets the position of the pointing device for the extended input stream stream to x and y , which are integers. pointer is as for stream-pointer-position .

For CLIM implementations that do not support setf* , the ``setter'' function for this is stream-set-pointer-position .

stream-set-input-focusstream[Generic function]
Sets the ``input focus'' to the extended input stream stream by changing the value of port-keyboard-input-focus and returns the old input focus as its value.

with-input-focus(stream) &body body[Macro]
Temporarily gives the keyboard input focus to the extended input stream stream . By default, an application frame gives the input focus to the window associated with frame-query-io .

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]
These three variables are used to hold the default values for the current input wait test, wait handler, and pointer button press handler. These variables are globally bound to nil .

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]
Calls stream-read-gesture on the extended input stream stream and all of the other keyword arguments. These arguments are the same as for stream-read-gesture .

stream-read-gesturestream &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]
Returns the next gesture available in the extended input stream stream ; the gesture will be either a character or an event (such as a pointer button event). The input is not echoed.

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-waitstream &key timeout input-wait-test[Generic function]
Waits for input to become available on the extended input stream stream . timeout and input-wait-test are as for stream-read-gesture .

unread-gesturegesture &key (stream *standard-input* )[Function]
Calls stream-unread-gesture on gesture and stream . These arguments are the same as for stream-unread-gesture .

stream-unread-gesturestream gesture[Generic function]
Places gesture back into the extended input stream stream 's input buffer. The next call to stream-read-gesture request will return the unread gesture. The gesture supplied must be the most recent gesture read from the stream via read-gesture .

22.2.2 Extended Input Stream Conditions

*abort-gestures*[Variable]
A list of all of the gesture names that correspond to abort gestures. The exact global set of standard abort gestures is unspecified, but must include the :abort gesture name.

abort-gesture[Condition]
This condition is signalled by read-gesture whenever an abort gesture (one of the gestures in *abort-gestures* is read from the user. This condition will handle the :event initarg, which is used to supply the event corresponding to the abort gesture.

abort-gesture-eventcondition[Generic function]
Returns the event that cause the abort gesture condition to be signalled. condition is an object of type abort-gesture .

*accelerator-gestures*[Variable]
A list of all of the gesture names that correspond to keystroke accelerators. The global value for this is nil .

accelerator-gesture[Condition]
This condition is signalled by read-gesture whenever an keystroke accelerator gesture (one of the gestures in *accelerator-gestures* is read from the user. This condition will handle the :event and the :numeric-argument initargs, which are used to supply the event corresponding to the abort gesture and the accumulated numeric argument (which defaults to 1).

accelerator-gesture-eventcondition[Generic function]
Returns the event that caused the accelerator gesture condition to be signalled. condition is an object of type accelerator-gesture .

accelerator-gesture-numeric-argumentcondition[Generic function]
Returns the accumlated numeric argument (maintained by the input editor) at the time the accelerator gesture condition was signalled. condition is an object of type accelerator-gesture .

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 #\Complete character), but on a Unix workstation, it may correspond to some other key. Another example is :select , which is commonly used to indicate a left button click on the pointer.

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-namename type gesture-spec &key (unique t )[Macro]
Defines a new gesture named by the symbol name . type is the type of gesture being created, and must be one of the symbols described below. gesture-spec specifies the physical gesture that corresponds to the named gesture; its syntax depends on the value of type . define-gesture-name must expand into a call to add-gesture-name .

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-namename type gesture-spec &key unique[Function]
Adds a gesture named by the symbol name to the set of gesture names. type is the type of gesture being created, and must be one of the symbols described below. gesture-spec specifies the physical gesture that corresponds to the named gesture; its syntax depends on the value of type .

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 #\Space), key-name is the character object itself. For the other ``semi-standard'' characters, key-name is a keyword symbol naming the character (:newline , :linefeed , :return , :tab , :backspace , :page , and :rubout ). CLIM implementations may extend the set of key names on a per-port basic, but should choose a port-specific package. For example, the Genera port might such gestures as include genera-clim:help and genera-clim:complete .

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-namename[Function]
Removes the gesture named by the symbol name .

event-matches-gesture-name-pevent gesture-name[Function]
Returns true if the device event event ``matches'' the gesture named by gesture-name .

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-pmodifier-state gesture-name[Function]
Returns true if the modifier key state from the device event event matches the names of the modifier keys in one of the gesture specifications named by gesture-name .


Issue: SWM
Note that none of the functions above take a port argument. This is because CLIM implicitly assumes that the canonical set of gesture names is the same on every port, and only the mappings differ from port to port. Some ports may define additional gesture names, but they will simply not be mapped on other ports. Is this a reasonable assumption?
make-modifier-state&rest modifiers[Function]
Given a list of modifier state names, this creates an integer that serves as a modifier key state. The legal modifier state names are :shift , :control , :meta , :super , and :hyper .

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:

Here are the required, standard pointer gesture names:

22.4 The Pointer Protocol

pointer[Protocol Class]
The protocol class that corresponds to a pointing device. If you want to create a new class that behaves like a pointer, it should be a subclass of pointer. Subclasses of pointer must obey the pointer protocol.Members of this class are mutable.
pointerpobject[Predicate]
Returns true if object is a pointer , otherwise returns false .

:port[Init arg]
The :port initarg is used to specify the port with which the pointer is associated.

standard-pointer[Class]
The instantiable class that implements a pointer.

pointer-sheetpointer[Generic function]
(setf pointer-sheet)sheet pointer[Generic function]
Returns (or sets) the sheet over which the pointer pointer is located.

pointer-button-statepointer[Generic function]
Returns the current state of the buttons of the pointer pointer as an integer. This will be a mask consisting of the logior of +pointer-left-button+ , +pointer-middle-button+ , and +pointer-right-button+ .

pointer-positionpointer[Generic function]
Returns the x and y position of the pointer pointer as two values.

(setf* pointer-position)x y pointer[Generic function]
Sets the x and y position of the pointer pointer to the specified position.

For CLIM implementations that do not support setf* , the ``setter'' function for this is pointer-set-position .

pointer-cursorpointer[Generic function]
(setf pointer-cursor)cursor pointer[Generic function]
A pointer object usually has a visible cursor associated with it. These functions return (or set) the cursor associated with the pointer pointer .

port(pointer standard-pointer )[Method]
Returns the port with which pointer is associated.

22.5 Pointer Tracking

tracking-pointer(sheet &key pointer multiple-window transformp context-type highlight) &body body[Macro]
The tracking-pointer macro provides a general means for running code while following the position of a pointing device, and monitoring for other input events. The programmer supplies code (the clauses in body ) to be run upon the occurrence of any of the following types of events:

The sheet argument is not evaluated, and must be a symbol that is bound to an input sheet or stream. If sheet is t , *standard-output* is used. body may have zero or more declarations as its first forms.

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:

drag-output-recordstream output-record &key repaint erase feedback finish-on-release multiple-window[Generic function]
Enters an interaction mode in which the user moves the pointer and output-record ``follows'' the pointer by being dragged on the output recording stream stream . By default, the dragging is accomplished by erasing the output record from its previous position and redrawing at the new position. output-record remains in the output history of stream at its final position.

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]
Evaluates body inside of with-output-to-output-record to produce an output record for the stream stream , and then invokes drag-output-record on the record in order to drag the output. The output record is not inserted into stream 's output history.

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