The CAPI supports receiving input from the user through the use of an input model, which is a mapping of events to the callbacks that should be run when they occur. The input model is specified by the initarg :input-model
.
When the event callback is called, it gets passed the output-pane and the x and y integer coordinates of the mouse pointer at the time of the event. A few events also pass additional information as necessary; for example, keyboard events also pass the key that was pressed.
For example, we can create a very simple drawing pane by adding a callback to draw a point whenever the left button is dragged across the pane. This is done using the function draw-point as follows:
(defun display-a-message (pane x y) (display-message-for-pane pane "clicked at ~d/~d" x y)) (contain (make-instance 'output-pane :input-model '(((:button-1 :press) display-a-message))))
An interactive output pane
The input model above seems quite complicated, but it is just a list of event to callback mappings, where each one of these mappings is a list containing an event specification and a callback. An event specification is also a list containing keywords specifying the type of event required.
There is an example input model in:
(example-edit-file "capi/graphics/pinboard-test")
and more examples are listed in 20.1 Output pane examples.
For the full input-model syntax, see 12.2.1 Detailed description of the input model.
The input model provides a means to get callbacks on mouse, keyboard and touch gestures in an output-pane. An input-model is a list of mappings from gesture to callback, where each mapping is a list:
(gesture callback . extra-callback-args)
gesture specifies the type of gesture, which can be Gesture Spec, character, button, modifier change, key, command, cursor motion or multi-touch. These are described in the following sections. User input is processed as described in 12.2.1.10 Processing user input.
Note: it is recommended you follow the style guidelines and conventions of the platform you are targeting when mapping gestures to callbacks.
In a Gesture Spec mapping, gesture can be simply the keyword :gesture-spec
, which matches any keyboard input. For specific mappings, gesture is a list:
(:gesture-spec data [modifier]*)
in which data is a character object or an integer between 0 and char-code-limit (interpreted as the character object obtained by code-char), or a keyword naming a function key, and each modifier is one of the keywords :shift
, :control
and :meta
. Note that the modifier :meta
is received only when the keys style is :emacs
(see interface-keys-style).
Also data can be a string which is interpreted as a Gesture Spec as if by sys:coerce-to-gesture-spec. See the LispWorks® User Guide and Reference Manual for a description of this and other functions for manipulating Gesture Spec objects.
Note: on Cocoa you cannot receive Command
key gestures via Gesture Spec mapping in input-model. To receive Command
key gestures you should add corresponding menu items with accelerators. See menu-item for information about accelerators.
In a character mapping, gesture can be simply the keyword :character
, which matches any character input. For specific mappings, gesture can be a list containing a single character object char, or a list:
(char)
Note: where input would match both a Gesture Spec mapping and a character mapping, the Gesture Spec mapping takes precedence.
Note: in LispWorks 7.0 and later versions the cl:character type does not support the bits attribute. To represent keyboard input with modifier keys, see 12.2.1.1 Gesture Spec mappings.
In a button mapping, gesture should be list:
(button action [modifiers]*)
where button is one of :button-1
, :button-2
or :button-3
denoting the mouse buttons. action is one of :press
, :release
, :second-press
, :third-press
, :nth-press
and :motion
, and each modifier is one of the keywords :shift
, :control
, :meta
and :hyper
. The :meta
modifier will be the Alt
key on most keyboards. On Cocoa, the :hyper
modifier is interpreted as the Command
key for button and motion gestures. On Windows, the :hyper
modifier is currently never generated, so gesture mappings using it will never be invoked.:third-press
and :nth-press
are supported only on Cocoa and Motif.
Button mappings with action :nth-press
are matched on the nth button click made in quick succession, but only when there is not a more specific match with :press
, :second-press
or :third-press
. The callback for :nth-press
receives an extra argument which is the count of clicks.
In a modifier change mapping, gesture is :modifier-change
, which generates a callback whenever the state of a modifier (Control
, Shift
and Meta
key, Command
on Cocoa, and Caps Lock
) changes.
The callback is called with the output pane, x and y, an integer mods, followed by extra-callback-args if any. mods is calculated as a logior of sys:gesture-*
-bit values. The bits that that may be set in mods are:
Note that sys:gesture-spec-hyper-bit is set when Command
is pressed.
Note that for Caps Lock, the callback is generated when the state of the Caps Lock changes, not when the Caps Lock
key is pressed or released.
The pane gets the callback only when it has the focus. If the pane receives the focus and the state of the modifiers is different from what it was the last time the pane had the focus, a callback is generated at that time. That means that tracking the state using the callback is reliable while the pane has the focus, but not while the pane does not have the focus.
For an example, see:
(example-edit-file "capi/output-panes/modifier-change")
Key mappings are intended for detecting low-level keyboard input. In a key mapping, gesture should be a list:
(:key [keyname] action [modifiers]*)
where the optional keyname is a character naming a key (no modifiers) or one of the valid Gesture Spec keywords documented in the entry for sys:make-gesture-spec, action is one of :press
or :release
and each modifier is one of the keywords :shift
, :control
and :meta
. The callback will receive a sys:gesture-spec, with its data set to an integer ASCII code or a keyword representing the primary item on the key and its modifiers representing the set of modifiers pressed. The :meta
modifier will be the Alt
key on most keyboards. On Cocoa, the :hyper
modifier is interpreted as the Command
key for :key
input.
In a motion mapping, gesture can either be defined in terms of dragging a button (in which case it is defined as a button gesture with action :motion
), or it can be defined for motions while no button is down by just specifying the keyword :motion
with no additional arguments.
In a command mapping, gesture should be a command which is defined using define-command, and provides an alias for a gesture. The following commands are predefined:
:post-menu |
|
:control-post-menu |
|
:keyboard-post-menu | |
|
On Cocoa and Windows input-model can contain mappings for multi-touch gestures from devices that can generate them (trackpad or touchscreen). These include zoom, rotate, pan, swipe (Cocoa only), two finger tap (Windows only), press and tap (Windows only), and beginning and end of sequences of gestures.
In a touch mapping gesture should be of the form:
(:touch multi-touch-keyword)
where multi-touch-keyword specifies the type of gesture as listed below. For all multi-touch gestures the callback receives as arguments the pane, and the x and y of the event. There are also an additional one or two arguments for each specific gesture. The extra arguments are always relative to the previous state, so each event can be interpreted on each own. Use extra-callback-args if any are added in the end.
multi-touch-keyword should be one of:
:zoom |
The callback receives an extra argument which is the zoom factor. |
:rotate |
The callback receives an extra argument which is the angle to rotate, anti-clockwise in radians. |
:pan |
The callback receives two extra arguments, the delta-x and delta-y, which are the amount to scroll in the x and y directions. |
:swipe |
The callback receives an extra argument which is one of the keywords
|
:two-finger-tap | The callback receives an extra argument which is the distance between the fingers.
|
:press-and-tap | The callback receives two extra arguments, which are the delta-x and delta-y of the tapping finger from the resting finger.
|
:begin-end |
The callback receives an extra argument begin-p which is a boolean, t for beginning of a sequence of events and nil for end. The beginning and end of sequences are determined by the underlying device implementation, which tries to identify what the user regards as a single operation. |
Because the callbacks receive relative values, you do not need the :begin-end
events to interpret them. These events are useful when you want to do things which correspond to user operations, for example recording a state for undo or committing a change.
They are also useful if you want to restrict the type of events that are processed inside each operation. For example, your pane may have a flag that the callbacks check and set which is used to allow only one kind of gesture to have an effect in each sequence.
The x and y coordinates are the coordinates which should be used as the center of operation. On Windows, you can track the x and y in :zoom
and :rotate
events, and do panning while rotating or zooming.
On Cocoa, a sequence of events (starting and ending with :begin-end
events) can contain either :zoom
and :rotate
events or :pan
events, but not a mixture of :pan
and :rotate
or :zoom
. On Windows all these three types of events can be mixed in principle.
:swipe
events (Cocoa only) are three finger brushing. :swipe
events are always on their own, and are not enclosed in pairs of :begin-end
callbacks.
On Cocoa, pan should generally act as a scrolling gesture, so normally you should not need to use it.
Windows touch events are described in the MSDN in:
Dev Center - Desktop > Design > Guidelines > Guidelines > Interaction > Touch
http://msdn.microsoft.com/en-us/library/windows/desktop/dn742468(v=vs.85).aspx.
Note that on Windows the Control+Mousewheel
gesture generates :zoom
events and Shift+Mousewheel
generates :rotate
.
The entries in the input-model look like this:
((:touch :zoom) my-zoom-callback)
((:touch :pan) my-pan-callback)
((:touch :rotate) my-rotate-callback)
((:touch :begin-end) my-begin-end-callback)
#+macosx ((:touch :swipe) my-swipe-callback))
#+mswindows ((:touch :two-finger-tap) my-two-finger-tap-callback)
#+mswindows ((:touch :press-and-tap) my-press-and-tap-callback)
The corresponding callbacks have these signatures:
my-zoom-callback pane x y zoom-factor
my-pan-callback pane x y delta-x delta-y
my-rotate-callback pane x y delta-angle
my-begin-end-callback pane x y begin-p
my-swipe-callback pane x y direction-keyword
my-two-finger-tap-callback pane x y distance
my-press-and-tap-callback pane x y distance-x distance-y
When user input matches a gesture gesture, the callback is called with the gesture callback arguments followed by any user-supplied extra-callback-args.
The gesture callback arguments contain three standard arguments, and for some gestures there is a fourth argument. The standard three arguments are:
output-pane x y
where (x, y) is the cursor position.
The following gestures have a fourth argument:
:gesture-spec or :key | |
A sys:gesture-spec representing the user input. | |
:character or character | |
A character representing the user input. | |
:modifier-change | An integer specifying the modifiers as a logior of the constants sys:gesture-spec-shift-bit etc. |
Button with :nth-press | |
An integer which is the number of clicks. |
Note: mouse gestures with :press
, :second-press
, :third-press
and :nth-press
actions can each be expected to be followed by a :release
action.
Note: In some circumstances :motion
events can be received even when the output-pane does not have the input focus. See window style :motion-events-without-focus
under interface for details.
input-model can be set before the pane is displayed, but changes after that are ignored.
In particular, cl:initialize-instance is the natural place for subclasses to modify the existing input-model, using the output-pane accessor output-pane-input-model. Note that since the mappings are processed in order, prepending to an existing input-model overrides it when there are clashes, while appending affects only gestures for which the original input-model did not have a match.
It is possible to define aliases for gestures (called "commands"), which is mapping between a gesture and a command (a unique Lisp object, typically a keyword). The command then can be used as the gesture in an input-model. That allows changing the actual user gesture to invoke the callbacks that are associated with the command in input models of many panes, without having to change the actual input model specifications.
A command is defined using define-command, which defines the mapping, and can also specify on which library it is applicable and a translator to change the arguments that are passed to the callback.
Commands that are defined by define-command can be programmatically invoked (as if the user entered the gesture) by invoke-command or invoke-untranslated-command.
The input that CAPI sees may be pre-processed by a native input method. Native input methods are part of the underlying GUI system which allow the user to enter characters that do not appear on the keyboard. On GTK+ you can control whether the native input method is used by the output-pane initarg :use-native-input-method
, and you can specify the default by set-default-use-native-input-method.
Composition of characters is done by the underlying window system, which combines several keystrokes to one character (or more rarely, to several characters) , and is used to input characters that are not available on the keyboard. output-pane has a callback, :composition-callback
, which is called when composition starts and ends, and also if the pane is supposed to display the input, it is called to tell it what to display.
Inside the callback call for starting composition, the function set-composition-placement where relative to the composition should, which tells the system where to put any window that it popups to interact the user. For example, editor-pane uses this to set the placement at the position of the cursor.
CAPI User Guide and Reference Manual (Unix version) - 01 Dec 2021 19:32:39