Add Customize interface for simulation keys
* exwm-input.el (exwm-input-simulation-keys): New user option for setting simulation keys. (exwm-input--init): Initialize simulation keys from this variable. * exwm-input.el (exwm-input--simulation-prefix-keys) (exwm-input--on-KeyPress-line-mode) (exwm-input--update-simulation-prefix-keys) (exwm-input-set-simulation-keys, exwm-input-set-local-simulation-keys) (exwm-input-send-simulation-key): `exwm-input--simulation-keys' is now a hash table storing both simulation keys and prefix keys. (exwm-input--unset-simulation-keys): Clear the hash table. (exwm-input--exit): Use `exwm-input--unset-simulation-keys'. * exwm-core.el (exwm--kmacro-map, exwm-mode-menu): Adapt to the change of `exwm-input--simulation-keys'. * exwm-config.el (exwm-config-default): Update the example.
This commit is contained in:
parent
5c5729c0d4
commit
7d4c57a6ab
3 changed files with 118 additions and 55 deletions
|
@ -52,17 +52,17 @@
|
|||
(interactive (list (read-shell-command "$ ")))
|
||||
(start-process-shell-command command nil command)))
|
||||
;; Line-editing shortcuts
|
||||
(exwm-input-set-simulation-keys
|
||||
'(([?\C-b] . left)
|
||||
([?\C-f] . right)
|
||||
([?\C-p] . up)
|
||||
([?\C-n] . down)
|
||||
([?\C-a] . home)
|
||||
([?\C-e] . end)
|
||||
([?\M-v] . prior)
|
||||
([?\C-v] . next)
|
||||
([?\C-d] . delete)
|
||||
([?\C-k] . (S-end delete))))
|
||||
(setq exwm-input-simulation-keys
|
||||
'(([?\C-b] . [left])
|
||||
([?\C-f] . [right])
|
||||
([?\C-p] . [up])
|
||||
([?\C-n] . [down])
|
||||
([?\C-a] . [home])
|
||||
([?\C-e] . [end])
|
||||
([?\M-v] . [prior])
|
||||
([?\C-v] . [next])
|
||||
([?\C-d] . [delete])
|
||||
([?\C-k] . [S-end delete])))
|
||||
;; Enable EXWM
|
||||
(exwm-enable)
|
||||
;; Configure Ido
|
||||
|
|
31
exwm-core.el
31
exwm-core.el
|
@ -45,7 +45,7 @@
|
|||
(defvar exwm--root nil "Root window.")
|
||||
|
||||
(defvar exwm-input--global-prefix-keys)
|
||||
(defvar exwm-input--simulation-prefix-keys)
|
||||
(defvar exwm-input--simulation-keys)
|
||||
(defvar exwm-input-line-mode-passthrough)
|
||||
(defvar exwm-input-prefix-keys)
|
||||
(declare-function exwm-input--fake-key "exwm-input.el" (event))
|
||||
|
@ -189,7 +189,7 @@ least SECS seconds later."
|
|||
(active-minibuffer-window)
|
||||
(memq last-input-event exwm-input--global-prefix-keys)
|
||||
(memq last-input-event exwm-input-prefix-keys)
|
||||
(memq last-input-event exwm-input--simulation-prefix-keys))
|
||||
(gethash last-input-event exwm-input--simulation-keys))
|
||||
(set-transient-map (make-composed-keymap (list exwm-mode-map
|
||||
global-map)))
|
||||
(push last-input-event unread-command-events))
|
||||
|
@ -229,19 +229,20 @@ least SECS seconds later."
|
|||
;; This is merely a reference.
|
||||
("Send simulation key" :filter
|
||||
(lambda (&rest _args)
|
||||
(mapcar (lambda (i)
|
||||
(let ((keys (cdr i)))
|
||||
(if (vectorp keys)
|
||||
(setq keys (append keys))
|
||||
(unless (sequencep keys)
|
||||
(setq keys (list keys))))
|
||||
(vector (key-description keys)
|
||||
`(lambda ()
|
||||
(interactive)
|
||||
(dolist (key ',keys)
|
||||
(exwm-input--fake-key key)))
|
||||
:keys (key-description (car i)))))
|
||||
exwm-input--simulation-keys)))
|
||||
(let (result)
|
||||
(maphash
|
||||
(lambda (key value)
|
||||
(when (sequencep key)
|
||||
(setq result (append result
|
||||
`([
|
||||
,(key-description value)
|
||||
(lambda ()
|
||||
(interactive)
|
||||
(dolist (i ',value)
|
||||
(exwm-input--fake-key i)))
|
||||
:keys ,(key-description key)])))))
|
||||
exwm-input--simulation-keys)
|
||||
result)))
|
||||
|
||||
["Define global binding" exwm-input-set-key]
|
||||
|
||||
|
|
120
exwm-input.el
120
exwm-input.el
|
@ -113,9 +113,6 @@
|
|||
|
||||
(defvar exwm-input--simulation-keys nil "Simulation keys in line-mode.")
|
||||
|
||||
(defvar exwm-input--simulation-prefix-keys nil
|
||||
"List of prefix keys of simulation keys in line-mode.")
|
||||
|
||||
(defvar exwm-input--temp-line-mode nil
|
||||
"Non-nil indicates it's in temporary line-mode for char-mode.")
|
||||
|
||||
|
@ -537,7 +534,7 @@ called interactively. Only invoke it non-interactively in configuration."
|
|||
;;
|
||||
(memq event exwm-input--global-prefix-keys)
|
||||
(memq event exwm-input-prefix-keys)
|
||||
(memq event exwm-input--simulation-prefix-keys)))
|
||||
(gethash event exwm-input--simulation-keys)))
|
||||
(setq mode xcb:Allow:AsyncKeyboard)
|
||||
(exwm-input--cache-event event))
|
||||
(unless mode
|
||||
|
@ -733,50 +730,111 @@ multiple keys."
|
|||
;; (unless (listp last-input-event) ;not a key event
|
||||
;; (exwm-input--fake-key last-input-event)))
|
||||
|
||||
(defun exwm-input--update-simulation-prefix-keys ()
|
||||
"Update the list of prefix keys of simulation keys."
|
||||
(setq exwm-input--simulation-prefix-keys nil)
|
||||
(dolist (i exwm-input--simulation-keys)
|
||||
(if exwm-input--local-simulation-keys
|
||||
(local-set-key (car i) #'exwm-input-send-simulation-key)
|
||||
(define-key exwm-mode-map (car i) #'exwm-input-send-simulation-key))
|
||||
(cl-pushnew (elt (car i) 0) exwm-input--simulation-prefix-keys)))
|
||||
|
||||
(defun exwm-input-set-simulation-keys (simulation-keys)
|
||||
"Set simulation keys.
|
||||
|
||||
SIMULATION-KEYS is an alist of the form (original-key . simulated-key)."
|
||||
(setq exwm-input--simulation-keys nil)
|
||||
SIMULATION-KEYS is an alist of the form (original-key . simulated-key),
|
||||
where both original-key and simulated-key are key sequences.
|
||||
|
||||
Simulation keys set this way take effect in real time. For configuration
|
||||
it's recommended to customize or set `exwm-input-simulation-keys' instead."
|
||||
;; Clear keymaps and the hash table.
|
||||
(when (hash-table-p exwm-input--simulation-keys)
|
||||
(maphash (lambda (key _value)
|
||||
(when (sequencep key)
|
||||
(if exwm-input--local-simulation-keys
|
||||
(local-unset-key key)
|
||||
(define-key exwm-mode-map key nil))))
|
||||
exwm-input--simulation-keys)
|
||||
(clrhash exwm-input--simulation-keys))
|
||||
;; Update the hash table.
|
||||
(setq exwm-input--simulation-keys (make-hash-table :test #'equal))
|
||||
(dolist (i simulation-keys)
|
||||
(cl-pushnew `(,(vconcat (car i)) . ,(cdr i)) exwm-input--simulation-keys))
|
||||
(exwm-input--update-simulation-prefix-keys))
|
||||
(let ((original (vconcat (car i)))
|
||||
(simulated (cdr i)))
|
||||
(setq simulated (if (sequencep simulated)
|
||||
(append simulated nil)
|
||||
(list simulated)))
|
||||
;; The key stored is a key sequence (vector).
|
||||
;; The value stored is a list of key events.
|
||||
(puthash original simulated exwm-input--simulation-keys)
|
||||
;; Also mark the prefix key as used.
|
||||
(puthash (aref original 0) t exwm-input--simulation-keys)))
|
||||
;; Update keymaps.
|
||||
(maphash (lambda (key _value)
|
||||
(when (sequencep key)
|
||||
(if exwm-input--local-simulation-keys
|
||||
(local-set-key key #'exwm-input-send-simulation-key)
|
||||
(define-key exwm-mode-map key
|
||||
#'exwm-input-send-simulation-key))))
|
||||
exwm-input--simulation-keys))
|
||||
|
||||
(defcustom exwm-input-simulation-keys nil
|
||||
"Simulation keys.
|
||||
|
||||
It is an alist of the form (original-key . simulated-key), where both
|
||||
original-key and simulated-key are key sequences. Original-key is what you
|
||||
type to an X window in line-mode which then gets translated to simulated-key
|
||||
by EXWM and forwarded to the X window.
|
||||
|
||||
Notes:
|
||||
* Setting the value directly (rather than customizing it) after EXWM
|
||||
finishes initialization has no effect.
|
||||
* Original-keys consist of multiple key events are only supported in Emacs
|
||||
27 and later.
|
||||
* A minority of applications do not accept simulated keys by default. It's
|
||||
required to customize them to accept events sent by SendEvent.
|
||||
* The predefined examples in the Customize interface are not guaranteed to
|
||||
work for all applications. This can be tweaked on a per application basis
|
||||
with `exwm-input-set-local-simulation-keys'."
|
||||
:type '(alist :key-type (choice (key-sequence :tag "Original"))
|
||||
:value-type (choice (key-sequence :tag "Move left" [left])
|
||||
(key-sequence :tag "Move right" [right])
|
||||
(key-sequence :tag "Move up" [up])
|
||||
(key-sequence :tag "Move down" [down])
|
||||
(key-sequence :tag "Move to BOL" [home])
|
||||
(key-sequence :tag "Move to EOL" [end])
|
||||
(key-sequence :tag "Page up" [prior])
|
||||
(key-sequence :tag "Page down" [next])
|
||||
(key-sequence :tag "Copy" [C-c])
|
||||
(key-sequence :tag "Paste" [C-v])
|
||||
(key-sequence :tag "Delete" [delete])
|
||||
(key-sequence :tag "Delete to EOL"
|
||||
[S-end delete])
|
||||
(key-sequence :tag "User-defined")))
|
||||
:set (lambda (symbol value)
|
||||
(set symbol value)
|
||||
(exwm-input-set-simulation-keys value)))
|
||||
|
||||
(defun exwm-input--unset-simulation-keys ()
|
||||
"Clear simulation keys and key bindings defined."
|
||||
(when (hash-table-p exwm-input--simulation-keys)
|
||||
(maphash (lambda (key _value)
|
||||
(when (sequencep key)
|
||||
(define-key exwm-mode-map key nil)))
|
||||
exwm-input--simulation-keys)
|
||||
(clrhash exwm-input--simulation-keys)))
|
||||
|
||||
(defun exwm-input-set-local-simulation-keys (simulation-keys)
|
||||
"Set buffer-local simulation keys.
|
||||
|
||||
Its usage is the same with `exwm-input-set-simulation-keys'."
|
||||
(make-local-variable 'exwm-input--simulation-keys)
|
||||
(make-local-variable 'exwm-input--simulation-prefix-keys)
|
||||
(use-local-map (copy-keymap exwm-mode-map))
|
||||
(let ((exwm-input--local-simulation-keys t))
|
||||
(exwm-input-set-simulation-keys simulation-keys)))
|
||||
|
||||
;;;###autoload
|
||||
(cl-defun exwm-input-send-simulation-key (times)
|
||||
"Fake a key event according to the last input key sequence.
|
||||
|
||||
Sending multiple fake keys at once is only supported by Emacs 27 and later."
|
||||
"Fake a key event according to the last input key sequence."
|
||||
(interactive "p")
|
||||
(unless (derived-mode-p 'exwm-mode)
|
||||
(cl-return-from 'exwm-input-send-simulation-key))
|
||||
(let ((pair (assoc (this-single-command-keys) exwm-input--simulation-keys)))
|
||||
(when pair
|
||||
(setq pair (cdr pair))
|
||||
(unless (listp pair)
|
||||
(setq pair (list pair)))
|
||||
(dotimes (_ times)
|
||||
(dolist (j pair)
|
||||
(exwm-input--fake-key j))))))
|
||||
(let ((keys (gethash (this-single-command-keys)
|
||||
exwm-input--simulation-keys)))
|
||||
(dotimes (_ times)
|
||||
(dolist (key keys)
|
||||
(exwm-input--fake-key key)))))
|
||||
|
||||
(defun exwm-input--on-pre-command ()
|
||||
"Run in `pre-command-hook'."
|
||||
|
@ -814,6 +872,9 @@ Sending multiple fake keys at once is only supported by Emacs 27 and later."
|
|||
:name-len (length atom)
|
||||
:name atom))
|
||||
'atom)))
|
||||
;; Initialize simulation keys.
|
||||
(when exwm-input-simulation-keys
|
||||
(exwm-input-set-simulation-keys exwm-input-simulation-keys))
|
||||
;; Attach event listeners
|
||||
(xcb:+event exwm--connection 'xcb:PropertyNotify
|
||||
#'exwm-input--on-PropertyNotify)
|
||||
|
@ -841,6 +902,7 @@ Sending multiple fake keys at once is only supported by Emacs 27 and later."
|
|||
|
||||
(defun exwm-input--exit ()
|
||||
"Exit the input module."
|
||||
(exwm-input--unset-simulation-keys)
|
||||
(remove-hook 'pre-command-hook #'exwm-input--on-pre-command)
|
||||
(remove-hook 'post-command-hook #'exwm-input--on-post-command)
|
||||
(remove-hook 'buffer-list-update-hook #'exwm-input--on-buffer-list-update)
|
||||
|
|
Loading…
Reference in a new issue