emacs-elpa-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[elpa] externals/ergoemacs-mode 97a2107 243/325: Add back the command lo


From: Stefan Monnier
Subject: [elpa] externals/ergoemacs-mode 97a2107 243/325: Add back the command loop. Part of it seems broken
Date: Sat, 23 Oct 2021 18:49:02 -0400 (EDT)

branch: externals/ergoemacs-mode
commit 97a21072a794199b54ad9000f7ebde49befc7894
Author: Matthew Fidler <514778+mattfidler@users.noreply.github.com>
Commit: Matthew Fidler <514778+mattfidler@users.noreply.github.com>

    Add back the command loop.  Part of it seems broken
---
 ergoemacs-command-loop.el | 1646 ++++++++++++++++++++++++++++++++++++++++++++-
 ergoemacs-macros.el       |   34 +
 ergoemacs-mode.el         |    6 +
 ergoemacs-themes.el       |  106 +++
 ergoemacs-translate.el    |  207 +++++-
 5 files changed, 1958 insertions(+), 41 deletions(-)

diff --git a/ergoemacs-command-loop.el b/ergoemacs-command-loop.el
index a8bbb22..af73e3e 100644
--- a/ergoemacs-command-loop.el
+++ b/ergoemacs-command-loop.el
@@ -35,6 +35,9 @@
   (require 'ergoemacs-macros))
 
 
+(declare-function ergoemacs-translate--emacs-shift "ergoemacs-translate")
+(declare-function ergoemacs-warn "ergoemacs-lib")
+
 (declare-function guide-key/close-guide-buffer "guide-key")
 (declare-function guide-key/popup-function "guide-key")
 
@@ -43,6 +46,9 @@
 
 (declare-function ergoemacs-mode-line "ergoemacs-mode")
 
+(declare-function ergoemacs-layout--regexp "ergoemacs-layouts")
+(declare-function ergoemacs-layouts--list "ergoemacs-layouts")
+
 (declare-function ergoemacs-map-properties--movement-p 
"ergoemacs-map-properties")
 (declare-function ergoemacs-map-properties--put "ergoemacs-map-properties")
 
@@ -64,6 +70,7 @@
 (declare-function ergoemacs-translation-struct-p "ergoemacs-translate")
 (declare-function ergoemacs-translation-struct-text "ergoemacs-translate")
 (declare-function ergoemacs-translation-struct-translation 
"ergoemacs-translate")
+(declare-function ergoemacs-translation-struct-unchorded "ergoemacs-translate")
 
 (declare-function ergoemacs-key-description--modifier 
"ergoemacs-key-description")
 
@@ -83,10 +90,15 @@
 (defvar ergoemacs-default-cursor-color)
 (defvar ergoemacs-echo-function)
 (defvar ergoemacs-map--quit-map)
+(defvar ergoemacs-modal-emacs-state-modes)
+(defvar ergoemacs-modal-ignored-buffers)
+(defvar ergoemacs-modal-ignored-keymap)
 (defvar ergoemacs-mode-started-p)
 (defvar guide-key/guide-key-sequence)
 (defvar keyfreq-mode)
 (defvar keyfreq-table)
+(defvar ergoemacs-translate--emacs-shift)
+(defvar ergoemacs-command-loop-start)
 
 
 (defvar universal-argument-num-events) ;; Not in Emacs 24.5
@@ -96,6 +108,12 @@
 (defvar ergoemacs-command-loop--mark-active nil
   "Determines if mark was active before ergoemacs command loop.")
 
+(define-obsolete-variable-alias 'ergoemacs-universal-fns 
'ergoemacs-command-loop--universal-functions "Ergoemacs-v5.16")
+
+
+(defvar ergoemacs-command-loop--universal-functions '(universal-argument 
ergoemacs-universal-argument ergoemacs-command-loop--universal-argument)
+  "List of `ergoemacs-mode' recognized functions.")
+
 
 (defvar ergoemacs-command-loop--next-key-hash
   (let ((hash (make-hash-table)))
@@ -115,6 +133,14 @@
 
 (defvar ergoemacs-command-loop--help-last-key nil)
 
+(define-obsolete-variable-alias 'ergoemacs-read-key-delay 
'ergoemacs-command-loop--decode-event-delay "Ergoemacs-v5.16")
+
+(defvar ergoemacs-command-loop--decode-event-delay 0.01
+  "Timeout for `ergoemacs-command-loop--decode-event'.
+This is to distinguish events in a terminal, like xterm.
+
+It needs to be less than `ergoemacs-command-loop-blink-rate'.")
+
 (defvar ergoemacs-command-loop--history nil
   "History of command loop locations.")
 
@@ -155,15 +181,163 @@ ignore the post-command hooks.")
 (defvar ergoemacs-command-loop--echo-keystrokes-complete nil
   "Echoed keystrokes, keep echoing active.")
 
-(defvar ergoemacs-command-loop-swap-translation)
+(defvar ergoemacs-command-loop--modal-stack '()
+  "The Modal Stack.")
+
+(defcustom ergoemacs-command-loop-swap-translation
+  '(((:normal :normal) :unchorded-ctl)
+    ((:normal :unchorded-ctl) :ctl-to-alt)
+    ((:normal :unchorded-ctl) :normal)
+    ((:ctl-to-alt :ctl-to-alt) :unchorded-ctl)
+    ((:ctl-to-alt :unchorded-ctl) :ctl-to-alt)
+    ((:unchorded-ctl :unchorded-ctl) :ctl-to-alt)
+    ((:unchorded-ctl :ctl-to-alt) :unchorded-ctl))
+  "How the translation will be swapped."
+  :type '(repeat
+          (list
+           (list
+            (sexp :tag "First Type")
+            (sexp :tag "Current Type"))
+           (sexp :tag "Translated Type")))
+  :group 'ergoemacs-command-loop)
+
+(defcustom ergoemacs-command-loop-blink-character (ergoemacs :unicode-or-alt 
"•" "·" "-")
+  "Blink character."
+  :type '(choice
+          (string :tag "Cursor")
+          (const :tag "No cursor" nil))
+  :group 'ergoemacs-command-loop)
+
+(defcustom ergoemacs-command-loop-blink-rate 0.4
+  "Rate that the ergoemacs-command loop cursor blinks."
+  :type 'number
+  :group 'ergoemacs-command-loop)
+
+(defcustom ergoemacs-command-loop-type nil
+  "Type of `ergoemacs-mode' command loop."
+  :type '(choice
+          (const :tag "Replace emacs command loop (full)" :full)
+          ;; (const :tag "Test mode; Don't actually run command " :test)
+          (const :tag "No command loop support" nil))
+  :group 'ergoemacs-comamnd-loop)
+
+(defcustom ergoemacs-command-loop-hide-shift-translations t
+  "Hide shift translations in the command loop help."
+  :type 'boolean
+  :group 'ergoemacs-command-loop)
+
+
+(defcustom ergoemacs-command-loop-echo-keystrokes 1
+  "The amount of time before `ergoemacs-mode' displays keystrokes."
+  :type 'number
+  :group 'ergoemacs-command-loop)
+
+(defcustom ergoemacs-command-loop-timeout 2
+  "The number of seconds before hook has froze."
+  :type 'number
+  :group 'ergoemacs-command-loop)
+
+(defcustom ergoemacs-echo-function :on-translation
+  "Shows the function evaluated with a key."
+  :type '(choice
+          (const :tag "Always echo" t)
+          (const :tag "For multi-key commands" :multi-key)
+          (const :tag "Echo on translations" :on-translation)
+          (const :tag "Don't Echo" nil))
+  :group 'ergoemacs-command-loop)
+
+
+
 (defvar ergoemacs-command-loop-time-before-blink)
-(defvar ergoemacs-command-loop-blink-character)
-(defvar ergoemacs-command-loop-blink-rate)
+(defvar ergoemacs-command-loop-hide-shift-translations)
 (defvar ergoemacs-mode)
 (defvar ergoemacs-command-loop-type)
 (defvar ergoemacs-keymap)
+(defvar ergoemacs-handle-ctl-c-or-ctl-x 'only-C-c-and-C-x)
+(defvar ergoemacs-ctl-c-or-ctl-x-delay)
 
 
+(defun ergoemacs-command-loop--modal-show ()
+  "Show modal translation.
+Returns the mode-line text."
+  (let (tmp color text)
+    (ergoemacs-save-buffer-state
+     (cond
+      ((setq tmp (ergoemacs :modal-p))
+       (setq color (ergoemacs-translation-struct-modal-color tmp))
+       (if color
+           (set-cursor-color color)
+         (when ergoemacs-default-cursor-color
+           (set-cursor-color ergoemacs-default-cursor-color)))
+       (setq text (ergoemacs-translation-struct-text tmp))
+       (when (functionp text)
+         (setq text (funcall text)))
+       (if text
+           (ergoemacs-mode-line ;; Indicate Alt+ in mode-line
+            text)
+         (ergoemacs-mode-line))
+       (or text "Unnamed"))
+      (t
+       (when ergoemacs-default-cursor-color
+         (set-cursor-color ergoemacs-default-cursor-color))
+       (ergoemacs-mode-line)
+       nil)))))
+
+(defun ergoemacs-command-loop--match-buffer-name-p (reg)
+  "Determine if the REG is found in `buffer-name'."
+  (and (stringp (buffer-name))
+       (string-match reg (buffer-name))))
+
+(defun ergoemacs-command-loop--modal-p ()
+  "Determine if the command should be modal.
+If so return the translation."
+  (if (not ergoemacs-command-loop--modal-stack) nil
+    (let* ((translation (nth 0 ergoemacs-command-loop--modal-stack))
+           (always)
+           ret)
+      (when (ergoemacs-translation-struct-p translation)
+        (setq always (ergoemacs-translation-struct-modal-always translation))
+        (cond
+         ((and (minibufferp)
+               (not always)))
+         ((and (not always)
+               (memq major-mode ergoemacs-modal-emacs-state-modes)))
+         ((and (not always)
+               (catch 'match-modal
+                 (dolist (reg ergoemacs-modal-ignored-buffers)
+                   (when (ergoemacs-command-loop--match-buffer-name-p reg)
+                     (throw 'match-modal t)))
+                 nil)))
+         (t
+          (setq ret translation))))
+      ret)))
+
+(defun ergoemacs-command-loop--modal-pop ()
+  "Turn off the last ergoemacs modal in the modal-stack."
+  (when ergoemacs-command-loop--modal-stack
+    (ergoemacs-command-loop--modal (ergoemacs-translation-struct-key (nth 0 
ergoemacs-command-loop--modal-stack)))))
+
+(defun ergoemacs-command-loop--modal (type)
+  "Toggle ergoemacs command modes.
+
+The TYPE is the type of command translation/modal keymaps that are installed."
+  (cond
+   ((or (not ergoemacs-command-loop--modal-stack) ;; First time to turn on
+        (not (eq (ergoemacs-translation-struct-key (nth 0 
ergoemacs-command-loop--modal-stack)) type)) ;; New modal 
+        )
+    (push (ergoemacs-translate--get type) ergoemacs-command-loop--modal-stack)
+    (unless ergoemacs-default-cursor-color
+      (setq ergoemacs-default-cursor-color
+            (or (frame-parameter nil 'cursor-color) "black")))
+    (ergoemacs-command-loop--message "%s command mode installed" 
(ergoemacs-command-loop--modal-show)))
+   
+   (t ;; Turn off.
+    (setq ergoemacs-command-loop--modal-stack (cdr 
ergoemacs-command-loop--modal-stack))
+    (if (ergoemacs :modal-p)
+        (ergoemacs-command-loop--message "%s command mode resumed." 
(ergoemacs-command-loop--modal-show))
+      (ergoemacs-command-loop--modal-show)
+      (ergoemacs-command-loop--message "Resume regular ergoemacs-mode")))))
+
 (defun ergoemacs-command-loop--redefine-quit-key (&optional key)
   "Redefines the quit-key in Emacs to KEY or Ctrl+g.
 
@@ -196,6 +370,65 @@ with this function."
             (throw 'found-quit t)))
         nil))))
 
+(add-hook 'ergoemacs-mode-startup-hook 
#'ergoemacs-command-loop--setup-quit-key)
+(add-hook 'ergoemacs-mode-shutdown-hook 
#'ergoemacs-command-loop--redefine-quit-key)
+
+(defun ergoemacs-command-loop--universal-argument (&rest _ignore)
+  "`ergoemacs-mode' universal argument.
+This is called through `ergoemacs-command-loop'"
+  (interactive)
+  (cond
+   ((not (ergoemacs-command-loop-p)) 
+    ;; Command loop hasn't started.
+    (setq current-prefix-arg '(4))
+    (setq ergoemacs-command-loop-start t)
+    (ergoemacs-command-loop nil (ergoemacs-command-loop--modal-p) nil t))
+   ((not current-prefix-arg)
+    (setq current-prefix-arg '(4)
+          ergoemacs-command-loop--universal t
+          ergoemacs-command-loop--exit :ignore-post-command-hook))
+   ((listp current-prefix-arg)
+    ;; Change current prefix argument
+    (setq current-prefix-arg (list (* (nth 0 current-prefix-arg) 4))
+          ergoemacs-command-loop--universal t
+          ergoemacs-command-loop--exit :ignore-post-command-hook))
+   (t
+    (setq ergoemacs-command-loop--universal t
+          ergoemacs-command-loop--exit :ignore-post-command-hook))))
+
+(defalias 'ergoemacs-read-key--universal-argument 
'ergoemacs-command-loop--universal-argument)
+
+(defalias 'ergoemacs-universal-argument 
'ergoemacs-command-loop--universal-argument)
+
+(defun ergoemacs-command-loop--digit-argument (&optional type)
+  "Ergoemacs digit argument.
+
+This is called through `ergoemacs-command-loop'.
+
+TYPE is the keyboard translation type, defined by `ergoemacs-translate'.
+Ergoemacs-mode sets up: :ctl-to-alt :unchorded :normal."
+  (interactive)
+  (let* ((char (if (integerp last-command-event)
+                   last-command-event
+                 (get last-command-event 'ascii-character)))
+         (digit (- (logand char ?\177) ?0)))
+    (setq current-prefix-arg digit))
+  (ergoemacs-command-loop nil type nil t))
+
+(defalias 'ergoemacs-digit-argument 'ergoemacs-command-loop--digit-argument)
+
+(defun ergoemacs-command-loop--negative-argument (&optional type)
+  "Ergoemacs negative argument.
+
+This is called through `ergoemacs-command-loop'.
+
+TYPE is the keyboard translation type, defined by `ergoemacs-translate'
+Ergoemacs-mode sets up: :ctl-to-alt :unchorded :normal."
+  (setq current-prefix-arg '-)
+  (ergoemacs-command-loop nil type nil t))
+
+(defalias 'ergoemacs-negative-argument 
'ergoemacs-command-loop--negative-argument)
+
 (dolist (arg '((next-key-is-alt (meta))
                (next-key-is-meta (meta))
                (next-key-is-ctl (control))
@@ -205,7 +438,7 @@ with this function."
                (next-key-is-control-meta (control meta))
                (next-key-is-meta-control (control meta))
                (next-key-is-quoted nil)))
-  (eval (macroexpand-all
+  (eval (macroexpand-all    ;FIXME: Why macroexpand-all?
          `(progn
             (defun ,(intern (concat "ergoemacs-command-loop--" (symbol-name 
(nth 0 arg)))) ()
               ,(format "Ergoemacs function to allow %s to be the emacs 
modifiers" (nth 1 arg))
@@ -220,7 +453,8 @@ with this function."
               (message "Dummy Function for %s" (ergoemacs :modifier-desc ,(nth 
1 arg))))
             (defalias ',(intern (concat "ergoemacs-read-key-force-" 
(symbol-name (nth 0 arg)))) ',(intern (concat "ergoemacs-command-loop--force-" 
(symbol-name (nth 0 arg)))))
             (puthash ',(intern (concat "ergoemacs-command-loop--force-" 
(symbol-name (nth 0 arg)))) '(,(nth 1 arg) :force) 
ergoemacs-command-loop--next-key-hash)
-            (puthash ',(intern (concat "ergoemacs-read-key-force-" 
(symbol-name (nth 0 arg)))) '(,(nth 1 arg) :force) 
ergoemacs-command-loop--next-key-hash)))))
+            (puthash ',(intern (concat "ergoemacs-read-key-force-" 
(symbol-name (nth 0 arg)))) '(,(nth 1 arg) :force) 
ergoemacs-command-loop--next-key-hash)
+           t))))
 
 (defvar ergoemacs-last-command-event nil
   "`ergoemacs-mode' command loop last read command.")
@@ -321,12 +555,12 @@ UNIVERSAL"
                     (and (not universal) "")
                     (or (and (string= ergoemacs-command-loop--read-key-prompt 
"") "") " ")
                     (and ergoemacs-command-loop-blink-character
-                         (or (and blink-on 
ergoemacs-command-loop-blink-character)
+                         (or (and blink-on (ergoemacs :unicode-or-alt 
ergoemacs-command-loop-blink-character "-"))
                              " "))
                     " ")
                    (or
                     (and (not universal) "")
-                    "▸")))
+                    (ergoemacs :unicode-or-alt "▸" ">"))))
       (format
        "%s%s%s %s "
        (cond
@@ -335,13 +569,25 @@ UNIVERSAL"
         (t current-prefix-arg))
        (or (and (not universal) "")
            (and ergoemacs-command-loop-blink-character
-                (or (and blink-on ergoemacs-command-loop-blink-character)
+                (or (and blink-on (ergoemacs :unicode-or-alt 
ergoemacs-command-loop-blink-character "-"))
                     " "))
            " ")
        (or (and (listp current-prefix-arg)
                 (format "%s" current-prefix-arg))
            "")
-       "▸")))
+       (ergoemacs :unicode-or-alt "▸" ">"))))
+
+(defun ergoemacs-command-loop--ensure-sane-variables ()
+  "Make sure that certain variables won't lock up Emacs.
+
+Currently this ensures:
+
+`ergoemacs-command-loop--decode-event-delay' is less than 
`ergoemacs-command-loop-blink-rate'."
+  (when (>= ergoemacs-command-loop--decode-event-delay 
ergoemacs-command-loop-blink-rate)
+    (ergoemacs-warn "ergoemacs-command-loop--decode-event-delay >= 
ergoemacs-command-loop-blink-rate; Reset to ergoemacs-command-loop-blink-rate / 
1000")
+    (setq ergoemacs-command-loop--decode-event-delay (/ 
ergoemacs-command-loop-blink-rate 1000))))
+
+(add-hook 'ergoemacs-mode-startup-hook 
#'ergoemacs-command-loop--ensure-sane-variables)
 
 (defun ergoemacs-command-loop--combine (current-key next-event)
   "Combine CURRENT-KEY and NEXT-EVENT into a vector."
@@ -409,13 +655,19 @@ This is not done when the event is [ergoemacs-ignore]"
                      ((not (stringp prompt)))
                      ((not (string= "" 
ergoemacs-command-loop--read-key-prompt)) prompt)
                      ((or (string= prompt " ")
-                          (string-match-p prompt (concat " *" 
ergoemacs-command-loop-blink-character " *")))
+                          (string-match-p prompt (concat " *" (ergoemacs 
:unicode-or-alt ergoemacs-command-loop-blink-character "-") " *")))
                       nil)
                      (ergoemacs-command-loop--universal prompt)
                      (ergoemacs-command-loop--echo-keystrokes-complete prompt)
                      ((not (numberp ergoemacs-command-loop-echo-keystrokes)) 
prompt)
                      ((= 0 ergoemacs-command-loop-echo-keystrokes) prompt)
                      ((< last-event-time 
ergoemacs-command-loop-echo-keystrokes) nil)
+                     ;; ((and (not 
ergoemacs-command-loop--echo-keystrokes-complete)
+                     ;;       (numberp ergoemacs-command-loop-echo-keystrokes)
+                     ;;       (or (= 0 ergoemacs-command-loop-echo-keystrokes)
+                     ;;           (< last-event-time 
ergoemacs-command-loop-echo-keystrokes))) nil)
+                     ;; ((and (< last-event-time 
ergoemacs-command-loop-time-before-blink) (string= prompt "")) nil)
+                     ;; ((and (< last-event-time 
ergoemacs-command-loop-time-before-blink) ) nil)
                      (t
                       (setq ergoemacs-command-loop--echo-keystrokes-complete t)
                       prompt)))
@@ -455,6 +707,120 @@ This is not done when the event is [ergoemacs-ignore]"
                  last-event-frame (selected-frame))))
        event)))
 
+(defvar ergoemacs-command-loop--decode-event-timeout-p nil
+  "Determines if `ergoemacs-command-loop--decode-event' timed out.")
+
+(defun ergoemacs-command-loop--decode-event (event keymap &optional 
current-key)
+  "Change EVENT based on KEYMAP.
+
+Used to help with translation keymaps like `input-decode-map'.
+
+CURRENT-KEY is the current key being read.  This is used
+inconjunction with `input-method-function' to translate keys if
+`set-input-method' is using a different keyboard layout."
+  (let* ((new-event event)
+         (old-ergoemacs-input unread-command-events)
+         new-ergoemacs-input
+         (current-test-key (or (and (listp event)
+                                   (vector 
(ergoemacs-translate--event-convert-list
+                                            (append 
(ergoemacs-translate--event-modifiers event)
+                                                    (list 
(ergoemacs-translate--event-basic-type event))))))
+                              (vector event)))
+         (test-ret (lookup-key keymap current-test-key))
+        (timeout-key (key-binding (vconcat current-test-key 
[ergoemacs-timeout])))
+         next-key)
+    (while (and current-test-key
+                (ergoemacs-keymapp test-ret))
+      ;; The translation needs more keys...
+      (if timeout-key
+         (setq next-key (with-timeout (ergoemacs-ctl-c-or-ctl-x-delay
+                                       (progn
+                                         (setq 
ergoemacs-command-loop--decode-event-timeout-p t)
+                                         nil))
+                          (ergoemacs-command-loop--history nil 
ergoemacs-command-loop--decode-event-delay current-key)))
+       (setq next-key (ergoemacs-command-loop--history nil 
ergoemacs-command-loop--decode-event-delay current-key)))
+      (when next-key ;; Since a key was read, save it to be read later.
+        (push last-command-event new-ergoemacs-input))
+      (if next-key
+          (setq current-test-key (ergoemacs :combine current-test-key next-key)
+               timeout-key (key-binding (vconcat current-test-key 
[ergoemacs-timeout]))
+                test-ret (lookup-key keymap current-test-key))
+        (setq current-test-key nil)))
+    ;; Change strings to emacs keys.
+    (when (stringp test-ret)
+      ;; Should it be read-kbd-macro?
+      (setq test-ret (vconcat test-ret)))
+    (when (functionp test-ret)
+      (when (memq test-ret '(xterm-mouse-translate 
xterm-mouse-translate-extended))
+       (message "xterm-mouse-translate: %s->%s" current-test-key (funcall 
test-ret nil)))
+      (setq last-input-event event
+           test-ret (if (or (eq keymap input-decode-map)
+                            (eq keymap key-translation-map)
+                            (eq keymap local-function-key-map))
+                        (funcall test-ret nil) ;; Pretend emacs called this 
from command loop.
+                      (funcall test-ret)))
+      (when (not (equal unread-command-events old-ergoemacs-input))
+       (push (pop unread-command-events) new-ergoemacs-input)))
+    (if (and (vectorp test-ret)
+             (= (length test-ret) 1))
+        (progn
+          (setq new-event (elt test-ret 0)))
+      ;; Not a new event, restore anything that was popped off the
+      ;; unread command events.
+      (when old-ergoemacs-input
+        (setq unread-command-events old-ergoemacs-input))
+      ;; Add anything read to the
+      ;; unread-command-events
+      (when new-ergoemacs-input
+        (setq unread-command-events (append new-ergoemacs-input 
unread-command-events))))
+    new-event))
+
+(defun ergoemacs-command-loop--read-event (prompt &optional current-key)
+  "Read a single event.
+
+PROMPT is the prompt used when reading an event.
+
+CURRENT-KEY is the current key sequence that has alerady been
+read.
+
+This respects `input-decode-map', `local-function-key-map' and
+`key-translation-map'.
+
+It also inputs real read events into the history with
+`ergoemacs-command-loop--history'
+
+It will timeout after `ergoemacs-command-loop-blink-rate' and
+return nil."
+  (let ((input (ergoemacs-command-loop--history prompt 
ergoemacs-command-loop-blink-rate current-key))
+        last-input
+        basic mods
+        binding gui)
+    ;; Fix issues with `input-decode-map'
+    (when input
+      ;; Fix input as if you defined C-i -> <C-i> on `input-decode-map'
+      ;; 
http://emacs.stackexchange.com/questions/10271/how-to-bind-c-for-real-seriously-for-real-this-time/15174
+      (if (and (display-graphic-p)
+               (setq basic (event-basic-type input))
+               (memq basic (list 'i 'm '\[ ?i ?m ?\[))
+               (setq mods (event-modifiers input))
+               (memq 'control mods)
+               (setq gui (ergoemacs-translate--event-convert-list (append 
(list 'ergoemacs-gui) mods (list basic))))
+               (setq binding (key-binding (ergoemacs :combine current-key 
input) t)))
+          (setq input gui)
+        (setq input (ergoemacs-command-loop--decode-event input 
input-decode-map current-key)
+              binding (key-binding (ergoemacs :combine current-key input) t)))
+      ;; These should only be replaced if they are not bound.
+      (unless binding
+        (setq last-input input
+              input (ergoemacs-command-loop--decode-event input 
local-function-key-map current-key))
+        (unless (eq last-input input)
+          (setq binding (key-binding (ergoemacs :combine current-key input) 
t))))
+      (setq last-input input
+           input (ergoemacs-command-loop--decode-event input 
key-translation-map current-key))
+      (unless (eq last-input input)
+       (setq binding (key-binding (ergoemacs :combine current-key input) t))))
+    input))
+
 (defun ergoemacs-command-loop--key-msg (blink-on universal text current-key 
unchorded trans keys)
   "Key message.
 
@@ -482,7 +848,7 @@ KEYS is the keys information"
          (or (and (string= ergoemacs-command-loop--read-key-prompt "") "") " ")
          (or (and universal "")
              (and ergoemacs-command-loop-blink-character
-                  (or (and blink-on ergoemacs-command-loop-blink-character)
+                  (or (and blink-on (ergoemacs :unicode-or-alt 
ergoemacs-command-loop-blink-character "-"))
                       " "))
              " ")
          trans
@@ -495,6 +861,308 @@ KEYS is the keys information"
 (defvar ergoemacs-command--timeout-timer nil)
 (defvar ergoemacs-command--timeout-keys nil)
 
+(defun ergoemacs-command--timer-timeout ()
+  "Send the [ergoemacs-timeout] event (after timeout)."
+  (let ((keys (this-single-command-keys)))
+    (when ergoemacs-command--timeout-timer
+      (cancel-timer ergoemacs-command--timeout-timer)
+      (setq ergoemacs-command--timeout-timer nil)
+      (when (equal keys ergoemacs-command--timeout-keys)
+       (push 'ergoemacs-timeout unread-command-events))
+      (setq ergoemacs-command--timeout-keys nil))))
+
+(defvar ergoemacs-this-command-keys-shift-translated nil
+  "ergoemacs override of shift translation in command loop.")
+
+(defun ergoemacs-command--echo-prefix ()
+  "Echos prefix keys in the ergoemacs-mode way."
+  (let ((keys (this-single-command-keys)))
+    (when (and ergoemacs-command--timeout-timer
+              (not (equal keys ergoemacs-command--timeout-keys)))
+      (cancel-timer ergoemacs-command--timeout-timer)
+      (setq ergoemacs-command--timeout-keys nil
+           ergoemacs-command--timeout-timer nil))
+    (unless (or (equal [] keys)
+               (ergoemacs-command-loop-p))
+      (when (ergoemacs-keymapp (key-binding keys))
+       (when (key-binding (vconcat keys [ergoemacs-timeout]))
+         (cond
+          ((eq ergoemacs-handle-ctl-c-or-ctl-x 'only-copy-cut) 
+           (push 'ergoemacs-timeout unread-command-events))
+          ((not (region-active-p))) ;; active
+          ((and (or ergoemacs-this-command-keys-shift-translated 
this-command-keys-shift-translated)
+                 (eq ergoemacs-handle-ctl-c-or-ctl-x 'both)))
+          ((and (not ergoemacs-ctl-c-or-ctl-x-delay) ;; Immediate
+                 (eq ergoemacs-handle-ctl-c-or-ctl-x 'both))
+           (push 'ergoemacs-timeout unread-command-events))
+           (t
+            (setq ergoemacs-command--timeout-keys keys
+                 ergoemacs-command--timeout-timer
+                  (run-at-time t ergoemacs-ctl-c-or-ctl-x-delay 
#'ergoemacs-command--timer-timeout)))))
+        (unless unread-command-events
+         (ergoemacs-command-loop--message
+          "%s" (ergoemacs-command-loop--key-msg
+                (setq ergoemacs-command--blink-on (not 
ergoemacs-command--blink-on))
+                nil nil
+                (this-single-command-keys)
+                nil nil nil)))))))
+
+(defun ergoemacs-command--echo-timer ()
+  "Echo the keystrokes in the `ergoemacs-mode' way."
+  (when (and (not ergoemacs-command-loop-type)
+            (not erogemacs-command--echo-timer))
+    (unless ergoemacs-orig-echo-keystrokes
+      (setq ergoemacs-orig-echo-keystrokes echo-keystrokes))
+    (setq echo-keystrokes 0)
+    (setq erogemacs-command--echo-timer
+          (run-at-time t ergoemacs-command-loop-blink-rate 
#'ergoemacs-command--echo-prefix))))
+
+(defun ergoemacs-command--echo-timer-off ()
+  "Turn off the timer."
+  (setq echo-keystrokes ergoemacs-orig-echo-keystrokes)
+  (when erogemacs-command--echo-timer
+    (cancel-timer erogemacs-command--echo-timer)))
+
+(add-hook 'ergoemacs-post-command-hook #'ergoemacs-command--echo-timer)
+(add-hook 'ergoemacs-shutdown-hook #'ergoemacs-command--echo-timer-off)
+
+(defun ergoemacs-command-loop--read-key (&optional current-key type universal)
+  "Read a key for the `ergoemacs-mode' command loop.
+
+This uses `ergoemacs-command-loop--read-event'.
+
+CURRENT-KEY is the current key that is being read, the next key
+read will be appended to this key.
+
+TYPE is the type of translation being applied.  By default,
+the :normal traslation is used.
+
+UNIVERSAL flag telss if this is a univeral argument that is being
+read."
+  (let* ((universal universal)
+         (type (or type :normal))
+         (translation (ergoemacs-translate--get type))
+         (local-keymap (ergoemacs-translate--keymap translation))
+         (text (ergoemacs-translation-struct-text translation))
+         (unchorded (ergoemacs-translation-struct-unchorded translation))
+         (trans (ergoemacs-translation-struct-translation translation))
+         (modal (ergoemacs :modal-p))
+         (keys nil)
+         (blink-on nil)
+         input
+         raw-input
+         mod-keys tmp
+         reset-key-p
+         double)
+    ;; Setup modal translation
+    (when (and (eq type :normal) modal)
+      (setq type (ergoemacs-translation-struct-key modal)
+            local-keymap (ergoemacs-translation-struct-keymap-modal modal)
+            text (ergoemacs-translation-struct-text modal)
+            unchorded (ergoemacs-translation-struct-unchorded modal)
+            trans (ergoemacs-translation-struct-translation modal)
+            tmp translation
+            translation modal
+            modal tmp
+            tmp nil))
+    
+    ;; (ergoemacs-command-loop--read-key (read-kbd-macro "C-x" t) 
:unchorded-ctl)
+    (when (functionp text)
+      (setq text (funcall text)))
+
+    (when trans
+      ;; Don't echo the uncommon hyper/super/alt translations (alt is
+      ;; not the alt key...)
+      (dolist (tr trans)
+        (unless (or (memq 'hyper (nth 0  tr)) (memq 'super (nth 0 tr)) (memq 
'alt (nth 0 tr))
+                    (and ergoemacs-command-loop-hide-shift-translations (memq 
'shift (nth 0  tr))))
+          (if (member (list (nth 1 tr) (nth 0 tr)) trans)
+              (when (not (member (list (nth 1 tr) (nth 0 tr)) double))
+                (push tr double))
+            (push tr tmp))))
+      (setq trans tmp))
+    
+    (setq trans (or (and (or trans double)
+                         (concat "\nTranslations: "
+                                 (or (and double
+                                          (mapconcat
+                                           (lambda(elt)
+                                            ;; (and (setq tmp (elt current-key 
0))
+                                            ;;      (or (and (consp tmp) 
(symbolp (setq tmp (car tmp)))))
+                                            ;;      (stringp tmp)
+                                            ;;      (string-match-p 
"\\<mouse\\>" tmp))
+                                             (format "%s%s%s"
+                                                     (ergoemacs :modifier-desc 
(nth 0 elt))
+                                                     (ergoemacs 
:unicode-or-alt "↔" "<->")
+                                                     (ergoemacs :modifier-desc 
(nth 1 elt))))
+                                           double ", "))
+                                     "")
+                                 (or (and double trans ", ") "")
+                                 (mapconcat
+                                  (lambda(elt)
+                                    (format "%s%s%s"
+                                            (ergoemacs :modifier-desc (nth 0 
elt))
+                                            (ergoemacs :unicode-or-alt "→" 
"->")
+                                            (ergoemacs :modifier-desc (nth 1 
elt))))
+                                  trans ", "))) ""))
+    (maphash
+     (lambda(key item)
+       (let ((local-key (where-is-internal key local-keymap t))
+             tmp)
+         (when local-key
+           (setq tmp (format "%s%s%s"
+                             (ergoemacs-key-description local-key)
+                             (if (eq (nth 1 item) :force)
+                                 (ergoemacs :unicode-or-alt "⇒" "=>")
+                               (ergoemacs :unicode-or-alt "→" "->"))
+                             (ergoemacs :modifier-desc (nth 0 item))))
+           (push (elt local-key 0) mod-keys)
+           (setq keys (or (and (not keys) tmp)
+                          (and keys (concat keys ", " tmp)))))))
+     ergoemacs-command-loop--next-key-hash)
+
+    (setq keys (or (and keys (concat "\nKeys: " keys)) ""))
+    (setq unchorded (or (and unchorded (concat " " (ergoemacs :modifier-desc 
unchorded))) ""))
+    
+    (while (not input)
+      (while (not input)
+        (setq blink-on (not blink-on)
+              input (ergoemacs-command-loop--read-event
+                    (ergoemacs-command-loop--key-msg blink-on universal text 
current-key unchorded trans keys)
+                     current-key)))
+      (cond
+       ((and (setq trans (or (and (memq input mod-keys)
+                                  (ergoemacs-gethash (lookup-key local-keymap 
(vector input)) ergoemacs-command-loop--next-key-hash))
+                             (setq reset-key-p (ergoemacs-gethash (lookup-key 
local-function-key-map (ergoemacs :combine current-key input)) 
ergoemacs-command-loop--next-key-hash))))
+             (or (eq :force (nth 1 trans)) ;; Override any keys
+                 (not (key-binding (vconcat current-key 
(ergoemacs-translate--event-mods input trans)) t)) ;; Don't use if bound.
+                 ))
+        (setq trans (nth 0 trans)
+              unchorded (concat " " (ergoemacs :modifier-desc trans))
+              input nil)
+        ;; Changed behavior.
+        (while (not input)
+          (setq blink-on (not blink-on)
+                input (ergoemacs-command-loop--read-event
+                      (ergoemacs-command-loop--key-msg blink-on universal text 
current-key unchorded trans keys)
+                       current-key)))
+        (setq raw-input input
+              input (ergoemacs-translate--event-mods input trans)
+              last-command-event input
+              last-input-event input
+              ergoemacs-last-command-event last-command-event))
+       (t
+        ;; Translate the key appropriately.
+        (when (and modal (lookup-key ergoemacs-modal-ignored-keymap (vector 
input)))
+          ;; Swap back, or ignore the modal translation.
+          (setq type (ergoemacs-translation-struct-key modal)
+                local-keymap (ergoemacs-translation-struct-keymap-modal modal)
+                text (ergoemacs-translation-struct-text modal)
+                unchorded (ergoemacs-translation-struct-unchorded modal)
+                trans (ergoemacs-translation-struct-translation modal)
+                tmp translation
+                translation modal
+                modal tmp
+                tmp nil))
+        (setq raw-input input
+              input (ergoemacs-translate--event-mods input type)
+              last-command-event input
+              last-input-event input
+              ergoemacs-last-command-event last-command-event)))
+      (cond
+       ((and input (not universal)
+             (not (key-binding (ergoemacs :combine current-key raw-input)))
+             (and local-keymap
+                  (memq (lookup-key local-keymap (vector raw-input))
+                        ergoemacs-command-loop--universal-functions)))
+        (setq universal t
+              raw-input nil
+              input nil
+              ergoemacs-command-loop--echo-keystrokes-complete t))
+       ((and raw-input universal) ;; Handle universal arguments.
+        (setq ergoemacs-command-loop--echo-keystrokes-complete t)
+        (cond
+         ((eq raw-input 45) ;; Negative argument
+          (cond
+           ((integerp current-prefix-arg)
+            (setq current-prefix-arg (- current-prefix-arg)))
+           ((eq current-prefix-arg '-)
+            (setq current-prefix-arg nil))
+           (t
+            (setq current-prefix-arg '-)))
+          (setq raw-input nil
+                input nil))
+         ((memq raw-input (number-sequence 48 57)) ;; Number
+          (setq raw-input (- raw-input 48)) ;; Actual Number.
+          (cond
+           ((and (integerp current-prefix-arg) (< 0 current-prefix-arg))
+            (setq current-prefix-arg (+ raw-input (* current-prefix-arg 10))))
+           ((and (integerp current-prefix-arg) (> 0 current-prefix-arg))
+            (setq current-prefix-arg (+ (- raw-input) (* current-prefix-arg 
10))))
+           ((and (eq current-prefix-arg '-) (> raw-input 0))
+            (setq current-prefix-arg (- raw-input)))
+           (t
+            (setq current-prefix-arg raw-input)))
+          (setq input nil
+                raw-input nil))
+         ((and local-keymap
+               (memq (lookup-key local-keymap (vector raw-input))
+                     ergoemacs-command-loop--universal-functions)) ;; Toggle 
to key-sequence.
+          (setq raw-input nil
+                universal nil))
+         ((or (memq (key-binding (ergoemacs :combine current-key input) t) 
ergoemacs-command-loop--universal-functions)
+              (not (key-binding (ergoemacs :combine current-key raw-input) t))
+              (and local-keymap (memq (lookup-key local-keymap (vector 
raw-input)) ergoemacs-command-loop--universal-functions)))
+          ;; Universal argument called.
+          (cond
+           ((not current-prefix-arg)
+            (setq current-prefix-arg '(4)
+                  raw-input nil
+                  input nil))
+           ((listp current-prefix-arg)
+            (setq current-prefix-arg (list (* (nth 0 current-prefix-arg) 4))
+                  raw-input nil
+                  input nil))
+           (t
+            (setq universal nil
+                  input nil
+                  raw-input nil))))
+         ((and local-keymap
+               (memq (lookup-key local-keymap (vector raw-input))
+                     ergoemacs-command-loop--undo-functions))
+          ;; Allow backspace to edit universal arguments.
+          (cond
+           ((not current-prefix-arg)) ;; Exit  universal argument
+           ((and (integerp current-prefix-arg)
+                 (= 0 (truncate current-prefix-arg 10))
+                 (< 0 current-prefix-arg))
+            (setq current-prefix-arg nil
+                  input nil
+                  raw-input nil))
+           ((and (integerp current-prefix-arg)
+                 (= 0 (truncate current-prefix-arg 10))
+                 (> 0 current-prefix-arg))
+            (setq current-prefix-arg '-
+                  input nil
+                  raw-input nil))
+           ((integerp current-prefix-arg)
+            (setq current-prefix-arg (truncate current-prefix-arg 10)
+                  input nil
+                  raw-input nil))
+           ((listp current-prefix-arg)
+            (setq current-prefix-arg
+                  (list (expt 4 (- (round (log (nth 0 current-prefix-arg) 4)) 
1))))
+            (when (equal current-prefix-arg '(1))
+              (setq current-prefix-arg nil))
+            (setq input nil
+                  raw-input nil))
+           ((eq current-prefix-arg '-)
+            (setq current-prefix-arg nil
+                  input nil
+                  raw-input nil))))))))
+    ;; Return list of raw key, and translated current key
+    (list (vector raw-input) (ergoemacs :combine (if reset-key-p nil 
current-key) input))))
+
 (defun ergoemacs-command-loop--listify-key-sequence (key &optional type)
   "Return a key sequence from KEY.
 
@@ -517,11 +1185,132 @@ This sequence is compatible with 
`listify-key-sequence'."
                  input))
     input))
 
+(defun ergoemacs-command-loop-p ()
+  "Determine if `ergoemacs-mode' is running its command loop.
+This is done by looking at the current `backtrace' and making
+sure that `ergoemacs-command-loop--internal' hasn't been called."
+  (eq (symbol-function 'this-command-keys) 
#'ergoemacs-command-loop--this-command-keys))
+
+(defvar ergoemacs-command-loop-start nil)
+(defun ergoemacs-command-loop (&optional key type initial-key-type universal 
initial-history)
+  "Process `ergoemacs-command-loop'.
+
+KEY is the key being read, or sequence being read.
+
+TYPE is the translation being used.
+
+INITIAL-KEY-TYPE ist he key type that is used fot the initial
+translation.
+
+UNIVERSAL is if the function will be calling a universal
+argument.
+
+INITIAL-HISTORY is the initial history list.
+
+The true work is done in `ergoemacs-command-loop--internal'."
+  (interactive)
+  (cond
+   ((and (or ergoemacs-command-loop-start key) (not 
(ergoemacs-command-loop-p)))
+    ;; (ergoemacs-command-loop--message "Start ergoemacs-mode command loop." )
+    (ergoemacs-command-loop--internal key type initial-key-type universal 
initial-history))
+   (t
+    (setq ergoemacs-command-loop--exit :ignore-post-command-hook
+          prefix-arg current-prefix-arg
+          ergoemacs-command-loop--single-command-keys (or (and key 
(read-kbd-macro key t))
+                                                          
ergoemacs-command-loop--single-command-keys)
+          unread-command-events (or (and key 
(ergoemacs-command-loop--listify-key-sequence key initial-key-type))
+                                    unread-command-events)
+          ergoemacs-command-loop--universal (if (and 
ergoemacs-command-loop--universal (not universal)) nil
+                                              universal)
+          ergoemacs-command-loop--current-type (or type 
ergoemacs-command-loop--current-type)
+         ergoemacs-command-loop--history (or initial-history 
ergoemacs-command-loop--history)))))
+
+(defvar ergoemacs-command-loop--running-pre-command-hook-p nil
+  "Variable to tell if ergoemacs-command loop is running the 
`pre-command-hook'.")
+
+(defvar ergoemacs-command-loop--excluded-variables
+  '(defining-kbd-macro executing-kbd-macro)
+  "List of variables stopping the command loop.
+
+While these variables are non-nil, the `ergoemacs-command-loop'
+will stop and not be started agin.")
+
+(defvar ergoemacs-command-loop--excluded-major-modes
+  '(calc-mode calc-trail-mode calc-edit-mode)
+  "List of major modes where the command loop is incompatible.")
+
+
 (defvar ergoemacs-command-loop--minibuffer-unsupported-p nil)
+(defun ergoemacs-command-loop--minibuffer-supported-p (&optional command)
+  "Determine if the current minibuffer supports the full command loop.
+When COMMAND is non-nil, set
+`ergoemacs-command-loop--minibuffer-unsupported-p' to the
+appropriate value based on the COMMAND."
+  (if (not command)
+      (or (not (minibufferp))
+         (not ergoemacs-command-loop--minibuffer-unsupported-p))
+    (when (or (and command (symbolp command) (string-match-p 
"^\\(calc\\|math\\)" (symbol-name command)))
+             (and (stringp command) (string-match-p "^[^:]*:\\(calc\\|math\\)" 
command))) 
+      (ergoemacs-save-buffer-state
+       (set (make-local-variable 
'ergoemacs-command-loop--minibuffer-unsupported-p) t)))
+    (ergoemacs-command-loop--minibuffer-supported-p)))
+
+(defun ergoemacs-command-loop-full-p (&optional type)
+  "Determines if the full command loop should be run.
+
+
+TYPE is the type of command loop to check for.  By default this
+is the :full command loop."
+  (and
+   (or (eq ergoemacs-command-loop-type (or type :full)) (ergoemacs :modal-p))
+   (ergoemacs-command-loop--minibuffer-supported-p)
+   (catch 'excluded-variables
+     (dolist (var ergoemacs-command-loop--excluded-variables)
+       (when (and var (ergoemacs-sv var))
+         (throw 'excluded-variables nil)))
+     t)
+   (not (memq major-mode ergoemacs-command-loop--excluded-major-modes))))
+
+(defun ergoemacs-command-loop--start-with-pre-command-hook ()
+  "Start ergoemacs command loop.
+
+This is done by replacing `this-command' with
+`ergoemacs-command-loop-start' and then running `this-command'
+from within the ergoemacs-mode command loop."
+  (when (and (not ergoemacs-command-loop--running-pre-command-hook-p)
+             (ergoemacs-command-loop-full-p)
+             (not unread-command-events)
+             (not (ergoemacs-command-loop-p)))
+    (setq ergoemacs-command-loop-start this-command
+          ergoemacs-command-loop--single-command-keys 
(this-single-command-keys)
+          this-command 'ergoemacs-command-loop-start)))
+
+(add-hook 'ergoemacs-pre-command-hook 
#'ergoemacs-command-loop--start-with-pre-command-hook)
+
+
+(defvar ergoemacs-command-loop--internal-end-command-p nil)
 
 (defvar ergoemacs-last-command-was-ergoemacs-ignore-p nil
   "Last command was `ergoemacs-ignore'.")
 
+(defun ergoemacs-command-loop--start-with-post-command-hook ()
+  "Start ergoemacs command loop.
+
+This is done by pushing the key [ergoemacs-ignore] on the
+`unread-command-events' stack.  This then forces `ergoemacs-mode'
+to start with
+`ergoemacs-command-loop--start-with-pre-command-hook'."
+  (when (and (not ergoemacs-command-loop--internal-end-command-p)
+             (ergoemacs-command-loop-full-p))
+    (if ergoemacs-last-command-was-ergoemacs-ignore-p
+       (unless (eq ergoemacs-last-command-was-ergoemacs-ignore-p :idle)
+         (run-with-idle-timer 0.05 nil (lambda()
+                                         (setq 
ergoemacs-last-command-was-ergoemacs-ignore-p :idle)
+                                         (ergoemacs-command-loop-start))))
+      (push 'ergoemacs-ignore unread-command-events))))
+
+(add-hook 'ergoemacs-post-command-hook 
#'ergoemacs-command-loop--start-with-post-command-hook)
+
 (defvar ergoemacs-command-loop--point-motion-last-point nil
   "Record the last point.")
 
@@ -557,6 +1346,79 @@ Fix this issue."
     (ignore-errors (switch-to-buffer (window-buffer) t t))
     (goto-char (window-point))))
 
+(defun ergoemacs-command-loop--update-primary-selection ()
+  "Update primary clipboard in X based systems."
+  (when (and mouse-drag-copy-region
+            (eventp last-command-event)
+            (consp last-command-event)
+            (memq (event-basic-type (car last-command-event))
+                       '(mouse-1))
+            (region-active-p))
+    (ergoemacs :set-selection 'PRIMARY (buffer-substring-no-properties 
(region-beginning) (region-end)))))
+
+(defun ergoemacs-command-loop--internal-end-command ()
+  "Simulates the end of a command."
+  ;; Simulate the end of an emacs command, since we are not
+  ;; exiting the loop.
+  (setq ergoemacs-command-loop--internal-end-command-p t)
+  (unwind-protect
+      (run-hooks 'post-command-hook)
+    (setq ergoemacs-command-loop--internal-end-command-p nil))
+  
+  ;; Deactivate mark.
+  (when deactivate-mark
+    (deactivate-mark)
+    (setq deactivate-mark nil))
+  
+  ;; Create undo-boundary like emacs does.
+
+  ;; The undo boundary is created every 20 characters.
+  (when (eq this-command 'self-insert-command)
+    ;; Adapted from `org-self-insert-command'
+    (if (not (eq last-command 'self-insert-command))
+        (setq ergoemacs-command-loop--self-insert-command-count 1)
+      (if (>= ergoemacs-command-loop--self-insert-command-count 20)
+          (setq ergoemacs-command-loop--self-insert-command-count 1)
+        (and (> ergoemacs-command-loop--self-insert-command-count 0)
+             buffer-undo-list (listp buffer-undo-list)
+             (not (cadr buffer-undo-list)) ; remove nil entry
+             (setcdr buffer-undo-list (cddr buffer-undo-list)))
+        (setq ergoemacs-command-loop--self-insert-command-count
+              (1+ ergoemacs-command-loop--self-insert-command-count))))
+    ;; See: 
http://stackoverflow.com/questions/6590889/how-emacs-determines-a-unit-of-work-to-undo
+    
+    ;; FIXME:
+    ;; Certain "hairy" insertions (as determined by
+    ;; internal_self_insert) cause an an undo boundary to be added
+    ;; immediately, and the character count to be reset. Reading the
+    ;; code, it looks as though these are: (1) in overwrite-mode, if you
+    ;; overwrote a character with one that has a different width,
+    ;; e.g. typing over a tab; (2) if the character you inserted caused
+    ;; an abbreviation to be expanded; (3) if the character you typed
+    ;; caused auto-fill-mode to insert indentation.
+    )
+  
+  ;; After executing, the emacs loop should copy `this-command' into
+  ;; `last-command'.
+  ;; It should also change `last-prefix-arg'
+  (setq last-command this-command
+        real-last-command this-command ;; Hopefully doesn't throw an error.
+        last-prefix-arg prefix-arg
+        current-prefix-arg prefix-arg
+        prefix-arg nil
+        this-command nil
+        deactivate-mark nil
+        ergoemacs-command-loop--echo-keystrokes-complete nil)
+  
+  (undo-boundary)
+  ;;  This (sort of) fixes `this-command-keys'
+  ;; But it doesn't fix it for keyboard macros.
+  (clear-this-command-keys t)
+  (setq ergoemacs-command-loop--decode-event-timeout-p nil)
+  (ergoemacs-command-loop--sync-point)
+  (ergoemacs-command-loop--point-motion-hooks)
+  (ergoemacs-command-loop--update-primary-selection))
+
 (defun ergoemacs-command-loop--mouse-command-drop-first (args &optional 
fn-arg-p)
   "Internal function for processing mouse commands.
 
@@ -609,6 +1471,68 @@ FN-ARG-P can be nil, :drop-rest or :rest"
             (push a ret)))
         (reverse ret))))))
 
+(defun ergoemacs-command-loop--modify-mouse-command (command)
+  "Modify mouse COMMAND to work with ergoemacs command loop."
+  (let* ((iform (interactive-form command))
+         (form (and iform (consp iform) (= 2 (length iform)) (stringp (nth 1 
iform)) (nth 1 iform)))
+         (args (help-function-arglist command t))
+         (fn-args (ergoemacs-command-loop--mouse-command-drop-first args t))
+         (strip-args (ergoemacs-command-loop--mouse-command-drop-first args))
+         (rest-p (ergoemacs-command-loop--mouse-command-drop-first args :rest))
+         (drop-rest (ergoemacs-command-loop--mouse-command-drop-first args 
:drop-rest))
+         (select-window-p (and (stringp form) (string-match-p "^[*^]*[@]" 
form)))
+         (event-p (and (stringp form) (string-match-p "^[*@^]*e" form)))
+         (new-form (and form
+                        (or (and (not event-p) form)
+                            (and event-p (replace-regexp-in-string 
"^\\([*@^]*\\)e\n*\\(.*\\)" "\\1\\2" form))))))
+    (when (and new-form (string= new-form ""))
+      (setq new-form nil))
+    (cond
+     ((not event-p)
+      command)
+     (rest-p
+      `(lambda ,fn-args
+         ,(if new-form
+              `(interactive ,new-form)
+            `(interactive))
+         ,(when select-window-p
+            '(select-window (posn-window (event-start last-command-event))))
+        (ergoemacs-command-loop--execute-modify-command-list ',command)
+         (if ,rest-p
+             (apply ',command last-command-event ,@strip-args)
+           (,command last-command-event ,@drop-rest))))
+     
+     ((not rest-p)
+      `(lambda ,fn-args
+         ,(if new-form
+              `(interactive ,new-form)
+            `(interactive))
+         ,(when select-window-p
+            '(select-window (posn-window (event-start last-command-event))))
+        (ergoemacs-command-loop--execute-modify-command-list ',command)
+         (,command last-command-event ,@strip-args))))))
+
+(defun ergoemacs-command-loop--call-mouse-command (command &optional 
record-flag keys)
+  "Call a possible mouse COMMAND.
+
+The COMMAND is modified to take out any event information and
+replace it with `last-event-command' information.  This
+modifciation isd one by
+`ergoemacs-command-loop--modify-mouse-command'.
+
+Mouse commands are also wrapped in `ignore-errors'.  This takes
+care of `window-live-p' errors that occur when running the
+Emacs detects keys when outside of Emacs.
+
+The RECORD-FLAG and KEYS arguments are passed to
+`ergoemacs-command-loop--grow-interactive' for the mouse command."
+  (cond
+   ((ergoemacs-keymapp command)
+    (popup-menu command nil current-prefix-arg))
+   (t
+    (ignore-errors
+      (call-interactively (ergoemacs-command-loop--modify-mouse-command 
command) record-flag keys)))))
+
 (defvar ergoemacs-command-loop-describe-key-functions
   '(describe-key describe-function)
   "Functions like `describe-key'.
@@ -616,6 +1540,124 @@ These functions will:
 - Replace `key-description' with `ergoemacs-key-description'.
 - Replace `read-key-sequence' with 
`ergoemacs-command-loop--read-key-sequence'.")
 
+(defcustom ergoemacs-comand-loop-grow-max-sizes-p t
+  "Grow the max sizes if needed.
+This grows `max-specpdl-size' and `max-lisp-eval-depth' if
+`ergoemacs-command-loop--call-interactively' throws an error
+about `max-specpdl-size' or `max-lisp-eval-depth'.
+
+The overall maximum that these are set to are controlled by
+`ergoemacs-max-specpdl-size' and
+`ergoemacs-max-lisp-eval-depth.'"
+  :type 'boolean
+  :group 'ergoemacs-mode)
+
+(defvar ergoemacs-command-loop--grow-command nil)
+(defvar ergoemacs-command-loop--grow-record nil)
+(defvar ergoemacs-command-loop--grow-keys nil)
+(defvar ergoemacs-command-loop--grow-special nil)
+
+
+(defcustom ergoemacs-max-specpdl-size (* 8 max-specpdl-size)
+  "Maximum `max-specpdl-size' that `ergoemacs-mode' increases to..."
+  :type 'boolean
+  :group 'ergoemacs-mode)
+
+(defcustom ergoemacs-max-lisp-eval-depth (* 8 max-lisp-eval-depth)
+  "Maximum `max-lisp-eval-depth' that `ergoemacs-mode' increases to..."
+  :type 'boolean
+  :group 'ergoemacs-mode)
+
+(defcustom ergoemacs-command-loop-dont-grow-commands
+  '(org-agenda)
+  "List of commands where the command loop will not adjust sizes."
+  :type '(repeat (sexp :tag "Command"))
+  :group 'ergoemacs-mode)
+
+(defun ergoemacs-command-loop--grow-interactive (command &optional record-flag 
keys)
+  "Call the COMMAND interactively.
+The RECORD-FLAG and KEYS are sent to `ergoemacs--real-call-interactively'.
+
+This will grow `max-lisp-eval-depth' and `max-specpdl-size' if
+needed (and resotre them to the original values)."
+  (setq ergoemacs-command-loop--grow-command nil
+       ergoemacs-command-loop--grow-record nil
+       ergoemacs-command-loop--grow-keys nil
+       ergoemacs-command-loop--grow-special nil)
+  (if (memq command ergoemacs-command-loop-dont-grow-commands)
+      (call-interactively command record-flag keys)
+    (let ((grow-max-lisp-p t)
+         (orig-max-specpdl-size max-specpdl-size)
+         (orig-max-lisp-eval-depth max-lisp-eval-depth))
+      (while grow-max-lisp-p
+       (condition-case err
+           (cond
+            (ergoemacs-command-loop--grow-command
+             (command-execute ergoemacs-command-loop--grow-command
+                              ergoemacs-command-loop--grow-record
+                              ergoemacs-command-loop--grow-keys
+                              ergoemacs-command-loop--grow-special)
+             (setq grow-max-lisp-p nil))
+            (t
+             (call-interactively command record-flag keys)
+             (setq grow-max-lisp-p nil)))
+         (error
+          (if (and (consp err)
+                   (eq (car err) 'error)
+                   (stringp (nth 1 err))
+                   (string-match "max-specpdl-size\\|max-lisp-eval-depth"
+                                 (nth 1 err))
+                   ergoemacs-comand-loop-grow-max-sizes-p
+                   (<= max-specpdl-size ergoemacs-max-specpdl-size)
+                   (<= max-lisp-eval-depth ergoemacs-max-lisp-eval-depth))
+              (progn
+                (setq max-specpdl-size (* 2 max-specpdl-size)
+                      max-lisp-eval-depth (* 2 max-lisp-eval-depth))
+                (ergoemacs-warn "Increased max-specpdl-size to %s and 
max-lisp-eval-depth to %s for %s"
+                                max-specpdl-size max-lisp-eval-depth command))
+            (setq grow-max-lisp-p nil
+                  max-specpdl-size orig-max-specpdl-size
+                  max-lisp-eval-depth orig-max-lisp-eval-depth)
+            (if (and err (consp err))
+                (signal (car err) (cdr err))
+              (signal err "Unknown error"))))))
+      (setq max-specpdl-size orig-max-specpdl-size
+           max-lisp-eval-depth orig-max-lisp-eval-depth))))
+
+
+(defun ergoemacs-command-loop--call-interactively (command &optional 
record-flag keys)
+  "Call the COMMAND interactively.  Also handle mouse events (if possible.)
+The RECORD-FLAG and KEYS are sent to 
`ergoemacs-command-loop--grow-interactive'."
+  (ergoemacs-command-loop--sync-point)
+  (setq ergoemacs-last-command-was-ergoemacs-ignore-p nil
+       this-command-keys-shift-translated (or 
ergoemacs-this-command-keys-shift-translated 
this-command-keys-shift-translated))
+  (cond
+   ((and (eventp last-command-event)
+         (consp last-command-event)
+        (memq (event-basic-type (car last-command-event))
+                  '(mouse-1 mouse-2 mouse-3 mouse-4 mouse-5 mouse-6 mouse-7 
mouse-8 mouse-9)))
+    (ergoemacs-command-loop--call-mouse-command command record-flag keys))
+   ((and (symbolp command) (not (fboundp command)))
+    (ergoemacs-command-loop--message "Command `%s' is not found" command))
+   ((and (symbolp command) (not (commandp command)))
+    (ergoemacs-command-loop--message "Command `%s' cannot be called from a 
key" command))
+   ((and (consp ergoemacs-command-loop-describe-key-functions)
+        (memq command ergoemacs-command-loop-describe-key-functions))
+    (ergoemacs-specials
+     (ergoemacs-command-loop--grow-interactive command record-flag keys)))
+   (t
+    (ergoemacs-command-loop--grow-interactive command record-flag keys)))
+  (setq ergoemacs-this-command-keys-shift-translated nil))
+
+
+(defun ergoemacs-command-loop-start ()
+  "Start `ergoemacs-command-loop'."
+  (interactive)
+  ;; Should work...
+  (unless ergoemacs-command-loop-start
+    (setq ergoemacs-command-loop-start t))
+  (ergoemacs-command-loop))
+
 (defvar ergoemacs-command-loop--spinner nil)
 (defvar ergoemacs-command-loop--spinner-i nil)
 (defvar ergoemacs-command-loop--spinner-list nil)
@@ -676,7 +1718,7 @@ instead of `format'."
       (when (eq ergoemacs-message-level 
ergoemacs-command-loop--spinner-display)      
        (let* ((string (or (and (listp string)
                                (eq (car string) 'quote)
-                               (eval string))
+                               (cadr string))
                           string))
               (rest (or (and (listp string)
                              (concat " " (apply #'format (apply 
#'ergoemacs-key-description--unicode-char string) args)))
@@ -686,10 +1728,12 @@ instead of `format'."
          (when (not ergoemacs-command-loop--spinner-list)
            (setq ergoemacs-command-loop--spinner-list (nth 1 (assoc 
ergoemacs-command-loop-spinner ergoemacs-command-loop-spinners))
                  ergoemacs-command-loop--spinner-i 0))
-         (ergoemacs-command-loop--message "%s%s" (nth (mod (setq 
ergoemacs-command-loop--spinner-i (+ 1 ergoemacs-command-loop--spinner-i))
-                                                           (length 
ergoemacs-command-loop--spinner-list))
-                                                      
ergoemacs-command-loop--spinner-list)
-                                          rest))))))
+         (ergoemacs-command-loop--message
+          "%s%s" (nth (mod (setq ergoemacs-command-loop--spinner-i
+                                 (+ 1 ergoemacs-command-loop--spinner-i))
+                           (length ergoemacs-command-loop--spinner-list))
+                      ergoemacs-command-loop--spinner-list)
+          rest))))))
 
 (defun ergoemacs-command-loop--spinner-end ()
   "Cancel the `ergoemacs-command-loop--spinner' timer."
@@ -714,6 +1758,28 @@ They don't exactly behave like their Emacs equivalents."
   (or (and ergoemacs-mode ergoemacs-command-loop--single-command-keys)
       (funcall ergoemacs-command-loop--this-command-keys)))
 
+(defvar ergoemacs-command-loop--timer nil
+  "Timer to startup `ergoemacs-mode' command loop.")
+(defun ergoemacs-command-loop--timer ()
+  "Start `ergoemacs-command-loop--internal' if not currently running."
+  (unless (and (ergoemacs-command-loop-full-p)
+               (ergoemacs-command-loop-p))
+    (ergoemacs-command-loop--internal)))
+
+(defun ergoemacs-command-loop--install-timer ()
+  "Install the `ergoemacs-command-loop--timer'."
+  (setq ergoemacs-command-loop--timer
+        (run-with-idle-timer 0.05 nil #'ergoemacs-command-loop--timer)))
+
+(defun ergoemacs-command-loop--remove-timer ()
+  "Remove `ergoemacs-command-loop--timer'."
+  (when ergoemacs-command-loop--timer
+    (cancel-timer ergoemacs-command-loop--timer)
+    (setq ergoemacs-command-loop--timer nil)))
+
+(add-hook 'ergoemacs-mode-startup-hook #'ergoemacs-command-loop--install-timer)
+(add-hook 'ergoemacs-mode-shutdown-hook #'ergoemacs-command-loop--remove-timer)
+
 (defun ergoemacs-command-loop--ignore (&rest _ignore)
   "Do nothing and return nil.
 
@@ -727,6 +1793,227 @@ run, by changing `this-command' to `last-command'"
   ;; FIXME: Somehow change the output of `this-single-command-raw-keys'
   nil)
 
+(defun ergoemacs-command-loop--read-key-sequence (prompt &rest _ignore)
+  "Read key sequence in ergoemacs-mode with PROMPT.
+
+Ignore all the other options."
+  (let ((old ergoemacs-command-loop-type)
+        (old-prompt ergoemacs-command-loop--read-key-prompt)
+        ret)
+    (setq ergoemacs-command-loop-type :read-key-sequence
+          ergoemacs-command-loop--read-key-prompt prompt)
+    (unwind-protect
+        (setq ret (ergoemacs-command-loop--internal))
+      (setq ergoemacs-command-loop-type old
+            ergoemacs-command-loop--read-key-prompt old-prompt))
+    ret))
+
+(defun ergoemacs-command-loop--internal (&optional key type initial-key-type 
universal initial-history)
+  "Read keyboard input and execute command.
+The KEY is the keyboard input where the reading begins.  If nil,
+read the whole keymap.
+
+TYPE is the keyboard translation type, defined by `ergoemacs-translate'
+Ergoemacs-mode sets up: :ctl-to-alt :unchorded :normal.
+
+INITIAL-KEY-TYPE represents the translation type for the initial KEY.
+
+UNIVERSAL allows ergoemacs-read-key to start with universal
+argument prompt.
+
+INITIAL-HISTORY is the initial history list to use.
+
+While in the loop, every command resets the keys typed every time
+a command is completed (by `clear-this-command-keys')
+
+Also in the loop, `universal-argument-num-events' is set to
+0. (Allows commands like `isearch' to work correctly in older
+Emacs versions)."
+  (interactive)
+  (when ergoemacs-mode
+    (ergoemacs-command-loop--execute-rm-keyfreq 'ergoemacs-command-loop)
+    ;; Call the startup command
+    (when (commandp ergoemacs-command-loop-start)
+      (ergoemacs-command-loop--call-interactively ergoemacs-command-loop-start)
+      (ergoemacs-command-loop--internal-end-command))
+    ;; Replace functions temporarily
+    (cl-letf (((symbol-function 'this-command-keys) 
#'ergoemacs-command-loop--this-command-keys)
+             ((symbol-function 'this-single-command-keys) 
#'ergoemacs-command-loop--this-command-keys)
+             ((symbol-function 'this-command-keys-vector) 
#'ergoemacs-command-loop--this-command-keys)
+             ((symbol-function 'this-single-command-raw-keys) 
#'ergoemacs-command-loop--this-command-keys)
+              ;; ((symbol-function 'read-key-sequence) 
#'ergoemacs-command-loop--read-key-sequence)
+             )
+      (let* ((type (or type :normal))
+             (from-start-p ergoemacs-command-loop-start)
+             (continue-read t)
+             (first-type type)
+             raw-key current-key last-current-key
+             (translation (ergoemacs-translate--get type))
+             (local-keymap (ergoemacs-translate--keymap translation))
+             modal-p
+             tmp command)
+        (unwind-protect
+            (progn
+             ;; Set these to nil when entering the command loop;
+             ;;
+             ;; For some reason `inhibit-point-motion-hooks' on emacs
+             ;; 25.1 is t when the command loop is entered.
+             ;;
+             ;; To allow the point motion hooks to work as
+             ;; advertised, set these on starting the command loop.
+             (setq inhibit-point-motion-hooks      nil
+                   disable-point-adjustment        nil
+                   global-disable-point-adjustment nil)
+              ;; Setup initial unread command events, first type and history
+              (setq tmp (ergoemacs-command-loop--listify-key-sequence key 
initial-key-type)
+                    unread-command-events (or (and unread-command-events tmp 
(append tmp unread-command-events)) tmp)
+                    ergoemacs-command-loop--first-type first-type
+                    ergoemacs-command-loop--history initial-history
+                    ergoemacs-command-loop-start nil)
+              (while continue-read
+               (setq ergoemacs-last-command-was-ergoemacs-ignore-p nil)
+                (unless (eq ergoemacs-command-loop-type :read-key-sequence)
+                  (setq inhibit-quit t))
+                (while continue-read
+                 (setq ergoemacs-last-command-was-ergoemacs-ignore-p nil)
+                  ;; Read key
+                  (setq ergoemacs-command-loop--single-command-keys current-key
+                        ergoemacs-command-loop--current-type type
+                        ergoemacs-command-loop--universal universal
+                        raw-key (ergoemacs-command-loop--read-key
+                                 current-key
+                                 (or (and unread-command-events :normal) type)
+                                 (and (not unread-command-events) universal))
+                        ergoemacs-command-loop--single-command-keys nil
+                        universal-argument-num-events 0
+                        last-current-key current-key
+                        current-key (nth 1 raw-key)
+                        raw-key (nth 0 raw-key)
+                        continue-read nil)
+                 (when (setq modal-p (ergoemacs :modal-p))
+                   (setq local-keymap 
(ergoemacs-translation-struct-keymap-modal modal-p)))
+                  (cond
+                   ;; Handle quit commands
+                   ((and last-current-key
+                         (or (lookup-key ergoemacs-map--quit-map raw-key)
+                             (and (equal raw-key [27])
+                                  (lookup-key ergoemacs-map--quit-map 
[escape]))))
+                    (ergoemacs-command-loop--message
+                     "Key sequence %s aborted by %s"
+                     (ergoemacs-key-description last-current-key)
+                     (ergoemacs-key-description raw-key))
+                    (setq quit-flag t
+                         ergoemacs-this-command-keys-shift-translated nil))
+                   ;; Handle local commands.
+                   ((and (or modal-p
+                             (not (equal current-key raw-key)))
+                         (setq command (lookup-key local-keymap raw-key))
+                         (not (ergoemacs-keymapp command)) ;; Ignore locally
+                         ;; Already handled by 
`ergoemacs-command-loop--read-key'
+                         (not (ergoemacs-gethash command 
ergoemacs-command-loop--next-key-hash))
+                         ;; If a command has :ergoemacs-local property of 
:force, don't
+                         ;; worry about looking up a key, just run the 
function.
+                         (or modal-p
+                             (and (symbolp command) (eq (get command 
:ergoemacs-local) :force))
+                             (not (key-binding current-key t))))
+                    (pop ergoemacs-command-loop--history) ;; Don't recored 
local events
+                    (setq ergoemacs-command-loop--single-command-keys 
last-current-key
+                          universal-argument-num-events 0
+                          ergoemacs-command-loop--current-type type
+                          ergoemacs-command-loop--universal universal
+                          ergoemacs-command-loop--exit nil)
+                    
+                    (unless (eq ergoemacs-command-loop-type :test)
+                      (setq tmp this-command
+                            this-command command)
+                      (ergoemacs-command-loop--call-interactively this-command)
+                      (setq command this-command
+                            this-command tmp))
+                    ;; If the command changed anything, fix it here.
+                    (unless (equal type ergoemacs-command-loop--current-type)
+                      (setq type ergoemacs-command-loop--current-type
+                            translation (ergoemacs-translate--get type)
+                            local-keymap (ergoemacs-translate--keymap 
translation)))
+                    
+                    (setq current-key 
ergoemacs-command-loop--single-command-keys
+                          universal ergoemacs-command-loop--universal
+                          ergoemacs-command-loop--single-command-keys nil
+                          continue-read (not ergoemacs-command-loop--exit)))
+                   ;; Handle any keys that are bound in some translatable way.
+                   ((setq command (ergoemacs-command-loop--key-lookup 
current-key))
+                    ;; Setup external indicators of how the loop currently 
behaves.
+                    (setq ergoemacs-command-loop--single-command-keys 
current-key
+                          universal-argument-num-events 0
+                          ergoemacs-command-loop--current-type type
+                          ergoemacs-command-loop--universal nil
+                          ergoemacs-command-loop--exit t)
+                    (if (setq continue-read (and (not (and (consp (aref 
current-key 0))
+                                                          (memq 
(event-basic-type (car (aref current-key 0)))
+                                                                '(mouse-1 
mouse-2 mouse-3 mouse-4 mouse-5 mouse-6 mouse-7 mouse-8 mouse-9))))
+                                                (ergoemacs-keymapp command)))
+                        (setq universal nil)
+                      (unless (memq ergoemacs-command-loop-type '(:test 
:read-key-sequence))
+                        (with-local-quit
+                          (ergoemacs-command-loop--execute command)))
+                      
+                      (when quit-flag
+                        (ergoemacs-command-loop--message "Quit!"))
+                      
+                      ;; Change any information (if needed)
+                      (unless (equal type ergoemacs-command-loop--current-type)
+                        (setq type ergoemacs-command-loop--current-type
+                              translation (ergoemacs-translate--get type)
+                              local-keymap (ergoemacs-translate--keymap 
translation)))
+
+                      (when (eq ergoemacs-command-loop-type :read-key-sequence)
+                        (setq ergoemacs-command-loop--exit t
+                              continue-read nil
+                              command current-key))
+                      
+                      (setq current-key 
ergoemacs-command-loop--single-command-keys 
+                            universal ergoemacs-command-loop--universal
+                            ergoemacs-command-loop--single-command-keys nil
+                            continue-read (not ergoemacs-command-loop--exit)
+                            current-prefix-arg (if 
ergoemacs-command-loop--universal current-prefix-arg prefix-arg))
+                      
+                      (when (and (not continue-read)
+                                 (eq ergoemacs-command-loop--exit 
:ignore-post-command-hook))
+                        (setq continue-read t)))
+                    
+                    (when (or (not ergoemacs-command-loop--exit)
+                              (and (not continue-read) (setq continue-read 
unread-command-events)))
+                      (ergoemacs-command-loop--internal-end-command)))
+                   (quit-flag
+                    (ergoemacs-command-loop--message "Quit!")
+                    (setq quit-flag nil
+                          type :normal
+                          first-type :normal
+                          raw-key nil
+                          current-key nil
+                          translation (ergoemacs-translate--get type)
+                          local-keymap (ergoemacs-translate--keymap 
translation)
+                          ergoemacs-command-loop--first-type first-type
+                          ergoemacs-command-loop--history nil))
+                  ((consp (aref current-key 0))) ;; don't complain about mouse 
keys
+                   (t ;; Command not found exit.
+                    (ergoemacs-command-loop--message "Key %s doesn't do 
anything." (ergoemacs-key-description current-key)))))
+                (unless quit-flag
+                  (ergoemacs-command-loop--internal-end-command))
+                (setq quit-flag nil
+                      type :normal
+                      continue-read (or unread-command-events (and 
from-start-p (ergoemacs-command-loop-full-p)))
+                      first-type :normal
+                      raw-key nil
+                      current-key nil
+                      translation (ergoemacs-translate--get type)
+                      local-keymap (ergoemacs-translate--keymap translation)
+                      ergoemacs-command-loop--first-type first-type
+                      ergoemacs-command-loop--history nil)
+                (when (or (not ergoemacs-mode) (eq :read-key-sequence 
ergoemacs-command-loop-type))
+                  (setq continue-read nil)))
+              (setq inhibit-quit nil)))
+        command))))
+
 (defcustom ergoemacs-message-in-mode-line t
   "Display ergoemacs information in mode-line."
   :type 'boolean
@@ -791,6 +2078,333 @@ to the `format' like: (format str args)."
     (let ((message-log-max ergoemacs-command-loop--message-log-max))
       (apply #'message (append (list str) args))))))
 
+(defvar ergoemacs-command-loop--temp-message-timer-secs 0.5
+  "Timer to ensure minibuffer isn't active.")
+
+(defvar ergoemacs-command-loop--temp-message-timer nil
+  "Timer to ensure minibuffer isn't active.")
+
+(defvar ergoemacs-command-loop--temp-message-timer-str nil
+  "Message string.")
+
+(defun ergoemacs-command-loop--temp-message-timer-echo ()
+  "Echos `ergoemacs-command-loop--temp-message-timer-str' if minibuffer isn't 
active."
+  (if (or (minibufferp) isearch-mode)
+      (setq ergoemacs-command-loop--temp-message-timer
+           (run-with-idle-timer ergoemacs-command-loop--temp-message-timer-secs
+                                nil 
#'ergoemacs-command-loop--temp-message-timer-echo))
+    (cancel-timer ergoemacs-command-loop--temp-message-timer)
+    (let (message-log-max)
+      (with-temp-message ergoemacs-command-loop--temp-message-timer-str
+       (sit-for (or (and (numberp ergoemacs-command-loop-message-sit-for) 
ergoemacs-command-loop-message-sit-for) 2))))))
+
+(defun ergoemacs-command-loop--temp-message (str &rest args)
+  "Message facility for `ergoemacs-mode' command loop.
+
+STR is the format string
+ARGS is the format arguments
+These are passed to `format' as (format str args)."
+  (setq ergoemacs-command-loop--last-event-time (float-time))
+  (cond
+   ((string= str ""))
+   ((or (minibufferp) isearch-mode)
+    (apply #'ergoemacs-command-loop--mode-line-message
+           (append (list str) args)))
+   (t
+    (setq ergoemacs-command-loop--temp-message-timer-str (apply #'format 
(append (list str) args))
+         ergoemacs-command-loop--temp-message-timer
+         (run-with-idle-timer ergoemacs-command-loop--temp-message-timer-secs
+                              nil 
#'ergoemacs-command-loop--temp-message-timer-echo)))))
+
+;; (2) Key sequence translated to command
+(defun ergoemacs-command-loop--message-binding (key &optional lookup 
translated-key)
+  "Optionally messages information about the translation.
+
+KEY is the original key.
+
+LOOKUP is what will be run.
+
+TRANSLATED-KEY is what the assumed key is actually bound."
+  (cond
+   ((and lookup (ergoemacs-keymapp lookup)))
+   ((consp (elt key 0))) ;; Don't message mouse translations
+   ((and (or (eq ergoemacs-echo-function :multi-key)
+             (not (and translated-key (eq ergoemacs-echo-function 
:on-translation)))
+             (not (eq ergoemacs-echo-function t)))
+         (vectorp key) (or (= (length key) 1) ;; Don't message single keys
+                           (and (eq 27 (elt key 0)) (= (length key) 2)))))
+   ((and lookup
+         (or (eq ergoemacs-echo-function t)
+             (and translated-key (eq ergoemacs-echo-function :on-translation))
+             (eq ergoemacs-echo-function :multi-key)))
+    (ergoemacs-command-loop--temp-message "%s%s%s%s"
+                                     (ergoemacs-key-description key)
+                                     (ergoemacs :unicode-or-alt "→" "->")
+                                     lookup
+                                     (or (and translated-key
+                                              (format " (from %s)" 
(ergoemacs-key-description translated-key)))
+                                         "")))
+   ((not lookup)
+    (ergoemacs-command-loop--temp-message "%s is undefined!"
+                                     (ergoemacs-key-description key)))
+   ((and ergoemacs-echo-function
+        (not (or (= (length key) 1) ;; Clear command completing message
+                 (and (eq 27 (elt key 0)) (= (length key) 2)))))
+    (ergoemacs-command-loop--message ""))))
+
+(defun ergoemacs-command-loop--key-lookup (key)
+  "Find the KEY's function based on current bindings.
+
+If `ergoemacs-mode' has translated this, make Emacs think you
+pressed the translated key by changing
+`ergoemacs-command-loop--single-command-keys'."
+  (if (and (vectorp key)
+          (consp (aref key 0))
+          (memq (event-basic-type (car (aref key 0)))
+                '(mouse-1 mouse-2 mouse-3 mouse-4 mouse-5 mouse-6 mouse-7 
mouse-8 mouse-9)))
+      (let* ((event (aref key 0))
+            (posn (car (cdr last-command-event)))
+            (area (and posn (ergoemacs-posnp posn) (posn-area posn)))
+            (obj (and posn (ergoemacs-posnp posn) (posn-object posn)))
+            (original-command (key-binding key t))
+            command tmp)
+       ;; From `read-key-sequence':
+       ;; /* Clicks in non-text areas get prefixed by the symbol
+       ;; in their CHAR-ADDRESS field.  For example, a click on
+       ;; the mode line is prefixed by the symbol `mode-line'.
+       ;; Furthermore, key sequences beginning with mouse clicks
+       ;; are read using the keymaps of the buffer clicked on, not
+       ;; the current buffer.  So we may have to switch the buffer
+       ;; here.
+       ;; When we turn one event into two events, we must make sure
+       ;; that neither of the two looks like the original--so that,
+       ;; if we replay the events, they won't be expanded again.
+       ;; If not for this, such reexpansion could happen either here
+       ;; or when user programs play with this-command-keys.  */
+
+       ;;
+       ;; /* Arrange to go back to the original buffer once we're
+       ;; done reading the key sequence.  Note that we can't
+       ;; use save_excursion_{save,ore} here, because they
+       ;; save point as well as the current buffer; we don't
+       ;; want to save point, because redisplay may change it,
+       ;; to accommodate a Fset_window_start or something.  We
+       ;; don't want to do this at the top of the function,
+       ;; because we may get input from a subprocess which
+       ;; wants to change the selected window and stuff (say,
+       ;; emacsclient).  */
+       (when area
+         (setq command (key-binding (vconcat (list area event)) t))
+         (when (and obj (consp obj)
+                    (setq tmp (ignore-errors (get-text-property (cdr obj)  
'local-map (car obj))))
+                    (setq tmp (or (and (symbolp tmp) (ergoemacs-sv tmp)) tmp))
+                    (ergoemacs-keymapp tmp)
+                    (setq tmp (lookup-key tmp (vconcat (list area event)))))
+           (setq command tmp)))
+       (unless command
+         (setq command original-command))
+       ;; (ergoemacs-command-loop--call-mouse-command command record-flag keys)
+       
+       command)
+    ;; Make sure to lookup the keys in the selected buffer
+    (ergoemacs-command-loop--sync-point)
+    (let ((trials (ergoemacs-translate--trials key))
+        tmp tmp2 ret)
+      (setq this-command-keys-shift-translated nil)
+    (catch 'found-command
+      (dolist (cur-key trials)
+        (when cur-key
+          (let* ((orig-key cur-key)
+                 (bind (key-binding orig-key t))
+                 (meta-key (ergoemacs-translate--meta-to-escape cur-key))
+                 (esc-key (ergoemacs-translate--escape-to-meta cur-key))
+                 (new-key (or meta-key esc-key))
+                 (new-binding (and new-key (key-binding new-key)))
+                 (global (and new-key
+                              (list (lookup-key ergoemacs-keymap orig-key t)
+                                    (lookup-key ergoemacs-keymap new-key t)))))
+            ;; Prefer non-global keys.
+           (when (eq bind 'undefined)
+             (setq bind nil))
+           (when (eq new-binding 'undefined)
+             (setq new-binding nil))
+            (cond
+             ((not new-key)
+              (setq new-key orig-key))
+             ((not (memq bind global))
+              (setq new-key orig-key))
+             ((and new-binding (not (memq new-binding global)))
+              (setq bind new-binding)))
+            (unless bind
+              (cond
+               ((or (ergoemacs-keymapp (setq tmp (lookup-key input-decode-map 
orig-key)))
+                    (and (not (integerp tmp)) (commandp tmp)))
+                (setq bind tmp))
+               ((or (ergoemacs-keymapp (setq tmp (lookup-key 
local-function-key-map orig-key)))
+                    (and (not (integerp tmp)) (commandp tmp)))
+                (setq bind tmp))
+               ((or (ergoemacs-keymapp (setq tmp (lookup-key 
key-translation-map orig-key)))
+                    (and (not (integerp tmp)) (commandp tmp)))
+                (setq bind tmp))))
+            (when (and orig-key
+                       (setq ret bind
+                             ret (if (and (eq ret 'ergoemacs-map-undefined)
+                                          (equal orig-key (nth 0 trials))
+                                          (nth 1 trials)) nil ret)))
+              (cond
+               ((equal orig-key (nth 0 trials))
+                (setq ergoemacs-command-loop--single-command-keys new-key)
+               ;; (message "History %s" (length 
ergoemacs-command-loop--history))
+                (when (and (not (eq ergoemacs-handle-ctl-c-or-ctl-x 
'only-C-c-and-C-x))
+                          (ergoemacs-keymapp ret)
+                           (setq tmp (lookup-key ret [ergoemacs-timeout])))
+                  (cond
+                   ((eq ergoemacs-handle-ctl-c-or-ctl-x 'only-copy-cut)
+                    (setq ret tmp))
+                  ((< 1  (length ergoemacs-command-loop--history)))
+                   ((not (region-active-p))) ;; its a key sequence.
+                   
+                   ((and (or ergoemacs-this-command-keys-shift-translated 
this-command-keys-shift-translated)
+                         (eq ergoemacs-handle-ctl-c-or-ctl-x 'both)))
+
+                   ;; Immediate
+                   ((and (not ergoemacs-ctl-c-or-ctl-x-delay)
+                        (eq ergoemacs-handle-ctl-c-or-ctl-x 'both))
+                    (setq ret tmp))
+                   
+                   (t ;; with delay
+                   (if ergoemacs-command-loop--decode-event-timeout-p
+                       (setq tmp2 nil
+                             ergoemacs-command-loop--decode-event-timeout-p 
nil))
+                    (setq tmp2 (with-timeout (ergoemacs-ctl-c-or-ctl-x-delay 
nil)
+                                 (ergoemacs-command-loop--read-event nil key)))
+                    (if (not tmp2)
+                        (setq ret tmp) ;; timeout, use copy/cut
+                      ;; Actual key
+                      (setq ret (ergoemacs-command-loop--key-lookup (vconcat 
key (vector tmp2))))))))
+                (ergoemacs-command-loop--message-binding new-key ret))
+               ((equal orig-key (nth 1 trials)) ;; `ergoemacs-mode' shift 
translation
+                (setq this-command-keys-shift-translated t
+                      ergoemacs-command-loop--single-command-keys (nth 0 
trials))
+                
+                ;; Shift+Control+c
+                (when (and (ergoemacs-keymapp ret)
+                           (setq tmp (lookup-key ret [ergoemacs-timeout]))
+                           (eq ergoemacs-handle-ctl-c-or-ctl-x 'both))
+                  (setq ret tmp))
+                (ergoemacs-command-loop--message-binding new-key ret key))
+               (t
+                (ergoemacs-command-loop--message-binding new-key ret key)
+                (setq ergoemacs-command-loop--single-command-keys new-key)))
+              (throw 'found-command ret))))))
+    ret)))
+
+(defun ergoemacs-command-loop--execute-handle-shift-selection (function)
+  "Allow `ergoemacs-mode' command loop to handle shift selection.
+
+This will apply `handle-shift-selection' when FUNCTION is
+considered a shift-selection compatible function.
+
+This allows shift-selection of non-letter keys.
+For instance in QWERTY M-> is shift translated to M-."
+  (when (ergoemacs :movement-p function)
+    (handle-shift-selection)))
+
+(defun ergoemacs-command-loop--execute-rm-keyfreq (command)
+  "Remove COMMAND from `keyfreq-mode' counts."
+  (when (featurep 'keyfreq)
+    (when keyfreq-mode
+      (let (count)
+        (setq count (ergoemacs-gethash (cons major-mode command) 
keyfreq-table))
+        (cond
+         ((not count))
+         ((= count 1)
+          (remhash (cons major-mode command) keyfreq-table))
+         (count
+          (puthash (cons major-mode command) (- count 1)
+                   keyfreq-table)))
+        ;; Add local-fn to counter.
+        (setq count (ergoemacs-gethash (cons major-mode command) 
keyfreq-table))
+        (puthash (cons major-mode command) (if count (+ count 1) 1)
+                 keyfreq-table)))))
+
+;; (3) execute command
+(defun ergoemacs-command-loop--execute (command &optional keys)
+  "Execute COMMAND pretending that KEYS were pressed."
+  (unwind-protect
+      (let ((keys (or keys ergoemacs-command-loop--single-command-keys)))
+        ;; (ergoemacs-command-loop--spinner)
+        (cond
+         ((or (stringp command) (vectorp command))
+          ;; If the command is a keyboard macro (string/vector) then execute
+          ;; it by adding it to `unread-command-events'
+          (let ((tmp (prefix-numeric-value current-prefix-arg)))
+            (cond
+             ((<= tmp 0) ;; Unsure what to do here.
+              (ergoemacs-command-loop--message "The %s keyboard macro was not 
run %s times" (ergoemacs-key-description (vconcat command)) tmp))
+             (t
+              (dotimes (_i tmp unread-command-events)
+                (setq unread-command-events
+                      (append (listify-key-sequence command)
+                              unread-command-events))))))
+          (setq ergoemacs-command-loop--single-command-keys nil))
+         (t
+          ;; This should be a regular command.
+          
+          ;; Remove counting of `this-command' in `keyfreq-mode'
+          ;; Shouldn't be needed any more...
+          ;; (ergoemacs-command-loop--execute-rm-keyfreq this-command)
+          
+          ;; This command execute should modify the following variables:
+          ;; - `last-repeatable-command'
+          ;; - `this-command'
+          ;; - `this-original-command'
+          
+          ;; In addition, other minor modes may store the command, so these
+          ;; should be modified as well.
+          
+          ;; These are stored in 
`ergoemacs-command-loop--execute-modify-command-list'
+
+         (ergoemacs-command-loop--execute-modify-command-list command)
+          
+          ;; Handle Shift Selection
+          (ergoemacs-command-loop--execute-handle-shift-selection this-command)
+          (when keys
+            (setq ergoemacs-command-loop--single-command-keys keys)
+            
+            ;; Modify the output for these functions when `keys' is not nil.
+            
+            ;; Assume this is a nonmenu event if it isn't a mouse event
+            (unless (consp last-command-event)
+              (setq last-nonmenu-event last-command-event)))
+          (unwind-protect
+              (progn
+                (setq ergoemacs-command-loop--running-pre-command-hook-p t)
+                (run-hooks 'pre-command-hook))
+            (setq ergoemacs-command-loop--running-pre-command-hook-p nil))
+          (unwind-protect
+              (ergoemacs-command-loop--call-interactively this-command t)
+            (setq ergoemacs-command-loop--single-command-keys nil)))))
+    ;; (ergoemacs-command-loop--spinner-end)
+    ))
+(defun ergoemacs-command-loop--shift-timeout ()
+  "This is the shift-timeout function for a key."
+  (interactive)
+  (let ((shift-trans (ergoemacs-translate--emacs-shift 
(this-single-command-keys))))
+    (if (eq ergoemacs-handle-ctl-c-or-ctl-x 'only-copy-cut)
+       (setq unread-command-events (append (ergoemacs-translate--emacs-shift 
shift-trans) '(ergoemacs-timeout)))
+      (setq ergoemacs-this-command-keys-shift-translated t)
+      (ergoemacs-command-loop--internal shift-trans))))
+
+(defun ergoemacs-command-loop--shift-translate ()
+  "Shift translation."
+  (interactive)
+  (let ((shift-trans (ergoemacs-translate--emacs-shift 
(this-single-command-keys) 'ergoemacs-shift)))
+    (message "%s->%s" (key-description (this-single-command-keys))
+            (key-description shift-trans))
+    (setq ergoemacs-this-command-keys-shift-translated t
+         this-command-keys-shift-translated t)
+    (ergoemacs-command-loop--call-interactively (key-binding shift-trans))))
 (provide 'ergoemacs-command-loop)
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;;; ergoemacs-command-loop.el ends here
diff --git a/ergoemacs-macros.el b/ergoemacs-macros.el
index 5cec912..69c8cea 100644
--- a/ergoemacs-macros.el
+++ b/ergoemacs-macros.el
@@ -316,6 +316,40 @@ When arg1 can be a property.  The following properties are 
supported:
    ((fboundp #'buffer-narrowed-p) `(buffer-narrowed-p))
    (t `(/= (- (point-max) (point-min)) (buffer-size)))))
 
+;;;###autoload
+(defmacro ergoemacs-translation (&rest body-and-plist)
+  "Defines an `ergoemacs-mode' translation.
+:text -- Text to display while completing this translation
+:keymap -- Local Keymap for translation
+:keymap-modal -- Modal keymap for overrides.
+:modal-always -- If the modal state is always on, regardless of
+                 the values of  `ergoemacs-modal-ignored-buffers',
+                `ergoemacs-modal-emacs-state-modes' `minibufferp'
+The following arguments allow the keyboard presses to be translated:
+ - :meta
+ - :control
+ - :shift
+ - :meta-control
+ - :meta-shift
+ - :control-shift
+ - :meta-control-shift
+ - :unchorded (no modifiers)
+This also creates functions:
+- ergoemacs-translate--NAME-universal-argument
+- ergoemacs-translate--NAME-digit-argument
+- ergoemacs-translate--NAME-negative-argument
+- ergoemacs-translate--NAME-modal"
+  (declare (doc-string 2)
+           (indent 2))
+  (let ((kb (make-symbol "kb")))
+    (setq kb (ergoemacs-theme-component--parse-keys-and-body body-and-plist))
+    
+    `(progn (puthash ,(intern (concat ":" (plist-get (nth 0 kb) ':name)))
+                     (lambda() ,(plist-get (nth 0 kb) ':description)
+                       (ergoemacs-translate--create :key ,(intern (concat ":" 
(plist-get (nth 0 kb) ':name)))
+                                                    ,@(nth 0 kb))) 
ergoemacs-translation-hash))))
+
+
 (provide 'ergoemacs-macros)
 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 ;;; ergoemacs-macros.el ends here
diff --git a/ergoemacs-mode.el b/ergoemacs-mode.el
index aa65846..d736b17 100644
--- a/ergoemacs-mode.el
+++ b/ergoemacs-mode.el
@@ -299,6 +299,12 @@ The `execute-extended-command' is now 
\\[execute-extended-command].
             (ergoemacs-setup-override-keymap))
            (t (ergoemacs-setup-override-keymap)))
           (setq ergoemacs-require--ini-p t)
+          (define-key key-translation-map (kbd "<apps>") (kbd "<menu>"))
+          (global-unset-key (kbd "<apps>"))
+          (global-unset-key (kbd "<menu>"))
+          (define-key ergoemacs-translate--parent-map  (if (eq system-type 
'windows-nt) [apps] [menu])
+            'ergoemacs-command-loop--swap-translation)
+
 
           (if refresh-p
               (message "Ergoemacs-mode keys refreshed (%s)" 
ergoemacs-keyboard-layout)
diff --git a/ergoemacs-themes.el b/ergoemacs-themes.el
index 635fd6e..1431ad3 100644
--- a/ergoemacs-themes.el
+++ b/ergoemacs-themes.el
@@ -1301,6 +1301,34 @@ keys (e.g. M-O A == <up>) or regular M-O keybinding."
   (ergoemacs-set-menu-bar-search)
   (ergoemacs-set-menu-bar-edit)
   (ergoemacs-set-menu-bar-file)
+  (ergoemacs-define-key ergoemacs-override-keymap
+                       (kbd "<menu> f")
+                       (lambda ()
+                          (interactive)
+                          (ergoemacs-command-loop "C-x" :ctl-to-alt)))
+
+  (ergoemacs-define-key ergoemacs-override-keymap
+                       (kbd "<menu> d")
+                       (lambda ()
+                          (interactive)
+                          (ergoemacs-command-loop "C-c" :unchorded-ctl)))
+
+  (ergoemacs-define-key        ergoemacs-override-keymap (kbd "<menu> n a") 
'org-agenda)
+  (ergoemacs-define-key        ergoemacs-override-keymap (kbd "<menu> n A") 
'org-capture)
+  (ergoemacs-define-key        ergoemacs-override-keymap (kbd "<menu> n C-a") 
'org-capture)
+  (ergoemacs-define-key        ergoemacs-override-keymap (kbd "<menu> n c") 
'calc)
+  (ergoemacs-define-key        ergoemacs-override-keymap (kbd "<menu> n d") 
'dired-jump)
+  (ergoemacs-define-key        ergoemacs-override-keymap (kbd "<menu> n e") 
'eshell)
+  (ergoemacs-define-key        ergoemacs-override-keymap (kbd "<menu> n p") 
'powershell)
+  (ergoemacs-define-key        ergoemacs-override-keymap (kbd "<menu> n f") 
'ergoemacs-open-in-desktop)
+  (ergoemacs-define-key        ergoemacs-override-keymap (kbd "<menu> n g") 
'grep)
+  (ergoemacs-define-key        ergoemacs-override-keymap (kbd "<menu> n m") 
'magit-status)
+  (ergoemacs-define-key        ergoemacs-override-keymap (kbd "<menu> n o") 
'ergoemacs-open-in-external-app)
+  (ergoemacs-define-key        ergoemacs-override-keymap (kbd "<menu> n r") 'R)
+  (ergoemacs-define-key        ergoemacs-override-keymap (kbd "<menu> n s") 
'shell)
+  (ergoemacs-define-key        ergoemacs-override-keymap (kbd "<menu> n t") 
'org-capture)
+  (ergoemacs-define-key        ergoemacs-override-keymap (kbd "<menu> n C-t") 
'org-agenda)
+  (ergoemacs-define-key        ergoemacs-override-keymap (kbd "<menu> n T") 
'org-agenda)
   )
 
 (defun ergoemacs-install-standard-theme ()
@@ -1385,4 +1413,82 @@ keys (e.g. M-O A == <up>) or regular M-O keybinding."
   )
 (add-hook 'calc-load-hook #'ergoemacs-install-calc-bindings)
 
+
+(ergoemacs-translation normal ()
+  "Identify transformation"
+  :keymap (let ((map (make-sparse-keymap)))
+            (define-key map [f1] 'ergoemacs-read-key-help)
+            (define-key map (read-kbd-macro "C-h") 'ergoemacs-read-key-help)
+            map))
+
+(ergoemacs-translation ctl-to-alt ()
+  "Ctl <-> Alt translation"
+  :text (lambda() (format "<Ctl%sAlt> " (ergoemacs :unicode-or-alt "↔" " to 
")))
+  
+  :meta '(control)
+  :control '(meta)
+  
+  :meta-shift '(control shift)
+  :control-shift '(meta shift)
+  
+  :control-hyper '(meta hyper)
+  :meta-hyper '(control hyper)
+
+  :control-super '(meta super)
+  :meta-super '(control super)
+
+  :meta-shift-hyper '(control shift hyper)
+  :control-shift-hyper '(meta shift hyper)
+
+  :meta-shift-super '(control shift super)
+  :control-shift-super '(meta shift super)
+
+  :meta-super-hyper '(control super hyper)
+  :control-super-hyper '(meta super hyper)
+
+  :meta-super-hyper-shift '(control super hyper shift)
+  :control-super-hyper-shift '(meta super hyper shift)
+  
+  :modal-color "blue"
+  :modal-always t
+  
+  :keymap (let ((map (make-sparse-keymap)))
+            (define-key map [f1] 'ergoemacs-read-key-help)
+            (define-key map (read-kbd-macro "M-h") 'ergoemacs-read-key-help)
+            (define-key map (if (eq system-type 'windows-nt) [M-apps] 
[M-menu]) 'ergoemacs-read-key-force-next-key-is-quoted)
+            (define-key map (read-kbd-macro "SPC") 
'ergoemacs-read-key-force-next-key-is-ctl)
+            (define-key map (read-kbd-macro "M-SPC") 
'ergoemacs-read-key-force-next-key-is-alt)
+            ;; (define-key map "G" 'ergoemacs-read-key-next-key-is-quoted)
+            ;; (define-key map "g" 'ergoemacs-read-key-next-key-is-alt)
+            map))
+
+(ergoemacs-translation unchorded-ctl ()
+  "Make the Ctl key sticky."
+  :text "<Ctl+>"
+  :unchorded '(control)
+  :shift '(control shift)
+  :meta '()
+  :control '(meta)
+  :keymap (let ((map (make-sparse-keymap)))
+            (define-key map [f1] 'ergoemacs-read-key-help)
+            (define-key map (read-kbd-macro "SPC") 
'ergoemacs-read-key-force-next-key-is-quoted)
+            (define-key map (read-kbd-macro "M-SPC") 
'ergoemacs-read-key-force-next-key-is-alt-ctl)
+            (define-key map "g" 'ergoemacs-read-key-force-next-key-is-alt)
+            (define-key map "G" 'ergoemacs-read-key-force-next-key-is-alt-ctl)
+            map))
+
+(ergoemacs-translation unchorded-alt ()
+  "Make the Alt key sticky."
+  :text "<Alt+>"
+  :unchorded '(meta) 
+  :shift '(meta shift)
+  :meta '(meta shift) 
+  :modal-color "red"
+  :keymap-modal (let ((map (make-sparse-keymap)))
+                  (define-key map (read-kbd-macro "<return>") 
'ergoemacs-unchorded-alt-modal)
+                  (define-key map (read-kbd-macro "RET") 
'ergoemacs-unchorded-alt-modal)
+                  map))
+
+
+
 (provide 'ergoemacs-themes)
diff --git a/ergoemacs-translate.el b/ergoemacs-translate.el
index e4503a3..0770c0a 100644
--- a/ergoemacs-translate.el
+++ b/ergoemacs-translate.el
@@ -1,6 +1,6 @@
 ;;; ergoemacs-translate.el --- Keyboard translation functions -*- 
lexical-binding: t -*-
 
-;; Copyright © 2013-2014  Free Software Foundation, Inc.
+;; Copyright © 2013-2021  Free Software Foundation, Inc.
 
 ;; Filename: ergoemacs-translate.el
 ;; Description: 
@@ -62,10 +62,12 @@
 (defvar ergoemacs-translate--hash)
 (defvar ergoemacs-translate--event-hash)
 (defvar ergoemacs-dir)
+(defvar ergoemacs-theme)
 (defvar ergoemacs-inkscape)
 (defvar ergoemacs-command-loop--universal-functions)
 
 (declare-function ergoemacs-layouts--list "ergoemacs-layouts")
+(declare-function ergoemacs-theme--list "ergoemacs-theme-engine")
 (declare-function ergoemacs-mode-reset "ergoemacs-mode")
 (declare-function ergoemacs-layouts--custom-documentation "ergoemacs-layouts")
 (declare-function ergoemacs-theme--custom-documentation 
"ergoemacs-theme-engine")
@@ -83,6 +85,10 @@
 (declare-function ergoemacs-map-properties--put "ergoemacs-map-properties")
 
 
+(declare-function ergoemacs-map-- "ergoemacs-map")
+
+(declare-function ergoemacs-command-loop--modal-p "ergoemacs-command-loop")
+
 (declare-function ergoemacs-translate--key-description "ergoemacs-translate")
 
 (fset #'ergoemacs-translate--key-description (symbol-function 
#'key-description))
@@ -191,6 +197,30 @@ KEY-SEQ must be a vector or string.  If there is no need 
to change the sequence,
           (push event seq))))
       (and found (vconcat seq)))))
 
+(defun ergoemacs-translate--swap-apps (key &optional what with)
+  "In KEY, swap apps key with menu key.
+Optionally specify WHAT you want to replace WITH.
+
+If no changes have been done, return nil."
+  (let ((seq (reverse (append key ())))
+        (what (or what 'apps))
+        (with (or with 'menu))
+        found-p
+        ret)
+    (dolist (e seq)
+      (cond
+       ((eq e what)
+        (push with ret)
+        (setq found-p t))
+       (t (push e ret))))
+    (if found-p
+        (vconcat ret)
+      nil)))
+
+(defun ergoemacs-translate--swap-menu (key)
+  "In KEY swap menu key with apps key."
+  (ergoemacs-translate--swap-apps key 'menu 'apps))
+
 (defun ergoemacs-translate--to-vector (key)
   "Translates KEY to vector format.
 
@@ -202,6 +232,43 @@ If no changes are performed, return nil."
         (setq ret new-key))
       ret)))
 
+(defun ergoemacs-translate--ergoemacs-shift-select (key)
+  "Translate KEY to allow `ergoemacs-mode' shift translation.
+
+This will shift translate Alt+# to Alt+3."
+  (let (modifiers basic)
+    (when (and (vectorp key)
+               ;; only makes sense for single key combinations.
+               (= (length key) 1)
+               ;; Doesn't make sense if shifted...
+               (not (or (memq 'shift (setq modifiers 
(ergoemacs-translate--event-modifiers (aref key 0))))
+                        (memq 'ergoemacs-shift modifiers)))
+              ;; Only define if emacs doesn't handle shift selection.
+              (not (eq (event-convert-list (list 'shift (setq basic 
(event-basic-type (aref key 0)))))
+                       (ergoemacs-translate--event-convert-list (list 
'ergoemacs-shift basic)))))
+      (setq ergoemacs-translate--define-key-if-defined-p nil
+            ergoemacs-translate--define-key-replacement-function 
'ergoemacs-command-loop--shift-translate)
+      (vector (ergoemacs-translate--event-convert-list (append modifiers (list 
'ergoemacs-shift basic)))))))
+
+(defun ergoemacs-translate--ergoemacs-timeout (key)
+  "Translates KEY to allow Shift translation to default to key sequence.
+
+This is done for key sequences like Ctrl+Shift+c which should
+allow the Ctrl+c key sequence to be called when text is
+seleceted (instead of copying the text)."
+  (let (modifiers basic)
+    (when (and (vectorp key)
+              ;; only makes sense for single key combinations.
+              (= (length key) 2)
+              (eq 'ergoemacs-timeout (aref key 1))
+              ;; Doesn't make sense if shifted...
+              (not (or (memq 'shift (setq modifiers 
(ergoemacs-translate--event-modifiers (aref key 0))))
+                       (memq 'ergoemacs-shift modifiers))))
+      (setq basic (ergoemacs-translate--event-basic-type (aref key 0))
+           ergoemacs-translate--define-key-if-defined-p nil
+            ergoemacs-translate--define-key-replacement-function 
'ergoemacs-command-loop--shift-timeout)
+      (vector (ergoemacs-translate--event-convert-list (append modifiers (list 
'shift basic)))))))
+
 (defun ergoemacs-translate--to-string (key)
   "Translates KEY to string format.
 
@@ -217,9 +284,12 @@ If no chanegs are performed, return nil."
 (defvar ergoemacs-translate--apply-funs
   '(ergoemacs-translate--escape-to-meta
     ergoemacs-translate--meta-to-escape
+    ergoemacs-translate--swap-apps
+    ergoemacs-translate--swap-menu
     ergoemacs-translate--to-string
     ergoemacs-translate--to-vector
-    )
+    ergoemacs-translate--ergoemacs-timeout
+    ergoemacs-translate--ergoemacs-shift-select)
   "Functions to apply to key.
 
 These functions take a key as an argument and translate it in
@@ -343,6 +413,11 @@ MODIFIERS is the precalculated modifiers from
            new-modifiers
            new-event
            (translation-hash (ergoemacs-translate--get-hash layout-to 
layout-from)))
+      (cond
+       ((and (eq system-type 'windows-nt) (eq basic 'menu))
+        (setq basic 'apps))
+       ((and (not (eq system-type 'windows-nt)) (eq basic 'apps))
+        (setq basic 'menu)))
       (if (memq 'ergoemacs-control modifiers)
           (setq new-event basic
                 new-modifiers modifiers)
@@ -489,6 +564,10 @@ make the translation."
              (not just-first-p))
         (setq translated-event
               (ergoemacs-translate--event-layout event layout-to layout-from 
basic modifiers)))
+       ((and (eq system-type 'windows-nt) (eq basic 'menu))
+        (setq translated-event (ergoemacs-translate--event-convert-list 
(append modifiers '(apps)))))
+       ((and (not (eq system-type 'windows-nt)) (eq basic 'apps))
+        (setq translated-event (ergoemacs-translate--event-convert-list 
(append modifiers '(menu)))))
        (t (setq translated-event event)))
       (setq untranslated (vconcat untranslated (list event))
             ret (vconcat ret (list translated-event))))
@@ -626,6 +705,7 @@ For keys, the list consists of:
   (universal-argument nil)
   (negative-argument nil)
   (digit-argument nil)
+  (modal nil)
   (text "")
   (keymap (make-sparse-keymap))
   (keymap-modal (make-sparse-keymap))
@@ -634,6 +714,62 @@ For keys, the list consists of:
   (key nil)
   (unchorded nil))
 
+(defvar ergoemacs-translate--setup-command-loop-regexp
+  
"^\\(?:ergoemacs\\(?:-translate-\\)?\\)-\\(.*?\\)-\\(universal-argument\\|negative-argument\\|digit-argument\\|modal\\)$"
+  "Command loop command match/setup regular expression.")
+
+(defun ergoemacs-translate--setup-command-loop ()
+  "Setup command loop.
+To do anything, `this-command' must match
+`ergoemacs-translate--setup-command-loop-regexp'.  The first
+match is the NAME of the translation, the second match is the
+TYPE of command.  This command will then
+call (ergoemacs-command-loop-TYPE :NAME)."
+  (interactive)
+  (let ((command-str (symbol-name this-command))
+       name type)
+    (save-match-data
+      (when (string-match ergoemacs-translate--setup-command-loop-regexp 
command-str)
+       (setq name (match-string 1 command-str)
+             type (match-string 2 command-str))
+       (funcall (intern (concat "ergoemacs-command-loop--" type)) (intern 
(concat ":" name)))))))
+
+(defun ergoemacs-translate--setup-translation (&optional name)
+  "Setup translation functions and keymaps.
+If NAME is nil, setup all translations.
+When NAME is a symbol, setup the translation function for the symbol."
+  (if (not name)
+      (maphash
+       (lambda(name _item)
+        (ergoemacs-translate--setup-translation name))
+       ergoemacs-translation-hash)
+    (let ((name-str (and (symbolp name) (substring (symbol-name name) 1))))
+      (eval
+       (macroexpand ; Fixme why?
+       `(progn
+          (defvar ,(intern (concat "ergoemacs-translate--" name-str "-map")) 
(make-sparse-keymap)
+            ,(concat "Ergoemacs local map for translation :"
+                     name-str
+                     " while completing a key sequence."))
+          (define-obsolete-variable-alias ',(intern (concat "ergoemacs-" 
name-str "-translation-local-map"))
+             ',(intern (concat "ergoemacs-translate--" name-str "-map"))
+            "Ergoemacs-v5.16")))
+       t)
+      (ergoemacs-map-properties--label-map (intern (concat 
"ergoemacs-translate--" name-str "-map")) t)
+      (ergoemacs (symbol-value (intern (concat "ergoemacs-translate--" 
name-str "-map"))) :only-local-modifications-p t)
+      ;; 
+      (dolist (type '("-universal-argument" "-negative-argument"
+                      "-digit-argument" "-modal"))
+       (fset (intern (concat "ergoemacs-translate--" name-str type))
+             'ergoemacs-translate--setup-command-loop)
+       (fset (intern (concat "ergoemacs-" name-str type))
+             'ergoemacs-translate--setup-command-loop)
+       (when (string= type "-universal-argument")
+         (cl-pushnew (intern (concat "ergoemacs-" name-str type)) 
ergoemacs-command-loop--universal-functions)
+         (cl-pushnew (intern (concat "ergoemacs-translate--" name-str type)) 
ergoemacs-command-loop--universal-functions))))))
+
+(add-hook 'ergoemacs-mode-intialize-hook 
#'ergoemacs-translate--setup-translation)
+
 (defun ergoemacs-translate--create (&rest plist)
   "Create a translation from PLIST and return translation object."
   (let ((plist plist)
@@ -641,6 +777,7 @@ For keys, the list consists of:
         -universal-argument
         -negative-argument
         -digit-argument
+        -modal
         translation
         (local-keymap (or (plist-get plist :keymap) (make-sparse-keymap)))
        (trans-keymap (intern (concat "ergoemacs-translate--" (plist-get plist 
:name) "-map"))))
@@ -686,6 +823,7 @@ For keys, the list consists of:
            :universal-argument -universal-argument
            :negative-argument -negative-argument
            :digit-argument -digit-argument
+           :modal -modal
            :text (plist-get plist :text)
            :keymap local-keymap
            :keymap-modal (or (plist-get plist :keymap-modal) 
(make-sparse-keymap))
@@ -720,7 +858,8 @@ If TYPE is unspecified, assume :normal translation"
                               ((eq 'ergoemacs-shift e) 'shift)
                               ((eq 'ergoemacs-control e) 'control)
                               (t e)))
-                           e-mod) #'string<))
+                           e-mod)
+                         #'string<))
          (special-p (memq basic (list ?m ?i ?\[)))
          (ambiguous-p (and special-p (memq 'control e-mod)))
          tmp
@@ -746,7 +885,8 @@ If TYPE is unspecified, assume :normal translation"
                  ((and special-p (display-graphic-p)
                        (memq 'control modifiers))
                   (push 'ergoemacs-gui modifiers)))
-                (throw 'found-mod t))) nil)
+                (throw 'found-mod t)))
+           nil)
       (if ambiguous-p
           (setq ret (ergoemacs-translate--event-convert-list `(control 
,@modifiers ,basic)))
         (setq ret (ergoemacs-translate--event-convert-list `(,@modifiers 
,basic)))))
@@ -754,23 +894,18 @@ If TYPE is unspecified, assume :normal translation"
 
 (defun ergoemacs-translate--no-gui (event)
   "Remove any gui elements to the EVENT.
-If there are no gui elements, retun nil."
+If there are no gui elements, return nil."
   (if (vectorp event)
-      (eval `(vector ,@(mapcar (lambda(x) (let ((ret (or 
(ergoemacs-translate--no-gui x) x)))
-                                           (if (symbolp ret)
-                                               `(quote ,ret)
-                                             ret))) event)))
+      (apply #'vector (mapcar (lambda(x) (or (ergoemacs-translate--no-gui x) 
x)) event))
     (let* ((last-event event)
           (last-mod (ergoemacs-translate--event-modifiers last-event))
           (last-basic-event (ergoemacs-translate--event-basic-type last-event))
-          new-mod
-          new-event)
+          new-mod)
       (when (memq 'ergoemacs-gui last-mod)
        (dolist (elt last-mod)
          (unless (eq elt 'ergoemacs-gui)
            (push elt new-mod)))
-       (setq new-event (ergoemacs-translate--event-convert-list `(,@new-mod 
,last-basic-event))))
-      new-event)))
+       (ergoemacs-translate--event-convert-list `(,@new-mod 
,last-basic-event))))))
 
 (defvar ergoemacs-translate--parent-map nil
   "Parent map for keymaps when completing a key sequence.")
@@ -810,16 +945,25 @@ If there are no gui elements, retun nil."
 ;; (add-hook 'ergoemacs-mode-intialize-hook 
#'ergoemacs-translate--keymap-reset)
 
 (defun ergoemacs-translate--keymap (&optional translation)
-  "Get the keymap for TRANSLATION."
-  (let* ((translation (or (and (ergoemacs-translation-struct-p translation)
+  "Get the keymap for TRANSLATION.
+This takes into consideration the modal state of `ergoemacs-mode'."
+  (let* ((modal (ergoemacs :modal-p))
+         (translation (or (and (ergoemacs-translation-struct-p translation)
+                               (or (not modal) ;; prefer modal when :normal 
+                                   (not (eq :normal 
(ergoemacs-translation-struct-key translation))))
                                translation)
+                          modal
                           (ergoemacs-translate--get (or translation :normal))))
-         (key (ergoemacs-translation-struct-key translation))
+         (key (or (and modal (intern (concat ":" 
(ergoemacs-translation-struct-name translation) "-modal")))
+                  (ergoemacs-translation-struct-key translation)))
          (ret (ergoemacs-gethash key ergoemacs-translate--keymap-hash))
          keymap)
     (unless ret
-      (setq keymap (ergoemacs-translation-struct-keymap translation)
-            ret (make-composed-keymap (ergoemacs keymap) (ergoemacs 
ergoemacs-translate--parent-map)))
+      (if modal
+          (setq keymap (ergoemacs-translation-struct-keymap-modal translation)
+                ret keymap)
+        (setq keymap (ergoemacs-translation-struct-keymap translation)
+              ret (make-composed-keymap (ergoemacs keymap) (ergoemacs 
ergoemacs-translate--parent-map))))
       (puthash key ret ergoemacs-translate--keymap-hash))
     ret))
 
@@ -984,13 +1128,15 @@ If there are no gui elements, retun nil."
           (setq ret (format "%s\n%s=%s" ret f (ergoemacs-translate--ahk-code 
key))))))
     ret))
 
-(defun ergoemacs-translate--ahk-ini (&optional all-layouts)
+(defun ergoemacs-translate--ahk-ini (&optional all-layouts all-themes)
   "Creates the ini file used with the autohotkey script."
   (let ((layouts (or (and all-layouts (sort (ergoemacs-layouts--list) 
'string<))
                      (and (eq (ergoemacs :layout) 'ergoemacs-layout-us) (list 
"us"))
                      (list "us" ergoemacs-keyboard-layout)))
-        (themes (list "standard"))
+        (themes (or (and all-themes (sort (ergoemacs-theme--list) 'string<))
+                    (list ergoemacs-theme)))
         (original-layout ergoemacs-keyboard-layout)
+        (original-theme ergoemacs-theme)
         ret)
     (unwind-protect
         (setq ret (with-temp-buffer
@@ -1004,13 +1150,15 @@ If there are no gui elements, retun nil."
                     (dolist (lay layouts)
                       (dolist (theme themes)
                         (message "Getting information from %s-%s" lay theme)
-                        (setq ergoemacs-keyboard-layout lay)
+                        (setq ergoemacs-keyboard-layout lay
+                              ergoemacs-theme theme)
                         (ergoemacs-mode-reset)
                         (insert "[" lay "-" theme "]"
                                 (ergoemacs-translate--ahk-functions-ini)
                                 "\n")))
                     (buffer-string)))
-      (setq ergoemacs-keyboard-layout original-layout)
+      (setq ergoemacs-keyboard-layout original-layout
+            ergoemacs-theme original-theme)
       (ergoemacs-mode-reset))
     ret))
 
@@ -1067,14 +1215,23 @@ If :type is :quail use the 180 length string that
            ((string-match "[a-zA-Z0-9]" char)
             char)
            (t
-            ;; Insert fancy characters as is and hope that the font
-            ;; will work.
             (setq ret (format "&#x%04X;"
                                (encode-char
                                 (with-temp-buffer
                                   (insert char)
                                   (char-before)) 'unicode))
-                  )
+                  font (ergoemacs-key-description--display-char-p char))
+            (when font
+              (setq font (or (font-get font :name)
+                             (font-get font :family)))
+              (when (and font (symbolp font))
+                (setq font (symbol-name font)))
+              (setq default-font (or (font-get default-font :name)
+                                     (font-get default-font :family)))
+              (when (and default-font (symbolp default-font))
+                (setq default-font (symbol-name default-font)))
+              (unless (string= font default-font)
+                (setq ret (format "<text style=\"font-family: 
'%s'\">%s</text>" font ret))))
             ret)))
       (while (< i (length char))
         (setq ret (concat ret (ergoemacs-translate--svg-quote (substring char 
i (+ i 1))))



reply via email to

[Prev in Thread] Current Thread [Next in Thread]