---+ 1: BRIEF:
How can I wrap all or almost all key-bindings? Both those already defined, and those that will be defined in the future? E.g. can you point me to code that overrides the command loop completely? Or is there a better way?
By "wrap" I mean leave all key-bindings in their keymaps, So that any existing keymap manipulation code continues to work. Possibly require a prefix to access all such key-bindings. And override the un-prefixed versions of such key bindings. Possibly dynamically
I will explain why I think I need this below.
---+ 2: LESS BRIEF:
How can I "wrap" ALL (or almost all) key-bindings? i.e. is there any existing code that I can be pointed to that wraps all key-bindings?
Not just those defined at the time I run or install my code, i.e. key-bindings defined in the past, but also those defined in the future, after the wrapping code has being run or started or installed.
By "wrap" I mean something like
- K1 ... Kn does NOT map to its original binding
- but SOME-PREFIX K1 ... Kn does
Well, actually, in the "wrapped" mode I might like behaviors such as the following:
(W0) none of the wrapped mode K1...Kn sequences map to the original non-wrapped mode key-binding.
(W-1) some but not all of the wrapped mode key sequences might map to the original non-wrapped mode key-binding, they might do nothing, or they might map to other commands
(W+1) possibly all wrapped mode key sequences K1...Kn map to the original non-wrapped mode key-binding. which would be exactly the same as if the key-binding wrapping package or command loop were not installed, except for one or a few commands to change between wrapping modes (W0), (W-1), and (W+1).
=== TL; DR ===========
If I have been clear enough above , it should be possible for you to stop reading here. I believe that I have described the questions in sufficient detail. The remaining stuff below is (a) to explain I want to this (speech recognition and better ergonomics), (b) will explain why some approaches are unsatisfactory, that have been suggested in answers and also tried by me years ago, (c) to mention that I have started investigating modal packages like ErgoEmacs, Evil, and Boon, but they seem overkill and in any case I seek advice as to which might be simplest to start with, etc.
---+ 3: Unsatisfactory Approaches
---+ 3.1: Sliding in new keymaps
Some have suggested sliding in new keymaps that refer to the old keymaps in the standard keymaps' names. E.g.
(let ((new-global-map (make-sparse-keymap)))
(define-key new-global-map (kbd "C-x") global-map)
(setq global-map new-global-map))
This is unsatisfactory for several reasons, including
It only applies to key-bindings that were created at the time this code was run. key-bindings created later will be made in the
new-global-map
Although simple enough for
global-map
, it is more awkward for other maps such aslocal-map
,minor-mode-map-alist
,overriding-local-map
, etc.Things break if the map wrapping code must know about the maps is overriding. E.g. when I first wrote such code IIRC the
overriding-local-map
did not exist and the minor mode math being reworked. Maintenance hassle.
---++ 3.2 Overriding the Command - Good or Bad?
Therefore it seems to me that overriding the command loop might be better: reading the next key symbol, and performing lookups or not according to what that symbol is but leaving all of the existing all of the existing emacs search code modified.
Assuming that the existing emacs Emacs search code is as described in https://www.gnu.org/software/emacs/manual/html_node/elisp/Searching-Keymaps.html
(or (if overriding-terminal-local-map
(find-in overriding-terminal-local-map))
(if overriding-local-map
(find-in overriding-local-map)
(or (find-in (get-char-property (point) 'keymap))
(find-in-any emulation-mode-map-alists)
(find-in-any minor-mode-overriding-map-alist)
(find-in-any minor-mode-map-alist)
(if (get-text-property (point) 'local-map)
(find-in (get-char-property (point) 'local-map))
(find-in (current-local-map)))))
(find-in (current-global-map)))
then wrapping that code within (non-elisp pseudocode)
e <-- read-event
IF (and (printable e) disable-key-sequences-starting-with-printable-characters)
THEN (self-insert e)
ELSE
unget e ;; Push it back so that the original lookup can be done
... the original lookup code above ...
This solves most of the problems with sliding in a new key map in place of an old.
However, overriding the EMACS command loop is considered undesirable, as is done by ErgoEmacs, discussed in "Start ergoemacs command loop" is blocking Emacs
On quick look the ErgoEmacs looks messy and fragile. Full of references to other packages such as icicle
and ispell
, with the command loop code intermixed with things like colors and blink-rate. Avoiding such dependencies is IMHO the bigger reason to consider overwriting the command loop. At the very least ErgoEmacs is doing much more that I want, and since I am lazy and would appreciate advice on how to spread things out.
In any case, what is the most elegant way to override the command loop?
---++ 3.3: Comparing Modal packages for EMACS
What I am asking for is a particular modal interface for EMACS. A particularly simple mobile interface for EMACS. Possibly similar to modal packages like evil
and boon
, and possibly ergoemacs
.
But, again, these packages do a lot, whereas I think I am looking for something much simpler.
Also, I am not at all certain that these packages provide full access to legacy keybindings.
---++ 3.3: Is There a Better or Best Known Way (BKM) to Do This?
I therefore ask questions such as:
Q1: is there a better way to get the "wrapping" behavior that I describe? better than overwriting the command loop.
Q2: as always, real code appreciated?
Q3: is ErgoEmacs approach the BKM? even if it has problems such as question referred to
---+ 4: WHY I THINK I WANT THIS
Note: I say "I think I want this" because I am open to the possibility of some other solution. But I also expect the usual misunderstandings.
There are at least two reasons why I want this, the most recent reason probably being more acceptable, and a historic reason that I have wanted this since the 1980s. I've lived without it so far, but the new reason is harder to work around not having this wrapping mode for key-bindings.
Reasons:
(1) speech recognition, want to avoid accidental emacs command invocation on misrecognitions
(2) ... I'll explain this original reason later ...
---++ 4.1: SPEECH RECOGNITION
In the original post of this question I provided much too much detail, which I have moved to https://github.com/AndyGlew/manx-UI--Speech/wiki/Speech-Commands-for-EMACS
Briefly, I want to use speech recognition to control EMACS. Nuance Dragon speech recognition accuracy is IMHO good enough. The real problem is trying to control EMACS via keyboard and mouse events (so don't do that), and interference with existing emacs key-bindings.
The big problem with automating nearly any WIMP application is controlling it by sending key and mouse events. Especially when the key and mouse command bindings are highly context-sensitive, and when the speech system cannot determine what the present context is.
Fortunately, EMACS can be controlled by commands: esc-X some-command [enter]
. Although many emacs commands are not convenient to say by voice, this problem can be solved.
The second problem is interference with existing emacs key-bindings. For the most part I do not want to completely disable all emacs key-bindings. I can still type; I just want to reduce my typing is more I type more I hurt. In Dragon I usually use "normal mode", where dictation and speech commands are intermixed.
Unfortunately speech recognition is imperfect, and occasionally "foo" is interpreted as "bar". This is not so bad if dictating text, ordinary printable characters. But in packages like the Gnus mailreader, if the user interface binds commands to unmodified keystrokes, bad things can happen.
This problem is not specific to EMACS. e.g. Thunderbird is a similar vendor, so much so that I actually disable unmodified letters in the main Thunderbird window. But it is a pain to turn such a letter chill mode on and off.
It should be possible to do better with EMACS. in the terms are used above:
A (W0') mode, adapted so that any key sequence that begins with an unmodified letter is restricted, But he sequences that begin with modifiers such as control or meta- are allowed. This is how I might normally work, intermixing dictation of ordinary text and modified key sequences, with the option of escaping to legacy key sequences that have been disabled to avoid interference with speech.
Plus the (W+1) mode that is essentially legacy EMACS key-bindings.
---++ 4.2: an older reason
I admit to an older reason to want to do this wrapping: I have had this computeritis for years. It got suddenly worse when I first started using EMACS, because as I'm sure you know emacs key-bindings use lots and lots of modifiers. Typing those is a really big cause of my computeritis/repetitive motion syndrome/Repetitive stress injury/... even RMS (Stallman) has had RMS/RSI.
Therefore many years ago I created my own set of key-bindings or emacs that are less stressful on my hands. In many ways they are much like VI's key-bindings, where the most frequent commands are often just the same letter pressed over again, possibly with slightly different modifiers. I did not completely reimplement VI, but I broke many of the rules for emacs key-bindings in much the same way that evil-mode now does.
Hence, the desire to completely wrap key-bindings defined by packages other than my own. I want to still access, with the prefix, or if I disable my mode. Yada yada yada
---+ 5: Mouse Bindings
Interestingly, I have much less need to override or wrap mouse findings. speech recognition errors usually do not emit mouse events by accident
---+ 6: pontificating: separate functionality from user interface
IMHO it is unfortunate that many emacs packages intermix the functions and the key-bindings. In my own packages I try to separate the code that does stuff from the user interface. I might have separate .EL files, or I might have a function that installs my normal bindings. If you don't want my bindings, you can still load my library, just not run my key-bindings function.