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