Open a13 opened 4 years ago
@jurta sorry for disturbing, as a person who knows about Emacs keymaps internals a /little/ bit more than me, do you have any ideas regarding this issue?
The thing is sometimes (like here or in org-agenda-mode-map
) Emacs ignores function-key-map when the single key (without modifier keys) is pressed and runs self-insert-command, while in most cases it works as I expect :)
Sorry, I'm not an expert in hydra :) maybe hydra author can help to provide the results of processing by hydra internals as plain define-key
calls, then I could help to see what is wrong.
In the example above with defhydra
, what are the real calls of define-key
by hydra?
it doesn't use define-key, but creates a keymap directly
(set
(defvar hydra-zoom/keymap nil "Keymap for hydra-zoom.")
'(keymap
(12 . hydra-zoom/text-scale-decrease)
(7 . hydra-zoom/text-scale-increase)
(kp-subtract . hydra--negative-argument)
(kp-9 . hydra--digit-argument)
(kp-8 . hydra--digit-argument)
(kp-7 . hydra--digit-argument)
(kp-6 . hydra--digit-argument)
(kp-5 . hydra--digit-argument)
(kp-4 . hydra--digit-argument)
(kp-3 . hydra--digit-argument)
(kp-2 . hydra--digit-argument)
(kp-1 . hydra--digit-argument)
(kp-0 . hydra--digit-argument)
(57 . hydra--digit-argument)
(56 . hydra--digit-argument)
(55 . hydra--digit-argument)
(54 . hydra--digit-argument)
(53 . hydra--digit-argument)
(52 . hydra--digit-argument)
(51 . hydra--digit-argument)
(50 . hydra--digit-argument)
(49 . hydra--digit-argument)
(48 . hydra--digit-argument)
(45 . hydra--negative-argument)
(21 . hydra--universal-argument)))
org-agenda bindings (the same issue) use org-defkey
wrapper instead, but since org-replace-disputed-keys
is nil
it should work like define-key
(defun org-key (key)
"Select key according to `org-replace-disputed-keys' and `org-disputed-keys'.
Or return the original if not disputed."
(when org-replace-disputed-keys
(let* ((nkey (key-description key))
(x (cl-find-if (lambda (x) (equal (key-description (car x)) nkey))
org-disputed-keys)))
(setq key (if x (cdr x) key))))
key)
(defun org-defkey (keymap key def)
"Define a key, possibly translated, as returned by `org-key'."
(define-key keymap (org-key key) def))
https://github.com/emacs-mirror/emacs/blob/master/lisp/org/org-agenda.el#L2277-L2416
back to hydra, it works on the first keypress (the bindings are in global-map
)
(define-key global-map
[f2 103]
'hydra-zoom/text-scale-increase)
(define-key global-map
[f2 108]
'hydra-zoom/text-scale-decrease)
But then it sets hydra-zoom/keymap
as a transient one using
(internal-push-keymap keymap 'overriding-terminal-local-map)
(defun hydra-zoom/text-scale-increase nil "Call the head `text-scale-increase' in the \"hydra-zoom\" hydra.\n\nThe heads for the associated hydra are:\n\n\"g\": `text-scale-increase',\n\"l\": `text-scale-decrease'\n\nThe body can be accessed via `hydra-zoom/body', which is bound to \"<f2>\"."
(interactive)
(require 'hydra)
(hydra-default-pre)
(let
((hydra--ignore t))
(hydra-keyboard-quit)
(setq hydra-curr-body-fn 'hydra-zoom/body))
(condition-case err
(progn
(setq this-command 'text-scale-increase)
(hydra--call-interactively-remap-maybe #'text-scale-increase))
((quit error)
(message
(error-message-string err))))
(hydra-show-hint hydra-zoom/hint 'hydra-zoom)
(hydra-set-transient-map hydra-zoom/keymap
(lambda nil
(hydra-keyboard-quit)
nil)
nil))
Transient map is a real problem. What you could try to do is either to add around
advice on hydra-set-transient-map
and add your mappings to its arg keymap
, or add after
advice and do the same on the modified overriding-terminal-local-map
.
Here is an advice function that does that. Though it uses Edit2: NOW it works fine with keymap-set
, which is only available starting with emacs 29.define-key
(probably without bugs this time).
Edit3: fixed a recursion
(defun +translate-keymap (map)
(let ((tl-map (make-sparse-keymap)))
(map-keymap
(lambda (char cmd)
(when (characterp char)
(if-let* ((modifiers (event-modifiers char))
(event (event-basic-type char))
(tl-event (string (reverse-im--translate-char event)))
(key (vector `(,@modifiers ,tl-event))))
(define-key tl-map key cmd)
(define-key tl-map (string
(reverse-im--translate-char char))
cmd))))
map)
tl-map))
(defun +translate-keymap-a (fun map &rest args)
(if-let* ((map? (keymapp map))
(comp-map (make-composed-keymap map (+translate-keymap map))))
(apply fun comp-map args)
(apply fun map args)))
(advice-add 'set-transient-map :around #'+translate-keymap-a)
(advice-add 'hydra-set-transient-map :around #'+translate-keymap-a)
I've tested it a little with hydra and built-in repeat-mode, and it works without problems so far. I can create a pull request if you want.
By advising use-local-map
it works with org agenda and other modes that use it, like mu4e-view, too.
doesn't work
works