I have a minor mode. If that mode is active and the user hits DEL, I want to do some action, but only if some condition holds. If the condition holds and the action is executed I want to do nothing more after that. But if the condition fails, I don't want to do anything and let the default DEL action execute.
Not sure how I could solve this. But I guess I could do it in two ways:
1) I could rebind the DEL key to a function in the minor mode and then check if the conditions holds ot not. But then how do I know what the default command to DEL is?
2) I could add a pre command hook like this. Execute the command and then break the chain. But how do I break the chain?
(add-hook 'pre-command-hook
(lambda()
(when (equal last-input-event 'backspace)
;; Do something and then stop (do not execute the
;; command that backspace is bound to)
)))
In what way would you solve it? Thanks!
The way to do this is to temporarily disable your minor mode, then look up the key binding.
Pretend that you've bound 'do-thingy
to DEL. Then this would do the trick (assuming the condition you want to trigger off is (equal last-input-event 'backspace)
:
(defun do-thingy ()
"Do something, unless last event was backspace."
(interactive)
(if (equal last-input-event 'backspace)
(let* ((my-minor-mode nil)
(original-func (key-binding (kbd "DEL"))))
;; original-func is whatever DEL would be if
;; my-minor-mode were disabled
(call-interactively original-func))
(message "Here's my minor mode behavior!")))
Note: This behavior assumes you have set up your key bindings the standard way a minor-mode would. Specifically, you should add your keymap to the variable minor-mode-map-alist
by adding an element (my-minor-mode . my-minor-mode-keymap)
. That's how the above let
statement works, it looks up the binding you want with your mode temporarily disabled.
If you use define-minor-mode
to define your minor mode, the keymap gets set up the "right way" automatically.
This is what I use for my smart-tab
package which does exactly that.
(defun smart-tab-default ()
"Indents region if mark is active, or current line otherwise."
(interactive)
(if mark-active
(indent-region (region-beginning)
(region-end))
(call-interactively
(or
;; Minor mode maps for tab (without smart-tab-mode)
(cdar (assq-delete-all 'smart-tab-mode (minor-mode-key-binding "\t")))
(cdar (assq-delete-all 'smart-tab-mode (minor-mode-key-binding [(tab)])))
(local-key-binding "\t")
(local-key-binding [(tab)])
(global-key-binding "\t")
(global-key-binding [(tab)])))))
And in the command smart-tab
(which is the one bound to tab in the minor
mode), it has the following:
(if (smart-tab-must-expand prefix)
;; use smart tab
(smart-tab-default))
It first checks if there are any minor mode bindings for tab (not including
smart-tab-mode
), then local, and finally global keybindings.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With