2

---+ 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

  • if the wrap code were not running or installed and there is a keybinding K1 ... Kn
  • then if the wrap code is installed
    • 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

    1. 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

    2. Although simple enough for global-map, it is more awkward for other maps such as local-map, minor-mode-map-alist, overriding-local-map, etc.

    3. 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.

    2 Answers 2

    0

    Your question seems discursive and poorly organized, but I think that I understand the gist of it. It also contains some errors that I presume result from using voice recognition.

    I think that you want to add a prefix to all keys.

    You should read chapter 22 Keymaps of the Emacs Lisp manual for all of the details, but perhaps you could do something like this:

    (let ((new-global-map (make-sparse-keymap)))
      (define-key new-global-map (kbd "C-x") global-map)
      (setq global-map new-global-map))
    

    This replaces the global key map with a new keymap containing only a prefix key which allows access to the original global map. However, this will not entirely work because global-map is not the only active keymap. See chapter 22.7 Active Keymaps for the details, but basically the major and minor modes all have keymaps too. You would need to modify them all in the same way.

    You might also look into modifying how Emacs searches these maps; it may be easier to add your global prefix there than it is to modify every single keymap for every single minor mode. An overview of that process is given in chapter 22.8 Searching the Active Keymaps, but you will need to read the Emacs source for the full story.

    Good luck!

    4
    • My bad, I will refactor by reducing StackExchange question and moving the background to my wiki on speech issues. in my defense: I added the long explanation of speech issues because I see many StackExchange questions (emacs and elsewhere) where one of the first comments is "don't ask a low level coding question, instead explain why you want to do it". Also, trying to anticipate off target answers.
      – Krazy Glew
      Jul 13, 2021 at 20:25
    • Amusingly, I decided not to add a section explaining why what you suggest is unsatisfactory. Even in the 1980s I realized it has problems such as: * Layering (doing this for local map, etc.). * Surviving extensions - IIRC back then there were no overriding keymaps, etc., so it broke every time a new such layer of key mapping was added. // AFAICT the best way to solve such problems is to override the command loop, and even that is imperfect. // After I have cleaned out the excess verbiage I might add a section to the question following up on this comment.
      – Krazy Glew
      Jul 13, 2021 at 20:38
    • I should probably have used a term other than "amusingly" in the previous comment. Verbosely "annoying, in a rather amusing way". "Ironically" isn't quite right, since I expected it. Frankly I ran out of time and my wife was calling me.
      – Krazy Glew
      Jul 14, 2021 at 21:07
    • I forgot one of the most important problems with the "override global-map (and local-map, and override-maps, and ...)" approach: it is a backward fix but not forward fix as bindings in the same session are set. Subsequent calls that create new global key-bindings will put them in new-global-map, which is now global-map. this is what I try to anticipate when I said "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" in the original question.
      – Krazy Glew
      Jul 14, 2021 at 21:11
    0

    partial solution

    • not necessarily to the question of how to wrap all emacs key-bindings, whether by overriding the command loop or some other way
    • but a solution to the 1st use case I listed in the original question --- which I subsequently removed because the 1st responder said it was too much detail, to discursive

    One of my big problems with speech recognition and emacs is that for the most part Dragon controls target applications by sending keyboard and mouse events. Fortunately in emacs I can send commands via M-X, but there remain problems: In particular it causes a big problem when a Dragon speech command targeting emacs is misrecognized as dictation, emitting ordinary unmodified letters, in an emacs mode like the Gnus mailreader where many commands do not have modifiers.

    also, certain Dragon ordinary dictation words are Unicode, and at the very least are interpreted as repeat counts on emacs commands and letters, but also occasionally as modifiers. similarly for some unknown reason certain keystrokes from Dragon have bit 8 set.

    I wanted to wrap emacs key mappings to ignore keystrokes related to some of these errors. I have not yet found any satisfactory solution within emacs.

    But in my original post I mentioned that in Thunderbird I have created an AutoHotKey script that disables all unmodified letters in the main Thundebird window, since Thunderbird has the same problem with unmodified keyboard shortcuts.

    This solution was not working for GNU emacs, because Dragon has limited knowledge of application context, based mainly on the window title. I have already modified my .emacs to put the major mode in the window title, but that does distinguish between when I want to send dictation and when I do not.

    Doh!

    I just realized that I can have emacs code, perhaps a minor mode, that indicates whether emacs command/key-bindings other than M-X or the like are allowed by modifying the window title. And I can have an AutoHotKey command that does letter telling based on that window title context.

    Doh! once again, the solution to a Dragon speech recognition problem and a target at is to do it in AutoHotKey.


    This does not immediately solve the 2nd use case for such keystroke lookup ramping in emacs, where I want to completely override the standard mappings but still have them accessible, in such a way that subsequent legacy key-bindings still work.

    ... although I'm brainstorming about ways of using AutoHotKey to accomplish the 2nd use case as well.


    I may let this Q&A into 2 parts, one with this partial answer, and the original question about wrapping keyboard mappings in emacs. even if it is possible to use AutoHotKey to solve the problem completely, I would prefer to have a purely emacs solution, not least because AutoHotKey is not available on Linux (and I would prefer not to have to create a TTY driver that does the same thing - although I have long wanted AutoHotKey functionality on Linux and Mac OS - and I wrote such a TTY driver a long time ago in a galaxy far far away).

    for the moment, I am going to mark this question as answered, even though it is only partially answered -- since StackExchange has no way of indicating such a partial answer. When I have refactored the question, I will rearrange the checkmark status.


    BTW, this was not a setup so that I could do a self answer question. I truly had not figured out how to do this AutoHotKey partial solution, until just a few minutes ago. Doh!

    Your Answer

    By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

    Not the answer you're looking for? Browse other questions tagged or ask your own question.