592 lines
23 KiB
Racket
592 lines
23 KiB
Racket
#lang racket/base
|
|
|
|
(require string-constants
|
|
racket/class
|
|
racket/match
|
|
racket/list
|
|
racket/unit
|
|
mred/mred-sig
|
|
"../preferences.rkt"
|
|
"sig.rkt"
|
|
"keymap-global.rkt")
|
|
|
|
(provide keymap@)
|
|
|
|
(define-unit keymap@
|
|
(import mred^
|
|
[prefix finder: framework:finder^]
|
|
[prefix handler: framework:handler^]
|
|
[prefix frame: framework:frame^]
|
|
[prefix editor: framework:editor^]
|
|
[prefix text: framework:text^])
|
|
(export (rename framework:keymap^
|
|
[-get-file get-file]))
|
|
(init-depend mred^)
|
|
|
|
;; if I put this in main.rkt with the others, it doesn't happen
|
|
;; early enough... ? JBC, 2011-07-12
|
|
(preferences:set-default 'framework:automatic-parens #f boolean?)
|
|
|
|
|
|
(define user-keybindings-files (make-hash))
|
|
|
|
(define (add-user-keybindings-file spec)
|
|
(hash-ref
|
|
user-keybindings-files
|
|
spec
|
|
(λ ()
|
|
(let* ([path (spec->path spec)]
|
|
[sexp (and (file-exists? path)
|
|
(parameterize ([read-accept-reader #t])
|
|
(call-with-input-file path read)))])
|
|
(match sexp
|
|
[`(module ,name ,lang ,x ...)
|
|
(cond
|
|
[(valid-keybindings-lang? lang)
|
|
(let ([km (dynamic-require spec '#%keymap)])
|
|
(hash-set! user-keybindings-files spec km)
|
|
(send user-keymap chain-to-keymap km #t))]
|
|
[else
|
|
(error 'add-user-keybindings-file
|
|
(string-constant user-defined-keybinding-malformed-file/found-lang)
|
|
(path->string path)
|
|
lang)])]
|
|
[else (error 'add-user-keybindings-file
|
|
(string-constant user-defined-keybinding-malformed-file)
|
|
(path->string path))])))))
|
|
|
|
(define (valid-keybindings-lang? x)
|
|
(member x
|
|
(list `(lib "keybinding-lang.ss" "framework")
|
|
`(lib "keybinding-lang.rkt" "framework")
|
|
`(lib "framework/keybinding-lang.ss")
|
|
`(lib "framework/keybinding-lang.rkt")
|
|
`framework/keybinding-lang)))
|
|
|
|
(define (spec->path p)
|
|
(cond
|
|
[(path? p) p]
|
|
[else
|
|
(let* ([mod-name ((current-module-name-resolver) p #f #f #t)]
|
|
[str (symbol->string mod-name)]
|
|
[pth (substring str 1 (string-length str))])
|
|
(let-values ([(base name _) (split-path pth)])
|
|
(let ([filenames
|
|
(sort
|
|
(filter (λ (x) (substring? (path->string name) x))
|
|
(map path->string (directory-list base)))
|
|
(λ (x y) (> (string-length x) (string-length y))))])
|
|
(when (null? filenames)
|
|
(error 'spec->path "could not convert ~s, found no filenames for ~s" p mod-name))
|
|
(build-path base (car filenames)))))]))
|
|
|
|
(define (substring? s1 s2)
|
|
(and (<= (string-length s1)
|
|
(string-length s2))
|
|
(string=? s1 (substring s2 0 (string-length s1)))))
|
|
|
|
(define (remove-user-keybindings-file spec)
|
|
(let/ec k
|
|
(let ([km (hash-ref user-keybindings-files spec (λ () (k (void))))])
|
|
(send global remove-chained-keymap km)
|
|
(hash-remove! user-keybindings-files spec))))
|
|
|
|
(define (remove-chained-keymap ed keymap-to-remove)
|
|
(let ([ed-keymap (send ed get-keymap)])
|
|
(when (eq? keymap-to-remove ed-keymap)
|
|
(error 'keymap:remove-keymap "cannot remove initial keymap from editor"))
|
|
(let p-loop ([parent-keymap ed-keymap])
|
|
(unless (is-a? parent-keymap aug-keymap<%>)
|
|
(error 'keymap:remove-keymap
|
|
"found a keymap that is not a keymap:aug-keymap<%> ~e"
|
|
parent-keymap))
|
|
(let c-loop ([child-keymaps (send parent-keymap get-chained-keymaps)])
|
|
(cond
|
|
[(null? child-keymaps)
|
|
(void)]
|
|
[else
|
|
(let ([child-keymap (car child-keymaps)])
|
|
(cond
|
|
[(eq? child-keymap keymap-to-remove)
|
|
(send parent-keymap remove-chained-keymap child-keymap)
|
|
(c-loop (cdr child-keymaps))]
|
|
[else
|
|
(p-loop child-keymap)
|
|
(c-loop (cdr child-keymaps))]))])))))
|
|
|
|
(define (set-chained-keymaps parent-keymap children-keymaps)
|
|
(for-each (λ (orig-sub) (send parent-keymap remove-chained-keymap))
|
|
(send parent-keymap get-chained-keymaps))
|
|
(for-each (λ (new-sub) (send parent-keymap chain-to-keymap new-sub #f))
|
|
children-keymaps))
|
|
|
|
(define aug-keymap<%> (interface ((class->interface keymap%))
|
|
get-chained-keymaps
|
|
get-map-function-table
|
|
get-map-function-table/ht))
|
|
|
|
(define aug-keymap-mixin
|
|
(mixin ((class->interface keymap%)) (aug-keymap<%>)
|
|
(define chained-keymaps null)
|
|
(define/public (get-chained-keymaps) chained-keymaps)
|
|
|
|
(define/override (chain-to-keymap keymap prefix?)
|
|
(super chain-to-keymap keymap prefix?)
|
|
(set! chained-keymaps
|
|
(if prefix?
|
|
(cons keymap chained-keymaps)
|
|
(append chained-keymaps (list keymap)))))
|
|
|
|
(define/override (remove-chained-keymap keymap)
|
|
(super remove-chained-keymap keymap)
|
|
(set! chained-keymaps (remq keymap chained-keymaps)))
|
|
|
|
(define function-table (make-hasheq))
|
|
(define/public (get-function-table) function-table)
|
|
(define/override (map-function keyname fname)
|
|
(super map-function (canonicalize-keybinding-string keyname) fname)
|
|
(hash-set! function-table (string->symbol keyname) fname))
|
|
|
|
(define/public (get-map-function-table)
|
|
(get-map-function-table/ht (make-hasheq)))
|
|
|
|
(define/public (get-map-function-table/ht table)
|
|
(for ([(keyname fname) (in-hash function-table)])
|
|
(define cs (canonicalize-keybinding-string (format "~a" keyname)))
|
|
(define key (string->symbol cs))
|
|
(unless (hash-ref table key #f)
|
|
(when (on-this-platform? cs)
|
|
(hash-set! table key fname))))
|
|
(for ([chained-keymap (in-list chained-keymaps)])
|
|
(when (is-a? chained-keymap aug-keymap<%>)
|
|
(send chained-keymap get-map-function-table/ht table)))
|
|
table)
|
|
|
|
(define/private (on-this-platform? cs)
|
|
(define splits
|
|
(for/list ([x (in-list (split-out #\; (string->list cs)))])
|
|
(all-but-last (split-out #\: x))))
|
|
(define (has-key? k) (ormap (λ (x) (member (list k) x)) splits))
|
|
(cond
|
|
[(eq? (system-type) 'windows)
|
|
(cond
|
|
[(and (regexp-match? #rx"c:m" cs)
|
|
(not (regexp-match? #rx"~c:m" cs))
|
|
(not (regexp-match? #rx"~g:" cs)))
|
|
#f]
|
|
[(or (has-key? #\a) (has-key? #\d))
|
|
#f]
|
|
[else #t])]
|
|
[(eq? (system-type) 'macosx)
|
|
(cond
|
|
[(has-key? #\m)
|
|
#f]
|
|
[else #t])]
|
|
[(eq? (system-type) 'unix)
|
|
(cond
|
|
[(or (has-key? #\a) (has-key? #\d))
|
|
#f]
|
|
[else #t])]
|
|
[else
|
|
;; just in case new platforms come along ....
|
|
#t]))
|
|
|
|
(define/private (all-but-last l)
|
|
(cond
|
|
[(null? l) l]
|
|
[(null? (cdr l)) l]
|
|
[else (cons (car l) (all-but-last (cdr l)))]))
|
|
|
|
(super-new)))
|
|
|
|
(define aug-keymap% (aug-keymap-mixin keymap%))
|
|
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
;;;;;;; ;;;;;;;;
|
|
;;;;;;; canonicalize-keybinding-string ;;;;;;;;
|
|
;;;;;;; ;;;;;;;;
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
|
|
;; canonicalize-keybinding-string : string -> string
|
|
;; The result can be used with string=? to determine
|
|
;; if two key bindings refer to the same key.
|
|
;; Assumes a well-formed keystring.
|
|
(define (canonicalize-keybinding-string str)
|
|
(define chars (map char-downcase (string->list str)))
|
|
(define separated-keys
|
|
(map
|
|
canonicalize-single-keybinding-string
|
|
(split-out #\; chars)))
|
|
(join-strings ";" separated-keys))
|
|
|
|
;; join-strings : string (listof string) -> string
|
|
;; concatenates strs with sep between each of them
|
|
(define (join-strings sep strs)
|
|
(if (null? strs)
|
|
""
|
|
(apply
|
|
string-append
|
|
(cons
|
|
(car strs)
|
|
(let loop ([sepd-strs (cdr strs)])
|
|
(cond
|
|
[(null? sepd-strs) null]
|
|
[else (list*
|
|
sep
|
|
(car sepd-strs)
|
|
(loop (cdr sepd-strs)))]))))))
|
|
|
|
;; canonicalize-single-keybinding-string : (listof char) -> string
|
|
(define (canonicalize-single-keybinding-string chars)
|
|
(let* ([neg? (char=? (car chars) #\:)]
|
|
[mods/key (split-out #\: (if neg? (cdr chars) chars))]
|
|
[mods
|
|
(let loop ([mods mods/key])
|
|
(cond
|
|
[(null? mods) null]
|
|
[(null? (cdr mods)) null]
|
|
[else (cons (car mods) (loop (cdr mods)))]))]
|
|
[key (apply string (car (last-pair mods/key)))]
|
|
[canon-key
|
|
(cond
|
|
[(string=? key "enter") "return"]
|
|
[(string=? key "del") "delete"]
|
|
[(string=? key "ins") "insert"]
|
|
[else key])]
|
|
[shift (if neg? #f 'd/c)]
|
|
[control (if neg? #f 'd/c)]
|
|
[alt (if neg? #f 'd/c)]
|
|
[meta (if neg? #f 'd/c)]
|
|
[command (if neg? #f 'd/c)]
|
|
[lock 'd/c]
|
|
[altgr 'd/c]
|
|
[question-mark 'd/c]
|
|
|
|
[do-key
|
|
(λ (char val)
|
|
(cond
|
|
[(eq? val #t) (string char)]
|
|
[(eq? val #f) (string #\~ char)]
|
|
[(eq? val 'd/c) #f]))])
|
|
|
|
(for-each (λ (mod)
|
|
(let ([val (not (char=? (car mod) #\~))])
|
|
(case (if (char=? (car mod) #\~)
|
|
(cadr mod)
|
|
(car mod))
|
|
[(#\s) (set! shift val)]
|
|
[(#\c) (set! control val)]
|
|
[(#\a) (set! alt val)]
|
|
[(#\d) (set! command val)]
|
|
[(#\m) (set! meta val)]
|
|
[(#\l) (set! lock val)]
|
|
[(#\g) (set! altgr val)]
|
|
[(#\?) (set! question-mark val)])))
|
|
mods)
|
|
|
|
(join-strings ":"
|
|
(filter
|
|
values
|
|
(list
|
|
(do-key #\? question-mark)
|
|
(do-key #\a alt)
|
|
(do-key #\c control)
|
|
(do-key #\d command)
|
|
(do-key #\m meta)
|
|
(do-key #\s shift)
|
|
(do-key #\l lock)
|
|
(and (eq? 'windows (system-type))
|
|
control
|
|
meta
|
|
(do-key #\g altgr))
|
|
canon-key)))))
|
|
|
|
;; split-out : char (listof char) -> (listof (listof char))
|
|
;; splits a list of characters at its first argument
|
|
;; if the last character is the same as the first character,
|
|
;; it is not split into an empty list, but returned.
|
|
(define (split-out split-char chars)
|
|
(let loop ([chars chars]
|
|
[this-split null]
|
|
[all-split null])
|
|
(cond
|
|
[(null? chars)
|
|
(reverse (cons (reverse this-split) all-split))]
|
|
[else (let ([char (car chars)])
|
|
(cond
|
|
[(char=? split-char char)
|
|
(if (null? (cdr chars))
|
|
(loop null
|
|
(cons char this-split)
|
|
all-split)
|
|
(loop (cdr chars)
|
|
null
|
|
(cons (reverse this-split) all-split)))]
|
|
[else
|
|
(loop (cdr chars)
|
|
(cons char this-split)
|
|
all-split)]))])))
|
|
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
;;;;;;; ;;;;;;;;
|
|
;;;;;;; end canonicalize-keybinding-string ;;;;;;;;
|
|
;;;;;;; ;;;;;;;;
|
|
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
|
|
|
(define make-meta-prefix-list keymap:make-meta-prefix-list)
|
|
|
|
(define send-map-function-meta keymap:send-map-function-meta)
|
|
|
|
(define region-click keymap:region-click)
|
|
|
|
(define add-to-right-button-menu keymap:add-to-right-button-menu)
|
|
(define add-to-right-button-menu/before keymap:add-to-right-button-menu/before)
|
|
|
|
(define (call/text-keymap-initializer thunk)
|
|
(let ([ctki (current-text-keymap-initializer)])
|
|
(parameterize ([current-text-keymap-initializer
|
|
(λ (keymap)
|
|
(send keymap chain-to-keymap global #t)
|
|
(ctki keymap))])
|
|
(thunk))))
|
|
|
|
(define (setup-global kmap #:alt-as-meta-keymap [alt-as-meta-keymap #f])
|
|
(keymap:setup-global kmap #:alt-as-meta-keymap alt-as-meta-keymap)
|
|
(define (goto-line keystroke-edit event)
|
|
(define keystroke-frame
|
|
(and (is-a? keystroke-edit editor:basic<%>)
|
|
(send keystroke-edit get-top-level-window)))
|
|
(define edit
|
|
(cond
|
|
[(is-a? keystroke-frame frame:info<%>)
|
|
(send keystroke-frame get-info-editor)]
|
|
[(is-a? keystroke-edit text%) keystroke-edit]
|
|
[else #f]))
|
|
(when edit
|
|
(define num-str
|
|
(call/text-keymap-initializer
|
|
(λ ()
|
|
(get-text-from-user
|
|
(string-constant goto-line)
|
|
(string-constant goto-line)))))
|
|
(when (string? num-str)
|
|
(define possible-num (string->number num-str))
|
|
(define line-num (and possible-num (inexact->exact possible-num)))
|
|
(cond
|
|
[(and (number? line-num)
|
|
(integer? line-num)
|
|
(<= 1 line-num (+ (send edit last-paragraph) 1)))
|
|
(define pos (send edit paragraph-start-position (sub1 line-num)))
|
|
(send edit set-position pos)]
|
|
[else
|
|
(message-box
|
|
(string-constant goto-line)
|
|
(format
|
|
(string-constant goto-line-invalid-number)
|
|
num-str
|
|
(+ (send edit last-line) 1)))])))
|
|
#t)
|
|
|
|
(let ([add-m (λ (name func)
|
|
(send kmap add-function name func)
|
|
(when alt-as-meta-keymap
|
|
(send alt-as-meta-keymap add-function name func)))]
|
|
[map-meta (λ (key func)
|
|
(keymap:send-map-function-meta kmap key func
|
|
(regexp-match? has-control-regexp key)
|
|
#:alt-as-meta-keymap alt-as-meta-keymap))])
|
|
(add-m "goto-line" goto-line)
|
|
(map-meta "g" "goto-line")))
|
|
|
|
(define setup-search
|
|
(let* ([send-frame
|
|
(λ (invoke-method)
|
|
(λ (edit event)
|
|
(let ([frame
|
|
(cond
|
|
[(is-a? edit editor<%>)
|
|
(let ([canvas (or (send edit get-active-canvas)
|
|
(send edit get-canvas))])
|
|
(and canvas
|
|
(send canvas get-top-level-window)))]
|
|
[(is-a? edit area<%>)
|
|
(send edit get-top-level-window)]
|
|
[else #f])])
|
|
(if frame
|
|
(invoke-method frame)
|
|
(bell)))
|
|
#t))])
|
|
(λ (kmap #:alt-as-meta-keymap [alt-as-meta-keymap #f])
|
|
(let* ([map (λ (key func)
|
|
(send kmap map-function key func))]
|
|
[map-meta (λ (key func)
|
|
(send-map-function-meta kmap key func
|
|
(regexp-match? has-control-regexp key)
|
|
#:alt-as-meta-keymap alt-as-meta-keymap))]
|
|
[add (λ (name func)
|
|
(send kmap add-function name func))]
|
|
[add-m (λ (name func)
|
|
(send kmap add-function name func)
|
|
(when alt-as-meta-keymap
|
|
(send alt-as-meta-keymap add-function name func)))])
|
|
|
|
(add-m "search forward"
|
|
(send-frame (λ (f) (send f search 'forward))))
|
|
(add "search backward"
|
|
(send-frame (λ (f) (send f search 'backward))))
|
|
(add "replace & search forward"
|
|
(send-frame (λ (f) (send f replace&search 'forward))))
|
|
(add "replace & search backward"
|
|
(send-frame (λ (f) (send f replace&search 'backward))))
|
|
(add "unhide search and toggle focus"
|
|
(send-frame (λ (f) (send f unhide-search-and-toggle-focus))))
|
|
(add "hide-search"
|
|
(send-frame (λ (f) (send f hide-search))))
|
|
|
|
(map "c:g" "hide-search")
|
|
(map "f3" "unhide search and toggle focus")
|
|
(map "c:s" "unhide search and toggle focus")
|
|
(map "c:r" "search backward")
|
|
(case (system-type)
|
|
[(unix)
|
|
(map-meta "%" "search forward")])))))
|
|
|
|
(define setup-file
|
|
(let* ([get-outer-editor ;; : text% -> text%
|
|
;; returns the outermost editor, if this editor is nested in an editor snip.
|
|
(λ (edit)
|
|
(let loop ([edit edit])
|
|
(let ([admin (send edit get-admin)])
|
|
(cond
|
|
[(is-a? admin editor-snip-editor-admin<%>)
|
|
(loop (send (send (send admin get-snip) get-admin) get-editor))]
|
|
[else edit]))))]
|
|
[save-file-as
|
|
(λ (this-edit event)
|
|
(let ([edit (get-outer-editor this-edit)])
|
|
(parameterize ([finder:dialog-parent-parameter
|
|
(and (is-a? edit editor:basic<%>)
|
|
(send edit get-top-level-window))])
|
|
(let ([file (finder:put-file)])
|
|
(when file
|
|
(send edit save-file/gui-error file)))))
|
|
#t)]
|
|
[save-file
|
|
(λ (this-edit event)
|
|
(let ([edit (get-outer-editor this-edit)])
|
|
(if (send edit get-filename)
|
|
(send edit save-file/gui-error)
|
|
(save-file-as edit event)))
|
|
#t)]
|
|
[load-file
|
|
(λ (edit event)
|
|
(define (fallback)
|
|
(let ([fn (send edit get-filename)])
|
|
(handler:open-file
|
|
(and fn
|
|
(let-values ([(base name dir) (split-path fn)])
|
|
base)))))
|
|
(cond
|
|
[(is-a? edit editor:basic<%>)
|
|
(define fr (send edit get-top-level-window))
|
|
(cond
|
|
[(is-a? fr frame:standard-menus<%>)
|
|
(send fr file-menu:open-callback
|
|
(send fr file-menu:get-open-item)
|
|
event)]
|
|
[else (fallback)])]
|
|
[else (fallback)])
|
|
#t)])
|
|
(λ (kmap #:alt-as-meta-keymap [alt-as-meta-keymap #f])
|
|
(let* ([map (λ (key func)
|
|
(send kmap map-function key func))]
|
|
[map-meta (λ (key func)
|
|
(send-map-function-meta kmap key func
|
|
(regexp-match? has-control-regexp key)
|
|
#:alt-as-meta-keymap alt-as-meta-keymap))]
|
|
[add (λ (name func)
|
|
(send kmap add-function name func))]
|
|
[add-m (λ (name func)
|
|
(send kmap add-function name func)
|
|
(when alt-as-meta-keymap
|
|
(send alt-as-meta-keymap add-function name func)))])
|
|
|
|
(add "save-file" save-file)
|
|
(add "save-file-as" save-file-as)
|
|
(add "load-file" load-file)
|
|
|
|
(map "c:x;c:s" "save-file")
|
|
(map "d:s" "save-file")
|
|
(map "c:x;c:w" "save-file-as")
|
|
(map "c:x;c:f" "load-file")))))
|
|
|
|
(define (setup-editor kmap)
|
|
(let ([add/map
|
|
(λ (func op key)
|
|
(send kmap add-function
|
|
func
|
|
(λ (editor evt)
|
|
(send editor do-edit-operation op)))
|
|
(send kmap map-function
|
|
(string-append
|
|
(case (system-type)
|
|
[(macosx macos) "d:"]
|
|
[(windows unix) "c:"]
|
|
[else (error 'keymap.rkt "unknown platform: ~s" (system-type))])
|
|
key)
|
|
func))])
|
|
(add/map "editor-undo" 'undo "z")
|
|
(unless (eq? (system-type) 'macosx)
|
|
(add/map "editor-redo" 'redo "y"))
|
|
(add/map "editor-cut" 'cut "x")
|
|
(add/map "editor-copy" 'copy "c")
|
|
(add/map "editor-paste" 'paste "v")
|
|
(add/map "editor-select-all" 'select-all "a")))
|
|
|
|
(define (generic-setup keymap)
|
|
(add-editor-keymap-functions keymap)
|
|
(add-pasteboard-keymap-functions keymap)
|
|
(add-text-keymap-functions keymap))
|
|
|
|
(define user-keymap (make-object aug-keymap%))
|
|
(define (get-user) user-keymap)
|
|
|
|
(define global (make-object aug-keymap%))
|
|
(define global-main (make-object aug-keymap%))
|
|
(define global-alt-as-meta (make-object aug-keymap%))
|
|
(send global chain-to-keymap global-main #f)
|
|
(generic-setup global-main)
|
|
(generic-setup global-alt-as-meta)
|
|
(setup-global global-main #:alt-as-meta-keymap global-alt-as-meta)
|
|
(define (get-global) global)
|
|
|
|
(define file (make-object aug-keymap%))
|
|
(define file-alt-as-meta (make-object aug-keymap%))
|
|
(generic-setup file)
|
|
(setup-file file #:alt-as-meta-keymap file-alt-as-meta)
|
|
(define (-get-file) file)
|
|
|
|
(define search (make-object aug-keymap%))
|
|
(define search-alt-as-meta (make-object aug-keymap%))
|
|
(generic-setup search)
|
|
(setup-search search #:alt-as-meta-keymap search-alt-as-meta)
|
|
(define (get-search) search)
|
|
|
|
(define editor (make-object aug-keymap%))
|
|
(setup-editor editor)
|
|
(define (get-editor) editor)
|
|
|
|
(preferences:set-default 'framework:alt-as-meta #f boolean?)
|
|
(define (adjust-alt-as-meta on?)
|
|
(send global-main remove-chained-keymap global-alt-as-meta)
|
|
(send file remove-chained-keymap file-alt-as-meta)
|
|
(send search remove-chained-keymap search-alt-as-meta)
|
|
(when on?
|
|
(send global-main chain-to-keymap global-alt-as-meta #f)
|
|
(send file chain-to-keymap file-alt-as-meta #f)
|
|
(send search chain-to-keymap search-alt-as-meta #f)))
|
|
(preferences:add-callback 'framework:alt-as-meta
|
|
(λ (p v) (adjust-alt-as-meta v)))
|
|
(adjust-alt-as-meta (preferences:get 'framework:alt-as-meta)))
|
|
|