From 981293f06af320f2929fd0d209eb97e63b4d8e3e Mon Sep 17 00:00:00 2001 From: Chris Feng Date: Wed, 26 Aug 2015 15:27:31 +0800 Subject: Replay KeyPress events instead of fake them in line-mode X windows in line-mode receive KeyPress events faked with SendEvent requests previously. This causes many problems including: * Some applications (e.g. xterm) ignore synthetic events completely * KeyPress and KeyRelease evnets arrive disorderly This commit makes EXWM exploiting AllowEvents requests (in ReplayKeyboard mode) to forward KeyPress events to X windows instead. --- exwm-input.el | 77 +++++++++++++++++++---------------------------------------- 1 file changed, 24 insertions(+), 53 deletions(-) (limited to 'exwm-input.el') diff --git a/exwm-input.el b/exwm-input.el index 760e5c96dc..ede635c54e 100644 --- a/exwm-input.el +++ b/exwm-input.el @@ -241,61 +241,27 @@ It's updated in several occasions, and only used by `exwm-input--set-focus'.") (defvar exwm-input--temp-line-mode nil "Non-nil indicates it's in temporary line-mode for char-mode.") -;; ;; This implementation has a problem that it also releases queued keys after -;; ;; requesting AllowEvent. The client window will capture unexpected key events -;; ;; in this case. -;; ;; P.S.; to use this implementation, comment out the KeyRelease listener -;; ;; together with this one and make GrabKey in Sync mode. -;; (cl-defmethod exwm-input--on-KeyPress-line-mode ((obj xcb:KeyPress)) -;; "Parse X KeyPress event to Emacs key event and then feed the command loop." -;; (with-slots (detail state) obj -;; (let ((keysym (xcb:keysyms:keycode->keysym exwm--connection detail state)) -;; event window mode) -;; (when (and keysym -;; (setq event (xcb:keysyms:keysym->event keysym state)) -;; (or exwm-input--during-key-sequence -;; (setq window (active-minibuffer-window)) -;; (eq event ?\C-c) ;mode-specific key -;; (memq event exwm-input--global-prefix-keys) -;; (memq event exwm-input-prefix-keys) -;; (memq event -;; exwm-input--simulation-prefix-keys))) -;; (setq mode xcb:Allow:SyncKeyboard) -;; (unless window (setq exwm-input--during-key-sequence t)) -;; (push event unread-command-events)) -;; (xcb:+request exwm--connection -;; (make-instance 'xcb:AllowEvents -;; :mode (or mode xcb:Allow:ReplayKeyboard) -;; :time xcb:Time:CurrentTime)) -;; (xcb:flush exwm--connection)))) - -;; This implementation has a drawback that some (legacy) applications -;; (e.g. xterm) ignore the synthetic key events, making it only viable for EXWM -;; to work in char-mode in such case. (cl-defmethod exwm-input--on-KeyPress-line-mode ((obj xcb:KeyPress)) "Parse X KeyPress event to Emacs key event and then feed the command loop." (with-slots (detail state) obj (let ((keysym (xcb:keysyms:keycode->keysym exwm--connection detail state)) - event minibuffer-window) - (if (and keysym - (setq event (xcb:keysyms:keysym->event keysym state)) - (or exwm-input--during-key-sequence - (setq minibuffer-window (active-minibuffer-window)) - (eq event ?\C-c) ;mode-specific key - (memq event exwm-input--global-prefix-keys) - (memq event exwm-input-prefix-keys) - (memq event exwm-input--simulation-prefix-keys))) - ;; Forward key to Emacs frame - (progn (unless minibuffer-window - (setq exwm-input--during-key-sequence t)) - (push event unread-command-events)) - ;; Forward key to window - (xcb:+request exwm--connection - (make-instance 'xcb:SendEvent - :propagate 0 :destination (slot-value obj 'event) - :event-mask xcb:EventMask:NoEvent - :event (xcb:marshal obj exwm--connection))) - (xcb:flush exwm--connection))))) + event minibuffer-window mode) + (when (and keysym + (setq event (xcb:keysyms:keysym->event keysym state)) + (or exwm-input--during-key-sequence + (setq minibuffer-window (active-minibuffer-window)) + (eq event ?\C-c) ;mode-specific key + (memq event exwm-input--global-prefix-keys) + (memq event exwm-input-prefix-keys) + (memq event exwm-input--simulation-prefix-keys))) + (setq mode xcb:Allow:AsyncKeyboard) + (unless minibuffer-window (setq exwm-input--during-key-sequence t)) + (push event unread-command-events)) + (xcb:+request exwm--connection + (make-instance 'xcb:AllowEvents + :mode (or mode xcb:Allow:ReplayKeyboard) + :time xcb:Time:CurrentTime)) + (xcb:flush exwm--connection)))) (cl-defmethod exwm-input--on-KeyPress-char-mode ((obj xcb:KeyPress)) "Handle KeyPress event in char-mode." @@ -307,7 +273,12 @@ It's updated in several occasions, and only used by `exwm-input--set-focus'.") (setq exwm-input--temp-line-mode t exwm-input--during-key-sequence t) (exwm-input--grab-keyboard)) ;grab keyboard temporarily - (push event unread-command-events))))) + (push event unread-command-events)))) + (xcb:+request exwm--connection + (make-instance 'xcb:AllowEvents + :mode xcb:Allow:AsyncKeyboard + :time xcb:Time:CurrentTime)) + (xcb:flush exwm--connection)) (defun exwm-input--grab-keyboard (&optional id) "Grab all key events on window ID." @@ -319,7 +290,7 @@ It's updated in several occasions, and only used by `exwm-input--set-focus'.") :modifiers xcb:ModMask:Any :key xcb:Grab:Any :pointer-mode xcb:GrabMode:Async - :keyboard-mode xcb:GrabMode:Async)) + :keyboard-mode xcb:GrabMode:Sync)) (exwm--log "Failed to grab keyboard for #x%x" id)) (setq exwm--on-KeyPress 'exwm-input--on-KeyPress-line-mode))) -- cgit 1.4.1