1#lang scribble/doc
2@(require "common.rkt")
3
4@defclass/title[keymap% object% ()]{
5
6A @racket[keymap%] object is used by @racket[editor<%>] objects to
7 map keyboard and mouse sequences to arbitrary functions in an
8 extensible way. Keymaps can be used without editors, as well.  A
9 @racket[keymap%] object contains
10
11@itemize[
12
13 @item{a mapping from function names to event-handling procedures; and}
14
15 @item{a mapping from key and mouse sequences to function names.}
16
17]
18
19A handler procedure in a keymap is invoked with a @racket[key-event%]
20 object or a @racket[mouse-event%] object. It is also given another
21 value that depends on the context in which the keymap is used (or,
22 more specifically, the arguments to @method[keymap% handle-key-event]
23 or @method[keymap% handle-mouse-event]). For keymaps associated with
24 @racket[editor<%>] objects, the extra parameter is generally the
25 @racket[editor<%>] object that received the keyboard or mouse event.
26
27
28@defconstructor[()]{
29
30Creates an empty keymap.
31
32}
33
34@defmethod[(add-function [name string?]
35                         [func (any/c (is-a?/c event%) . -> . any)])
36           void?]{
37
38Names a new function to handle events, called in response to
39 @method[keymap% handle-key-event], @method[keymap%
40 handle-mouse-event], or @method[keymap% call-function]. The return
41 value is of the procedure is ignored.
42
43If there was already a function mapped to this name, it will be
44 replaced with the given function.
45
46When the function is called, it gets the arguments that were passed to
47 @method[keymap% handle-key-event], @method[keymap%
48 handle-mouse-event], or @method[keymap% call-function]. For keymaps
49 associated with an editor, this is normally the target editor.
50
51}
52
53@defmethod[(is-function-added? [fname string?]) boolean?]{
54  Returns @racket[#t] if @racket[fname] has been added
55          via @method[add-function keymap%] to this keymap
56          and @racket[#f] otherwise.
57
58  This method doesn't check chained keymaps to see if the function
59  has been added to one of those.
60}
61
62@defmethod[(break-sequence)
63           void?]{
64
65Clears the state of the keymap if it is in the middle of a key
66 sequence. For example, the user may have hit escape, and then changed
67 to another window; if escape is part of a keyboard sequence, the
68 keymap state needs to be cleared because the user is not going to
69 complete the sequence.
70
71A break callback function can be installed with @method[keymap%
72 set-break-sequence-callback].
73
74}
75
76@defmethod[(call-function [name string?]
77                          [in any/c]
78                          [event (is-a?/c event%)]
79                          [try-chain? any/c #f])
80           boolean?]{
81
82Calls a named event handler directly. If the function cannot be found
83 or the found handler did not want to handle the event, @racket[#f] is
84 returned. Otherwise, the return value is the boolean return value of
85 the event handler.
86
87The @racket[in] and @racket[event] arguments are passed on to the keymap
88 handler procedure if one is found.
89
90If @racket[try-chain?] is not @racket[#f], keymaps chained to this one
91 are searched for the function name.  If the function is not found and
92 @racket[try-chain?] is @racket[#f]; an exception is also raised, but
93 the exception handler cannot escape (see
94 @secref["evtcontjump"]).
95
96}
97
98
99@defmethod[(chain-to-keymap [next (is-a?/c keymap%)]
100                            [prefix? any/c])
101           void?]{
102
103Chains @racket[next] off @this-obj[] The @racket[next] keymap will be
104 used to handle events which are not handled by @this-obj[].
105
106If @racket[prefix?] is a true value, then @racket[next] will take
107 precedence over other keymaps already chained to @this-obj[] in the
108 case that both keymaps map the same key sequence.
109 When one chained keymap maps a key that is a prefix of another, then the
110 shorter key sequence is always used, regardless of @racket[prefix?].
111
112Multiple keymaps can be chained off one keymap using @method[keymap%
113 chain-to-keymap]. When keymaps are chained off a main keymap, events
114 not handled by the main keymap are passed to the chained keymaps
115 until some chained keymap handles the events.  Keymaps can be chained
116 together in an arbitrary acyclic graph.
117
118Keymap chaining is useful because multiple-event sequences are handled
119 correctly for chained groups. Without chaining, a sequence of events
120 can produce state in a keymap that must be reset when a callback is
121 invoked in one of the keymaps. This state can be manually cleared
122 with @method[keymap% break-sequence], though calling the
123 @method[keymap% break-sequence] method also invokes the handler
124 installed by @method[keymap% set-break-sequence-callback].
125
126}
127
128
129@defmethod[(get-double-click-interval)
130           (integer-in 0 1000000)]{
131
132Returns the maximum number of milliseconds that can separate the
133 clicks of a double-click.
134
135The default interval is determined in a platform-specific way, but it
136 can be overridden globally though the
137 @ResourceFirst{doubleClickTime}; see @|mrprefsdiscuss|.
138
139}
140
141@defmethod[(handle-key-event [in any/c]
142                             [event (is-a?/c key-event%)])
143           boolean?]{
144
145Attempts to handle a keyboard event, returning @racket[#t] if the event
146 was handled (i.e., a handler was found and it returned a true value),
147 @racket[#f] otherwise.
148
149See also @method[keymap% call-function].
150
151}
152
153
154@defmethod[(handle-mouse-event [in any/c]
155                               [event (is-a?/c mouse-event%)])
156           boolean?]{
157
158Attempts to handle a mouse event, returning @racket[#t] if the event
159 was handled (i.e., a handler was found and it returned a true value),
160 @racket[#f] otherwise.
161
162See also @method[keymap% call-function].
163
164}
165
166
167@defmethod[(map-function [keyname string?]
168                         [fname string?])
169           void?]{
170
171Maps an input state sequence to a function name using a string-encoded
172 sequence in @racket[keyname]. The format of @racket[keyname] is a
173 sequence of semicolon-delimited input states; each state is made up
174 of a sequence of modifier identifiers followed by a key identifier.
175
176The modifier identifiers are:
177
178@itemize[
179
180 @item{@litchar{s:} --- All platforms: Shift}
181
182 @item{@litchar{c:} --- All platforms: Control}
183
184 @item{@litchar{a:} --- Mac OS: Option}
185
186 @item{@litchar{m:} --- Windows: Alt; Unix: Meta; Mac OS: Command, when
187 @racket[map-command-as-meta-key] produces @racket[#t]}
188
189 @item{@litchar{d:} --- Mac OS: Command}
190
191 @item{@litchar{l:} --- All platforms: Caps Lock}
192
193 @item{@litchar{g:} --- Windows: Control plus Alt as AltGr;
194                        see @xmethod[key-event% get-control+meta-is-altgr]}
195
196 @item{@litchar{?:} --- All platforms: allow match to character produced by opposite
197                  use of Shift, AltGr/Option, and/or Caps Lock, when available; see
198                  @xmethod[key-event% get-other-shift-key-code]}
199]
200
201If a particular modifier is not mentioned in a state string, it
202 matches states whether that modifier is pressed or not pressed. A
203 @litchar{~} preceding a modifier makes the string match only states
204 where the corresponding modifier is not pressed. If the state string
205 begins with @litchar{:}, then the string matches a state only if
206 modifiers among Shift, Control, Option, Alt, Meta, and Command that are
207 not mentioned in the string are not pressed.
208
209A key identifier can be either a character on the keyboard (e.g.,
210 @litchar{a}, @litchar{2}, @litchar{?}) or a special name. The
211 special names are as follows:
212
213@itemize[
214#:style 'compact
215@item{@litchar{leftbutton} (button down)}
216@item{@litchar{rightbutton}}
217@item{@litchar{middlebutton}}
218@item{@litchar{leftbuttondouble} (button down for double-click)}
219@item{@litchar{rightbuttondouble}}
220@item{@litchar{middlebuttondouble}}
221@item{@litchar{leftbuttontriple} (button down for triple-click)}
222@item{@litchar{rightbuttontriple}}
223@item{@litchar{middlebuttontriple}}
224@item{@litchar{leftbuttonseq} (all events from button down through button up)}
225@item{@litchar{rightbuttonseq}}
226@item{@litchar{middlebuttonseq}}
227@item{@litchar{wheelup}}
228@item{@litchar{wheeldown}}
229@item{@litchar{wheelleft}}
230@item{@litchar{wheelright}}
231@item{@litchar{esc}}
232@item{@litchar{delete}}
233@item{@litchar{del}  (same as @litchar{delete})}
234@item{@litchar{insert}}
235@item{@litchar{ins} (same as @litchar{insert})}
236@item{@litchar{add}}
237@item{@litchar{subtract}}
238@item{@litchar{multiply}}
239@item{@litchar{divide}}
240@item{@litchar{backspace}}
241@item{@litchar{back}}
242@item{@litchar{return}}
243@item{@litchar{enter} (same as @litchar{return})}
244@item{@litchar{tab}}
245@item{@litchar{space}}
246@item{@litchar{right}}
247@item{@litchar{left}}
248@item{@litchar{up}}
249@item{@litchar{down}}
250@item{@litchar{home}}
251@item{@litchar{end}}
252@item{@litchar{pageup}}
253@item{@litchar{pagedown}}
254@item{@litchar{semicolon} (since @litchar{;} separates sequence steps)}
255@item{@litchar{colon}  (since @litchar{:} separates modifiers)}
256@item{@litchar{numpad0}}
257@item{@litchar{numpad1}}
258@item{@litchar{numpad2}}
259@item{@litchar{numpad3}}
260@item{@litchar{numpad4}}
261@item{@litchar{numpad5}}
262@item{@litchar{numpad6}}
263@item{@litchar{numpad7}}
264@item{@litchar{numpad8}}
265@item{@litchar{numpad9}}
266@item{@litchar{numpadenter}}
267@item{@litchar{f1}}
268@item{@litchar{f2}}
269@item{@litchar{f3}}
270@item{@litchar{f4}}
271@item{@litchar{f5}}
272@item{@litchar{f6}}
273@item{@litchar{f7}}
274@item{@litchar{f8}}
275@item{@litchar{f9}}
276@item{@litchar{f10}}
277@item{@litchar{f11}}
278@item{@litchar{f12}}
279@item{@litchar{f13}}
280@item{@litchar{f14}}
281@item{@litchar{f15}}
282@item{@litchar{f16}}
283@item{@litchar{f17}}
284@item{@litchar{f18}}
285@item{@litchar{f19}}
286@item{@litchar{f20}}
287@item{@litchar{f21}}
288@item{@litchar{f22}}
289@item{@litchar{f23}}
290@item{@litchar{f24}}
291]
292
293For a special keyword, the capitalization does not matter. However,
294 capitalization is important for single-letter keynames. Furthermore,
295 single-letter ASCII keynames are treated specially: @litchar{A} and
296 @litchar{s:a} are both treated as @litchar{s:A}.  However, when
297 @litchar{c:} is included on Windows without @litchar{m:}, or when
298 @litchar{d:} is included on Mac OS, then ASCII letters are not
299 upcased with @litchar{s:}, since the upcasing behavior of the Shift key
300 is cancelled by Control without Alt (on Windows) or by Command
301 (on Mac OS).
302
303A state can match multiple state strings mapped in a keymap (or keymap
304 chain); when a state matches multiple state strings, a mapping is
305 selected by ranking the strings according to specificity. A state
306 string that mentions more pressed modifiers ranks higher than other
307 state strings, and if two strings mention the same number of pressed
308 modifiers, the one that mentions more unpressed modifiers ranks
309 higher. Finally, a state string that includes @litchar{?:} and
310 matches only with the opposite use of Shift, AltGr/Option, and/or
311 Caps Lock ranks below all matches that do not depend on @litchar{?:},
312 and one that requires the opposite use of both Shift and AltGr/Option
313 ranks even lower. In the case that multiple matching strings have the
314 same rank, a match is selected arbitrarily.
315
316Examples:
317
318@itemize[
319
320 @item{@racket["space"] --- matches whenever the space bar is pressed,
321 regardless of the state of modifiers keys.}
322
323 @item{@racket["~c:space"] --- matches whenever the space bar is pressed
324 and the Control key is not pressed.}
325
326 @item{@racket["a"] --- matches whenever @litchar{a} is typed, regardless of
327 the state of modifiers keys (other than Shift).}
328
329 @item{@racket[":a"] --- matches only when @litchar{a} is typed with no
330 modifier keys pressed.}
331
332 @item{@racket["~c:a"] --- matches whenever @litchar{a} is typed and neither
333 the Shift key nor the Control key is pressed.}
334
335 @item{@racket["c:m:~g:x"] --- matches whenever @litchar{x} is typed
336 with Control and Alt (Windows) or Meta (Unix) is pressed, as long as
337 the Control-Alt combination is not formed by AltGr on Windows.}
338
339 @item{@racket[":esc;:c:c"] --- matches an Escape key press (no
340 modifiers) followed by a Control-C press (no modifiers other than
341 Control).}
342
343 @item{@racket["?:d:+"] --- matches when Command is pressed with key
344  that produces @litchar{+}, even if producing @litchar{+} normally requires
345  pressing Shift.}
346
347]
348
349A call to @method[keymap% map-function] that would map a particular
350 key sequence both as a prefix and as a complete sequence raises an
351 exception, but the exception handler cannot escape (see
352 @secref["evtcontjump"]).
353
354A function name does not have to be mapped to a handler before input
355 states are mapped to the name; the handler is dispatched by name at
356 the time of invocation. The event handler mapped to a function name
357 can be changed without affecting the map from input states to
358 function names.
359
360
361@history[#:changed "1.2" @elem{Added @litchar{g:} and @litchar{~g:} support.}]}
362
363
364@defmethod[(remove-chained-keymap [keymap (is-a?/c keymap%)])
365           void?]{
366
367If @racket[keymap] was previously chained from this keymap (through
368 @method[keymap% chain-to-keymap]), then it is removed from the
369 chain-to list.
370
371}
372
373
374@defmethod[(remove-grab-key-function)
375           void?]{
376
377Removes a callback installed with @method[keymap%
378 set-grab-key-function].
379
380}
381
382@defmethod[(remove-grab-mouse-function)
383           void?]{
384
385Removes a callback installed with @method[keymap%
386 set-grab-mouse-function].
387
388}
389
390
391@defmethod[(set-break-sequence-callback [f (-> any)])
392           void?]{
393
394Installs a callback procedure that is invoked when @method[keymap%
395 break-sequence] is called. After it is invoked once, the callback is
396 removed from the keymap. If another callback is installed before
397 @method[keymap% break-sequence] is called, the old callback is
398 invoked immediately before the new one is installed.
399
400}
401
402
403@defmethod[(set-double-click-interval [n (integer-in 0 1000000)])
404           void?]{
405
406Sets the maximum number of milliseconds that can separate the clicks
407 of a double-click.
408
409}
410
411@defmethod[(set-grab-key-function [f ((or/c string? false?)
412                                      (is-a?/c keymap%)
413                                      any/c
414                                      (is-a?/c key-event%)
415                                      . -> . any)])
416           void?]{
417
418Installs a callback procedure that is invoked after the keymap matches
419 input to a function name or fails to match an input. Only one
420 keyboard grab function can be installed at a time. When keymaps are
421 chained to a keymap with a grab callback, the callback is invoked for
422 matches in the chained keymap (when the chained keymap does not have
423 its own grab callback).
424
425If a grab callback returns a true value for a matching or non-matching
426 callback, the event is considered handled. If the callback returns a
427 true value for a matching callback, then the matching keymap function
428 is not called by the keymap.
429
430The callback procedure @racket[f] will be invoked as:
431
432@racketblock[
433(f _str _keymap _editor _event)
434]
435
436The @racket[_str] argument is the name of a function for a matching
437 callback, or @racket[#f] for a non-matching callback.  The
438 @racket[_keymap] argument is the keymap that matched (possibly a
439 keymap chained to the one in which the callback was installed) or the
440 keymap in which the callback was installed. The @racket[_editor] and
441 @racket[_event] arguments are the same as passed on to the matching
442 keymap function.
443
444Key grab callback functions are de-installed with @method[keymap%
445 remove-grab-key-function].
446
447}
448
449
450@defmethod[(set-grab-mouse-function [f ((or/c string? false?)
451                                        (is-a?/c keymap%)
452                                        any/c
453                                        (is-a?/c mouse-event%)
454                                        . -> . any)])
455           void?]{
456
457Like @method[keymap% set-grab-key-function], but for mouse events.
458
459}}
460
461