-
Notifications
You must be signed in to change notification settings - Fork 84
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feature request: custom command keymaps for certain modes #133
Comments
Yes, I just asked myself similar questions when posting issue #137 . I wonder whether this needs to be looked at from the other side: you want to modify org-mode, so you should add your bindings to the org-mode's keymap only. Then the binding you added to org-mode's keymap needs to be specific to command-mode being enabled. I can think of two ways to do that:
|
I would be open to have / write / manage such a fork because what I use now is a ugly messy buggy hack I don't really like. And it's very important to me to keep emacs hackable and not loosing that just because I use exwm. I mean sure exwm will be always no ideal solution I can't define application specific keybindings or use command mode in a text box. But as long as we can't do everything in native emacs exwm is the best we can get. So basically that lines: ("a" . xah-fly-M-x)
("b" . isearch-forward)
("c" . previous-line) Would be then: ("H-a" . xah-fly-M-x)
("H-b" . isearch-forward)
("H-c" . previous-line) and then what something like: (unless (boundp xah-fly-exwm-command-map <key-pressed>)
(... call-interactive <H key-pressed>)) |
I think you're somewhat ahead to me in terms of having moved into a emacs-only working environment. About the mess that xah-fly made of all the other modes, I'm starting to like the "sticky hyper key" approach to mode switching and may try to do a prototype next week. Though in general, with the problems you describe, (partially) reimplementing xah-fly-keys via a custom keyboard firmware (see e.g. QMK) may be the less insane aproach :) |
@dvdkhlng just updated my last comment, just say it in case you got not noticed. |
I'm not sure I understand what you're up to, but I think that the "hyper" modification can automatically be dropped directly inside the key-translation-map handler as required (e.g. when detecting current buffer is in exwm mode). Or alternatively drop the Hyper modifier when no current binding matches. Right now I'm not sure which keymap to attach those hyper bindings to. Putting them in the global map would affect exwm mode, so I wonder whether there is some less global keymap that would make more sense? As all the major modes seem to form a hierarchy (c-mode is a child of prog-mode is a child of text-mode), maybe there is a small set of major mode maps that we could attach to, which would imply that exwm buffers would not be affected. |
But I want some keys to work in exwm buffers like: ("<kp-4>" . 'eshell)
("<kp-5>" . 'shell)
("<XF86Launch6>" . (lambda () (interactive)
(find-file user-init-org))) it's just not all, I use normal number keys if I want to type numbers so I want them basically in command mode at least but also in insert mode. Which currently I have to write either: (push 'XF86Launch6 exwm-input-prefix-keys) So that exwm does not shadow this key to xah-fly-keys or I have to bind it to the xah-fly-exwm-command-map. basically I can't bind it to exwm-keymap because I want this key bindings sometimes depending on insert mode/ command mode somethimes I want them active in both modes. |
@dvdkhlng Yes I think having some prototype code would be very nice. keyboard firmware might be easier I don't know but not very helpful because not everybody has a keyboard compatible with such firmware. |
This proof of concept seems to work. edit fixed ;; the "command mode" flag, i.e. whether our sticky hyper key is pressed.
(defvar hyper-lock nil)
;; For testing, F12 toggles our sticky "hyper" key.
(global-set-key [f12] (lambda ()
(interactive)
(setq hyper-lock (not hyper-lock))
(message "hyper-lock %s" hyper-lock)))
;; Key translation handler that adds Hyper to the first event in the sequence
;; but only if that yields a valid key binding in the current context.
(defun hyperify (prompt)
(let* ((v (this-command-keys-vector))
(len (length v))
(ev1 (aref v (1- len)))
(ev1v (vector ev1)))
(if (or (not hyper-lock) (/= 1 len))
ev1v
(let ((ev1mod (event-modifiers ev1))
(ev1base (event-basic-type ev1)))
(if (memq 'hyper ev1mod)
ev1v
(vector
(event-convert-list
(nconc (cons 'hyper ev1mod) (cons ev1base nil)))))))))
(define-key key-translation-map "r" 'hyperify)
(define-key key-translation-map "n" 'hyperify)
;; Bind H-n, but do not bind H-r so we can verify that hyperify only affects
;; key bindings that are in use.
(global-set-key [(hyper ?n)] (lambda() (interactive)( insert "hyper!"))) So then we'd only put the xah-fly special bindings into text-mode's map and maybe some of them into special-mode's map (maybe also into some minor-mode relevant maps?). As exwm does not inherit from either of those major modes, it should not receive any of the hyper-bindings and would thus not be affected by the newly added sticky hyper key (unless you manually add bindings into exwm's map or add bindings to the global map or to any minor mode maps that are active when you use exwm). |
So I rewrote the key-binding machinery of xah-fly-keys to not change the set of active key-maps, but solely rely on key translation. Warning: this is still very experimental, make backups of your files and don't blame me for lost work/time/nerves. https://github.com/dvdkhlng/xah-fly-keys-hyper When activating xah-fly-keys minor mode, this now installs a key translation handler that adds "hyper-" modifier to the keys listed in
The
For testing, you can e.g. visit a file using (xah-fly-keymap-inject (current-global-map) xah-fly-command-map)) Which will make command mode take effect (almost) everywhere (no, I haven't verified that this works). So where to go from here? edit in case there are too many people/modes who/that rely on hyper bindings for their standard operation, we may want to use a different set of modifiers that are unlikely to be used by human operators. Such as "hyper-super-meta-control-". |
@dvdkhlng oh you were very busy :D give me a second I test it later very interesting |
Trying to use this productively, I just found at least 3 bugs, two of them I just pushed fixes for to the above repo (isearch broken and major-mode keymap injection failed depending on load order). The remaining bug seems to be about how |
Ah yes, and the keymap injection is broken, in that any modes adding stuff to any of the keymaps after we modified them, those modes will accidentally inject into our command mode map instead ,causing quite some havock. |
latest commit fixes that. |
@dvdkhlng so I tried it a bit but struggle to get it in a usable state together with exwm. As example when I set: (bind-key (kbd "w") 'xah-next-window-or-frame xah-fly-command-map) in insert mode w now also changes the window. (I think that was the same in classic exwm) But still "w" doesn't work for frame change in a exwm-buffer then I had something like that: (defun sb/wrapper-active-xfk ()
(push ?w exwm-input-prefix-keys))
(defun sb/wrapper-deactive-xfk ()
(setq exwm-input-prefix-keys (remove ?w exwm-input-prefix-keys)))
(progn
(add-hook 'xah-fly-command-mode-activate-hook 'sb/wrapper-active-xfk)
(add-hook 'xah-fly-insert-mode-activate-hook 'sb/wrapper-deactive-xfk)
(add-hook 'change-major-mode-hook 'sb/wrapper-active-xfk)) alternatively there would also be exwm-mode-hook, but the 1 liner at top should work. |
I trimmed it down I use "?a" which should start "M-x" execute-command or smex or something. all hook I use don't seem to work with changing to a exwm window except change-major-mode-hook, but if I then press "a" I get the error: Here the code: (defun sb/wrapper-active-xfk ()
(push ?a exwm-input-prefix-keys))
(add-hook 'change-major-mode-hook 'sb/wrapper-active-xfk) That should work with upstream xah-fly-keys In Messages I see even before a slightly different error: |
I mean the goal is as first step to get the "a" and "w" button to work in command mode under exwm buffers like in text buffers, that code I posted is just how I did that in upstream exwm. For testing you can use exwm also in normal emacs without using it as the desktop environment. |
Ah no, xah-fly-command-map is now active all the time, and merely the hyper modifier gets added on input when in command mode. So this should look like this: (bind-key (kbd "H-w") 'xah-next-window-or-frame xah-fly-command-map) But then, I don't even know the You may now also just put these bindings into the global keymap (and override them from the major mode keymaps where required).
Try adding bindings directly to exwm-mode-map (require 'exwm)
(define-key exwm-mode-map (kbd "H-w") 'xah-next-window-or-frame) (it would be cleaner to use BTW just pushed another round of fixes, after a eating my own dog food today. |
In the xah-fly-keys-hyper implementation, command mode is now just a sticky hyper key affecting first key event in any key sequence. So just forget about xah-fly-command-map and add keyboard bindings for The "sticky hyper modifier key" metaphor is only slightly incorrect in that hyper modifier is omitted, when there is no key binding for the resulting event. |
@dvdkhlng no that does not work, exwm is more than just another major mode, it fiddles with some fundamentals of emacs, because having X buffers. I am no expert of exwm but you could see it a bit like exwm is the new framework in which emacs buffers and x buffers run. There is even a special exwm-input-set-key function but that seems not very helpful. the description of exwm-input-prefix-keys: Line mode is always on by default, so basically the keys it should forward to emacs and not send to the X application, otherwise the application manages the key press. Maybe @ch11ng could help here out, and maybe exwm should be rewritten to work better with this modal modes, but seems to be a much bigger task :D |
Oh god, I had no idea what a mind boggling machinery this exwm is. Just skimmed over the key input handling and the X protocol implementation. I think that adding support for modal key bindings should be possible, though I need some more time to grok this. They seem to re-implement emacs' keyboard input handling, but they invoke |
I have used a lot of workarounds to customize xah-fly-keys for certain modes especially in context with exwm, but not only with exwm, just with normal modes.
or
(setq xah-fly-command-map (assq-delete-all ?q xah-fly-command-map))
So I wonder if it would not be better to have the ability to define some alist where you add your modes with keybindings like that:
Partially I did implement that statically in #132 but it's a bit a hack and should maybe not be exwm-specific.
The text was updated successfully, but these errors were encountered: