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 as follows:
(contain
(make-instance
'output-pane
:input-model '(((:motion :button-1)
gp:draw-point))))
Figure 12.3 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 Output pane examples.
For the full input-model syntax, see 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 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 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:
sys:gesture-spec-shift-bit
sys:gesture-spec-control-bit
sys:gesture-spec-meta-bit
sys:gesture-spec-hyper-bit
sys:gesture-spec-caps-lock-bit
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.
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,
action
is one of :press
or :release
and each modifier is one of the keywords :shift
, :control
and :meta
. The callback will receive a Gesture Spec object, 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:
(:button-3 :release)
on Microsoft Windows.
(:button-1 :press :control)
on Mac OS X.
(:button-3 :press :control)
on Microsoft Windows, Motif and Mac OS X.
(:gesture-spec :f10 :shift)
on Microsoft Windows, Motif and Mac OS X.
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:
The callback receives an extra argument which is the zoom factor.
The callback receives an extra argument which is the angle to rotate, anti-clockwise in radians.
The callback receives two extra arguments, the delta-x and delta-y , which are the amount to scroll in the x and y directions.
The callback receives an extra argument which is one of the keywords :left
, :right
, :up
or :down
.
:swipe
is supported only on Cocoa.
The callback receives an extra argument which is the distance between the fingers.
:two-finger-tap
is supported only on Windows.
The callback receives two extra arguments, which are the delta-x and delta-y of the tapping finger from the resting finger.
:press-and-tap
is supported only on Windows.
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:
where ( x , y ) is the cursor position.
The following gestures have a fourth argument:
A gesture-spec representing the user input.
A character representing the user input.
An integer specifying the modifiers as logior of sys:gesture-spec-*-bit
.
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 (Macintosh version) - 3 Aug 2017