Grab & Replay key events with XI2 and XTEST
; A change has been made in Xorg server 1.20 that replaying a key ; event with keyboard grabbed would generate extra focus change and ; enter/leave events. This basically breaks line-mode for apps like ; Firefox. This commit reimplements the grab & replay functionality ; with XI2 and XTEST. * exwm-input.el (exwm-input--devices): New variable for caching slave keyboards. (exwm-input--update-devices): Update it and re-grab keys if necessary. (exwm-input--on-Hierarchy): Event listener for the Hierarchy event that would in turn call `exwm-input--update-devices' to update the cache. * exwm-input.el (exwm-input--on-KeyPress): Use XI2 KeyPress events. (exwm-input--on-KeyRelease): Event listener for the KeyRelease events. (exwm-input--grab-global-prefix-keys): Use XI2 and also select KeyRelease events. (exwm-input--on-KeyPress-line-mode): Use XI2 KeyPress events and replay key events with XTEST. (exwm-input--on-KeyPress-char-mode, exwm-input--grab-keyboard) (exwm-input--release-keyboard): Use XI2 KeyPress events. * exwm-input.el (exwm-input--init): Initialize the XI2 and XTEST extensions; add listeners for XI2 KeyPress, KeyRelease and Hierarchy events.
This commit is contained in:
		
							parent
							
								
									b75c89cae2
								
							
						
					
					
						commit
						0680be104f
					
				
					 1 changed files with 222 additions and 85 deletions
				
			
		
							
								
								
									
										307
									
								
								exwm-input.el
									
										
									
									
									
								
							
							
						
						
									
										307
									
								
								exwm-input.el
									
										
									
									
									
								
							| 
						 | 
					@ -36,6 +36,9 @@
 | 
				
			||||||
;;; Code:
 | 
					;;; Code:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
(require 'xcb-keysyms)
 | 
					(require 'xcb-keysyms)
 | 
				
			||||||
 | 
					(require 'xcb-xinput)
 | 
				
			||||||
 | 
					(require 'xcb-xtest)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
(require 'exwm-core)
 | 
					(require 'exwm-core)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
(defgroup exwm-input nil
 | 
					(defgroup exwm-input nil
 | 
				
			||||||
| 
						 | 
					@ -102,6 +105,8 @@ defined in `exwm-mode-map' here."
 | 
				
			||||||
(defconst exwm-input--update-focus-interval 0.01
 | 
					(defconst exwm-input--update-focus-interval 0.01
 | 
				
			||||||
  "Time interval (in seconds) for accumulating input focus update requests.")
 | 
					  "Time interval (in seconds) for accumulating input focus update requests.")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					(defvar exwm-input--devices nil "List of slave keyboard devices.")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
(defvar exwm-input--during-command nil
 | 
					(defvar exwm-input--during-command nil
 | 
				
			||||||
  "Indicate whether between `pre-command-hook' and `post-command-hook'.")
 | 
					  "Indicate whether between `pre-command-hook' and `post-command-hook'.")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -364,6 +369,44 @@ ARGS are additional arguments to CALLBACK."
 | 
				
			||||||
                     :window exwm--root
 | 
					                     :window exwm--root
 | 
				
			||||||
                     :data (or id xcb:Window:None))))
 | 
					                     :data (or id xcb:Window:None))))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					(defun exwm-input--update-devices (update)
 | 
				
			||||||
 | 
					  "Update the cache of slave keyboards."
 | 
				
			||||||
 | 
					  (with-slots (infos)
 | 
				
			||||||
 | 
					      (xcb:+request-unchecked+reply exwm--connection
 | 
				
			||||||
 | 
					          (make-instance 'xcb:xinput:XIQueryDevice
 | 
				
			||||||
 | 
					                         :deviceid xcb:xinput:Device:All))
 | 
				
			||||||
 | 
					    (setq exwm-input--devices
 | 
				
			||||||
 | 
					          (delq nil
 | 
				
			||||||
 | 
					                (mapcar (lambda (info)
 | 
				
			||||||
 | 
					                          (with-slots (deviceid type enabled name) info
 | 
				
			||||||
 | 
					                            (setq name (downcase name))
 | 
				
			||||||
 | 
					                            (when (and (= xcb:xinput:DeviceType:SlaveKeyboard
 | 
				
			||||||
 | 
					                                          type)
 | 
				
			||||||
 | 
					                                       (string-match-p "keyboard" name)
 | 
				
			||||||
 | 
					                                       ;; Exclude XTEST keyboard.
 | 
				
			||||||
 | 
					                                       (not (string-match-p "xtest" name)))
 | 
				
			||||||
 | 
					                              deviceid)))
 | 
				
			||||||
 | 
					                        infos)))
 | 
				
			||||||
 | 
					    (unless exwm-input--devices
 | 
				
			||||||
 | 
					      (error "Failed to retrieve keyboards"))
 | 
				
			||||||
 | 
					    (when update
 | 
				
			||||||
 | 
					      ;; Try to re-grab all keys.
 | 
				
			||||||
 | 
					      (exwm-input--update-global-prefix-keys)
 | 
				
			||||||
 | 
					      (dolist (pair exwm--id-buffer-alist)
 | 
				
			||||||
 | 
					        (with-current-buffer (cdr pair)
 | 
				
			||||||
 | 
					          (when exwm--keyboard-grabbed
 | 
				
			||||||
 | 
					            (exwm-input--grab-keyboard (car pair))))))))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					(defun exwm-input--on-Hierarchy (data _synthetic)
 | 
				
			||||||
 | 
					  "Handle Hierarchy events."
 | 
				
			||||||
 | 
					  (let ((evt (make-instance 'xcb:xinput:Hierarchy)))
 | 
				
			||||||
 | 
					    (xcb:unmarshal evt data)
 | 
				
			||||||
 | 
					    (with-slots (flags infos) evt
 | 
				
			||||||
 | 
					      (when (/= 0 (logand flags
 | 
				
			||||||
 | 
					                          (logior xcb:xinput:HierarchyMask:SlaveAdded
 | 
				
			||||||
 | 
					                                  xcb:xinput:HierarchyMask:SlaveRemoved)))
 | 
				
			||||||
 | 
					        (exwm-input--update-devices t)))))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
(defun exwm-input--on-ButtonPress (data _synthetic)
 | 
					(defun exwm-input--on-ButtonPress (data _synthetic)
 | 
				
			||||||
  "Handle ButtonPress event."
 | 
					  "Handle ButtonPress event."
 | 
				
			||||||
  (let ((obj (make-instance 'xcb:ButtonPress))
 | 
					  (let ((obj (make-instance 'xcb:ButtonPress))
 | 
				
			||||||
| 
						 | 
					@ -417,12 +460,30 @@ ARGS are additional arguments to CALLBACK."
 | 
				
			||||||
 | 
					
 | 
				
			||||||
(defun exwm-input--on-KeyPress (data _synthetic)
 | 
					(defun exwm-input--on-KeyPress (data _synthetic)
 | 
				
			||||||
  "Handle KeyPress event."
 | 
					  "Handle KeyPress event."
 | 
				
			||||||
  (let ((obj (make-instance 'xcb:KeyPress)))
 | 
					  (let ((obj (make-instance 'xcb:xinput:KeyPress)))
 | 
				
			||||||
    (xcb:unmarshal obj data)
 | 
					    (xcb:unmarshal obj data)
 | 
				
			||||||
    (if (eq major-mode 'exwm-mode)
 | 
					    (if (eq major-mode 'exwm-mode)
 | 
				
			||||||
        (funcall exwm--on-KeyPress obj data)
 | 
					        (funcall exwm--on-KeyPress obj data)
 | 
				
			||||||
      (exwm-input--on-KeyPress-char-mode obj))))
 | 
					      (exwm-input--on-KeyPress-char-mode obj))))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					(defun exwm-input--on-KeyRelease (data _synthetic)
 | 
				
			||||||
 | 
					  "Handle KeyRelease event."
 | 
				
			||||||
 | 
					  ;; TODO: For simplicity every KeyRelease event is replayed which is likely
 | 
				
			||||||
 | 
					  ;; to cause overheads and perhaps problems.
 | 
				
			||||||
 | 
					  (let ((evt (make-instance 'xcb:xinput:KeyRelease)))
 | 
				
			||||||
 | 
					    (xcb:unmarshal evt data)            ;FIXME: optimize.
 | 
				
			||||||
 | 
					    (with-slots (deviceid detail root-x root-y) evt
 | 
				
			||||||
 | 
					      (xcb:+request exwm--connection
 | 
				
			||||||
 | 
					          (make-instance 'xcb:xtest:FakeInput
 | 
				
			||||||
 | 
					                         :type 3      ;KeyRelease
 | 
				
			||||||
 | 
					                         :detail detail
 | 
				
			||||||
 | 
					                         :time xcb:Time:CurrentTime
 | 
				
			||||||
 | 
					                         :root exwm--root
 | 
				
			||||||
 | 
					                         :rootX root-x
 | 
				
			||||||
 | 
					                         :rootY root-y
 | 
				
			||||||
 | 
					                         :deviceid deviceid))
 | 
				
			||||||
 | 
					      (xcb:flush exwm--connection))))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
(defun exwm-input--on-CreateNotify (data _synthetic)
 | 
					(defun exwm-input--on-CreateNotify (data _synthetic)
 | 
				
			||||||
  "Handle CreateNotify events."
 | 
					  "Handle CreateNotify events."
 | 
				
			||||||
  (let ((evt (make-instance 'xcb:CreateNotify)))
 | 
					  (let ((evt (make-instance 'xcb:CreateNotify)))
 | 
				
			||||||
| 
						 | 
					@ -445,29 +506,44 @@ ARGS are additional arguments to CALLBACK."
 | 
				
			||||||
                           'children))))))
 | 
					                           'children))))))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
(defun exwm-input--grab-global-prefix-keys (&rest xwins)
 | 
					(defun exwm-input--grab-global-prefix-keys (&rest xwins)
 | 
				
			||||||
  (let ((req (make-instance 'xcb:GrabKey
 | 
					  (let ((req (make-instance 'xcb:xinput:XIPassiveGrabDevice
 | 
				
			||||||
                            :owner-events 0
 | 
					                            :time xcb:Time:CurrentTime
 | 
				
			||||||
                            :grab-window nil
 | 
					                            :grab-window nil
 | 
				
			||||||
                            :modifiers nil
 | 
					                            :cursor 0
 | 
				
			||||||
                            :key nil
 | 
					                            :detail nil
 | 
				
			||||||
                            :pointer-mode xcb:GrabMode:Async
 | 
					                            :deviceid nil
 | 
				
			||||||
                            :keyboard-mode xcb:GrabMode:Async))
 | 
					                            :num-modifiers 1
 | 
				
			||||||
        keysym keycode)
 | 
					                            :mask-len 1
 | 
				
			||||||
 | 
					                            :grab-type xcb:xinput:GrabType:Keycode
 | 
				
			||||||
 | 
					                            :grab-mode xcb:xinput:GrabMode22:Sync
 | 
				
			||||||
 | 
					                            :paired-device-mode 0
 | 
				
			||||||
 | 
					                            :owner-events xcb:xinput:GrabOwner:NoOwner
 | 
				
			||||||
 | 
					                            :mask (list
 | 
				
			||||||
 | 
					                                   (logior xcb:xinput:XIEventMask:KeyPress
 | 
				
			||||||
 | 
					                                           xcb:xinput:XIEventMask:KeyRelease))
 | 
				
			||||||
 | 
					                            :modifiers nil))
 | 
				
			||||||
 | 
					        keysym keycode sequences)
 | 
				
			||||||
    (dolist (k exwm-input--global-prefix-keys)
 | 
					    (dolist (k exwm-input--global-prefix-keys)
 | 
				
			||||||
      (setq keysym (xcb:keysyms:event->keysym exwm--connection k)
 | 
					      (setq keysym (xcb:keysyms:event->keysym exwm--connection k)
 | 
				
			||||||
            keycode (xcb:keysyms:keysym->keycode exwm--connection
 | 
					            keycode (xcb:keysyms:keysym->keycode exwm--connection
 | 
				
			||||||
                                                 (car keysym)))
 | 
					                                                 (car keysym)))
 | 
				
			||||||
      (setf (slot-value req 'modifiers) (cdr keysym)
 | 
					      (setf (slot-value req 'modifiers) (list (cdr keysym))
 | 
				
			||||||
            (slot-value req 'key) keycode)
 | 
					            (slot-value req 'detail) keycode)
 | 
				
			||||||
      (dolist (xwin xwins)
 | 
					      (dolist (device exwm-input--devices)
 | 
				
			||||||
        (setf (slot-value req 'grab-window) xwin)
 | 
					        (setf (slot-value req 'deviceid) device)
 | 
				
			||||||
        (xcb:+request exwm--connection req)
 | 
					        (dolist (xwin xwins)
 | 
				
			||||||
        ;; Also grab this key with num-lock mask set.
 | 
					          (setf (slot-value req 'grab-window) xwin)
 | 
				
			||||||
        (when (/= 0 xcb:keysyms:num-lock-mask)
 | 
					          (setq sequences (append sequences
 | 
				
			||||||
          (setf (slot-value req 'modifiers)
 | 
					                                  (list (xcb:+request exwm--connection req))))
 | 
				
			||||||
                (logior (cdr keysym) xcb:keysyms:num-lock-mask))
 | 
					          ;; Also grab this key with num-lock mask set.
 | 
				
			||||||
          (xcb:+request exwm--connection req))))
 | 
					          (when (/= 0 xcb:keysyms:num-lock-mask)
 | 
				
			||||||
    (xcb:flush exwm--connection)))
 | 
					            (setf (slot-value req 'modifiers)
 | 
				
			||||||
 | 
					                  (list (logior (cdr keysym) xcb:keysyms:num-lock-mask)))
 | 
				
			||||||
 | 
					            (setq sequences (append sequences
 | 
				
			||||||
 | 
					                                    (list (xcb:+request exwm--connection
 | 
				
			||||||
 | 
					                                              req))))))))
 | 
				
			||||||
 | 
					    (dolist (sequence sequences)
 | 
				
			||||||
 | 
					      (xcb:+reply exwm--connection sequence))))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
(defun exwm-input--set-key (key command)
 | 
					(defun exwm-input--set-key (key command)
 | 
				
			||||||
  (global-set-key key command)
 | 
					  (global-set-key key command)
 | 
				
			||||||
| 
						 | 
					@ -563,60 +639,71 @@ instead."
 | 
				
			||||||
 | 
					
 | 
				
			||||||
(defun exwm-input--on-KeyPress-line-mode (key-press raw-data)
 | 
					(defun exwm-input--on-KeyPress-line-mode (key-press raw-data)
 | 
				
			||||||
  "Parse X KeyPress event to Emacs key event and then feed the command loop."
 | 
					  "Parse X KeyPress event to Emacs key event and then feed the command loop."
 | 
				
			||||||
  (with-slots (detail state) key-press
 | 
					  (with-slots (deviceid detail root-x root-y mods) key-press
 | 
				
			||||||
    (let ((keysym (xcb:keysyms:keycode->keysym exwm--connection detail state))
 | 
					    (let* ((state (slot-value mods 'effective))
 | 
				
			||||||
          event raw-event mode)
 | 
					           (keysym (xcb:keysyms:keycode->keysym exwm--connection detail state))
 | 
				
			||||||
      (when (and (/= 0 (car keysym))
 | 
					           event raw-event)
 | 
				
			||||||
                 (setq raw-event (xcb:keysyms:keysym->event
 | 
					      (if (and (/= 0 (car keysym))
 | 
				
			||||||
                                  exwm--connection (car keysym)
 | 
					               (setq raw-event (xcb:keysyms:keysym->event
 | 
				
			||||||
                                  (logand state (lognot (cdr keysym)))))
 | 
					                                exwm--connection (car keysym)
 | 
				
			||||||
                 (setq event (exwm-input--mimic-read-event raw-event))
 | 
					                                (logand state (lognot (cdr keysym)))))
 | 
				
			||||||
                 (or exwm-input-line-mode-passthrough
 | 
					               (setq event (exwm-input--mimic-read-event raw-event))
 | 
				
			||||||
                     exwm-input--during-command
 | 
					               (or exwm-input-line-mode-passthrough
 | 
				
			||||||
                     ;; Forward the event when there is an incomplete key
 | 
					                   exwm-input--during-command
 | 
				
			||||||
                     ;; sequence or when the minibuffer is active.
 | 
					                   ;; Forward the event when there is an incomplete key
 | 
				
			||||||
                     exwm-input--line-mode-cache
 | 
					                   ;; sequence or when the minibuffer is active.
 | 
				
			||||||
                     (eq (active-minibuffer-window) (selected-window))
 | 
					                   exwm-input--line-mode-cache
 | 
				
			||||||
                     ;;
 | 
					                   (eq (active-minibuffer-window) (selected-window))
 | 
				
			||||||
                     (memq event exwm-input--global-prefix-keys)
 | 
					                   ;;
 | 
				
			||||||
                     (memq event exwm-input-prefix-keys)
 | 
					                   (memq event exwm-input--global-prefix-keys)
 | 
				
			||||||
                     (when overriding-terminal-local-map
 | 
					                   (memq event exwm-input-prefix-keys)
 | 
				
			||||||
                       (lookup-key overriding-terminal-local-map
 | 
					                   (when overriding-terminal-local-map
 | 
				
			||||||
                                   (vector event)))
 | 
					                     (lookup-key overriding-terminal-local-map
 | 
				
			||||||
                     (lookup-key (current-local-map) (vector event))
 | 
					                                 (vector event)))
 | 
				
			||||||
                     (gethash event exwm-input--simulation-keys)))
 | 
					                   (lookup-key (current-local-map) (vector event))
 | 
				
			||||||
        (setq mode xcb:Allow:AsyncKeyboard)
 | 
					                   (gethash event exwm-input--simulation-keys)))
 | 
				
			||||||
        (exwm-input--cache-event event)
 | 
					          (progn
 | 
				
			||||||
        (exwm-input--unread-event raw-event))
 | 
					            (exwm-input--cache-event event)
 | 
				
			||||||
      (unless mode
 | 
					            (exwm-input--unread-event raw-event))
 | 
				
			||||||
        (if (= 0 (logand #x6000 state)) ;Check the 13~14 bits.
 | 
					        (if (/= 0 (logand #x6000 state)) ;Check the 13~14 bits.
 | 
				
			||||||
            ;; Not an XKB state; just replay it.
 | 
					            ;; An XKB state; sent it with SendEvent.
 | 
				
			||||||
            (setq mode xcb:Allow:ReplayKeyboard)
 | 
					            ;; FIXME: Can this also be replayed?
 | 
				
			||||||
          ;; An XKB state; sent it with SendEvent.
 | 
					            ;; FIXME: KeyRelease events are lost.
 | 
				
			||||||
          ;; FIXME: Can this also be replayed?
 | 
					            (xcb:+request exwm--connection
 | 
				
			||||||
          ;; FIXME: KeyRelease events are lost.
 | 
					                (make-instance 'xcb:SendEvent
 | 
				
			||||||
          (setq mode xcb:Allow:AsyncKeyboard)
 | 
					                               :propagate 0
 | 
				
			||||||
 | 
					                               :destination (slot-value key-press 'event)
 | 
				
			||||||
 | 
					                               :event-mask xcb:EventMask:NoEvent
 | 
				
			||||||
 | 
					                               :event raw-data))
 | 
				
			||||||
 | 
					          ;; Replay the key.
 | 
				
			||||||
          (xcb:+request exwm--connection
 | 
					          (xcb:+request exwm--connection
 | 
				
			||||||
              (make-instance 'xcb:SendEvent
 | 
					              (make-instance 'xcb:xtest:FakeInput
 | 
				
			||||||
                             :propagate 0
 | 
					                             :type 2    ;KeyPress
 | 
				
			||||||
                             :destination (slot-value key-press 'event)
 | 
					                             :detail detail
 | 
				
			||||||
                             :event-mask xcb:EventMask:NoEvent
 | 
					                             :time xcb:Time:CurrentTime
 | 
				
			||||||
                             :event raw-data)))
 | 
					                             :root exwm--root
 | 
				
			||||||
 | 
					                             :rootX root-x
 | 
				
			||||||
 | 
					                             :rootY root-y
 | 
				
			||||||
 | 
					                             :deviceid deviceid)))
 | 
				
			||||||
        ;; Make Emacs aware of this event when defining keyboard macros.
 | 
					        ;; Make Emacs aware of this event when defining keyboard macros.
 | 
				
			||||||
        (when (and defining-kbd-macro event)
 | 
					        (when (and defining-kbd-macro event)
 | 
				
			||||||
          (set-transient-map '(keymap (t . (lambda () (interactive)))))
 | 
					          (set-transient-map '(keymap (t . (lambda () (interactive)))))
 | 
				
			||||||
          (exwm-input--unread-event event)))
 | 
					          (exwm-input--unread-event event)))
 | 
				
			||||||
      (xcb:+request exwm--connection
 | 
					      (xcb:+request exwm--connection
 | 
				
			||||||
          (make-instance 'xcb:AllowEvents
 | 
					          (make-instance 'xcb:xinput:XIAllowEvents
 | 
				
			||||||
                         :mode mode
 | 
					                         :time xcb:Time:CurrentTime
 | 
				
			||||||
                         :time xcb:Time:CurrentTime))
 | 
					                         :deviceid deviceid
 | 
				
			||||||
 | 
					                         :event-mode xcb:xinput:EventMode:AsyncDevice
 | 
				
			||||||
 | 
					                         :touchid 0
 | 
				
			||||||
 | 
					                         :grab-window 0))
 | 
				
			||||||
      (xcb:flush exwm--connection))))
 | 
					      (xcb:flush exwm--connection))))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
(defun exwm-input--on-KeyPress-char-mode (key-press &optional _raw-data)
 | 
					(defun exwm-input--on-KeyPress-char-mode (key-press &optional _raw-data)
 | 
				
			||||||
  "Handle KeyPress event in char-mode."
 | 
					  "Handle KeyPress event in char-mode."
 | 
				
			||||||
  (with-slots (detail state) key-press
 | 
					  (with-slots (deviceid detail mods) key-press
 | 
				
			||||||
    (let ((keysym (xcb:keysyms:keycode->keysym exwm--connection detail state))
 | 
					    (let* ((state (slot-value mods 'effective))
 | 
				
			||||||
          event raw-event)
 | 
					           (keysym (xcb:keysyms:keycode->keysym exwm--connection detail state))
 | 
				
			||||||
 | 
					           event raw-event)
 | 
				
			||||||
      (when (and (/= 0 (car keysym))
 | 
					      (when (and (/= 0 (car keysym))
 | 
				
			||||||
                 (setq raw-event (xcb:keysyms:keysym->event
 | 
					                 (setq raw-event (xcb:keysyms:keysym->event
 | 
				
			||||||
                                  exwm--connection (car keysym)
 | 
					                                  exwm--connection (car keysym)
 | 
				
			||||||
| 
						 | 
					@ -628,12 +715,15 @@ instead."
 | 
				
			||||||
          (setq exwm-input--temp-line-mode t)
 | 
					          (setq exwm-input--temp-line-mode t)
 | 
				
			||||||
          (exwm-input--grab-keyboard)
 | 
					          (exwm-input--grab-keyboard)
 | 
				
			||||||
          (exwm-input--cache-event event)
 | 
					          (exwm-input--cache-event event)
 | 
				
			||||||
          (exwm-input--unread-event raw-event)))))
 | 
					          (exwm-input--unread-event raw-event))))
 | 
				
			||||||
  (xcb:+request exwm--connection
 | 
					    (xcb:+request exwm--connection
 | 
				
			||||||
      (make-instance 'xcb:AllowEvents
 | 
					        (make-instance 'xcb:xinput:XIAllowEvents
 | 
				
			||||||
                     :mode xcb:Allow:AsyncKeyboard
 | 
					                       :time xcb:Time:CurrentTime
 | 
				
			||||||
                     :time xcb:Time:CurrentTime))
 | 
					                       :deviceid deviceid
 | 
				
			||||||
  (xcb:flush exwm--connection))
 | 
					                       :event-mode xcb:xinput:EventMode:AsyncDevice
 | 
				
			||||||
 | 
					                       :touchid 0
 | 
				
			||||||
 | 
					                       :grab-window 0))
 | 
				
			||||||
 | 
					    (xcb:flush exwm--connection)))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
(defun exwm-input--update-mode-line (id)
 | 
					(defun exwm-input--update-mode-line (id)
 | 
				
			||||||
  "Update the propertized `mode-line-process' for window ID."
 | 
					  "Update the propertized `mode-line-process' for window ID."
 | 
				
			||||||
| 
						 | 
					@ -667,15 +757,30 @@ instead."
 | 
				
			||||||
  "Grab all key events on window ID."
 | 
					  "Grab all key events on window ID."
 | 
				
			||||||
  (unless id (setq id (exwm--buffer->id (window-buffer))))
 | 
					  (unless id (setq id (exwm--buffer->id (window-buffer))))
 | 
				
			||||||
  (when id
 | 
					  (when id
 | 
				
			||||||
    (when (xcb:+request-checked+request-check exwm--connection
 | 
					    (let ((sequences
 | 
				
			||||||
              (make-instance 'xcb:GrabKey
 | 
					           (mapcar
 | 
				
			||||||
                             :owner-events 0
 | 
					            (lambda (device)
 | 
				
			||||||
                             :grab-window id
 | 
					              (xcb:+request exwm--connection
 | 
				
			||||||
                             :modifiers xcb:ModMask:Any
 | 
					                  (make-instance 'xcb:xinput:XIPassiveGrabDevice
 | 
				
			||||||
                             :key xcb:Grab:Any
 | 
					                                 :time xcb:Time:CurrentTime
 | 
				
			||||||
                             :pointer-mode xcb:GrabMode:Async
 | 
					                                 :grab-window id
 | 
				
			||||||
                             :keyboard-mode xcb:GrabMode:Sync))
 | 
					                                 :cursor 0
 | 
				
			||||||
      (exwm--log "Failed to grab keyboard for #x%x" id))
 | 
					                                 :detail xcb:Grab:Any
 | 
				
			||||||
 | 
					                                 :deviceid device
 | 
				
			||||||
 | 
					                                 :num-modifiers 1
 | 
				
			||||||
 | 
					                                 :mask-len 1
 | 
				
			||||||
 | 
					                                 :grab-type xcb:xinput:GrabType:Keycode
 | 
				
			||||||
 | 
					                                 :grab-mode xcb:xinput:GrabMode22:Sync
 | 
				
			||||||
 | 
					                                 :paired-device-mode 0
 | 
				
			||||||
 | 
					                                 :owner-events xcb:xinput:GrabOwner:NoOwner
 | 
				
			||||||
 | 
					                                 :mask
 | 
				
			||||||
 | 
					                                 (list
 | 
				
			||||||
 | 
					                                  (logior xcb:xinput:XIEventMask:KeyPress
 | 
				
			||||||
 | 
					                                          xcb:xinput:XIEventMask:KeyRelease))
 | 
				
			||||||
 | 
					                                 :modifiers (list 2147483648.))))
 | 
				
			||||||
 | 
					            exwm-input--devices)))
 | 
				
			||||||
 | 
					      (dolist (sequence sequences)
 | 
				
			||||||
 | 
					        (xcb:+reply exwm--connection sequence)))
 | 
				
			||||||
    (with-current-buffer (exwm--id->buffer id)
 | 
					    (with-current-buffer (exwm--id->buffer id)
 | 
				
			||||||
      (setq exwm--on-KeyPress #'exwm-input--on-KeyPress-line-mode))))
 | 
					      (setq exwm--on-KeyPress #'exwm-input--on-KeyPress-line-mode))))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -683,12 +788,16 @@ instead."
 | 
				
			||||||
  "Ungrab all key events on window ID."
 | 
					  "Ungrab all key events on window ID."
 | 
				
			||||||
  (unless id (setq id (exwm--buffer->id (window-buffer))))
 | 
					  (unless id (setq id (exwm--buffer->id (window-buffer))))
 | 
				
			||||||
  (when id
 | 
					  (when id
 | 
				
			||||||
    (when (xcb:+request-checked+request-check exwm--connection
 | 
					    (dolist (device exwm-input--devices)
 | 
				
			||||||
              (make-instance 'xcb:UngrabKey
 | 
					      (xcb:+request exwm--connection
 | 
				
			||||||
                             :key xcb:Grab:Any
 | 
					          (make-instance 'xcb:xinput:XIPassiveUngrabDevice
 | 
				
			||||||
                             :grab-window id
 | 
					                         :grab-window id
 | 
				
			||||||
                             :modifiers xcb:ModMask:Any))
 | 
					                         :detail xcb:Grab:Any
 | 
				
			||||||
      (exwm--log "Failed to release keyboard for #x%x" id))
 | 
					                         :deviceid device
 | 
				
			||||||
 | 
					                         :num-modifiers 1
 | 
				
			||||||
 | 
					                         :grab-type xcb:xinput:GrabType:Keycode
 | 
				
			||||||
 | 
					                         :modifiers (list 2147483648.)))) ;1 << 31
 | 
				
			||||||
 | 
					    (xcb:flush exwm--connection)
 | 
				
			||||||
    (exwm-input--grab-global-prefix-keys id)
 | 
					    (exwm-input--grab-global-prefix-keys id)
 | 
				
			||||||
    (with-current-buffer (exwm--id->buffer id)
 | 
					    (with-current-buffer (exwm--id->buffer id)
 | 
				
			||||||
      (setq exwm--on-KeyPress #'exwm-input--on-KeyPress-char-mode))))
 | 
					      (setq exwm--on-KeyPress #'exwm-input--on-KeyPress-char-mode))))
 | 
				
			||||||
| 
						 | 
					@ -930,6 +1039,30 @@ where both ORIGINAL-KEY and SIMULATED-KEY are key sequences."
 | 
				
			||||||
 | 
					
 | 
				
			||||||
(defun exwm-input--init ()
 | 
					(defun exwm-input--init ()
 | 
				
			||||||
  "Initialize the keyboard module."
 | 
					  "Initialize the keyboard module."
 | 
				
			||||||
 | 
					  ;; Initialize the XI2 extension.
 | 
				
			||||||
 | 
					  (if (= 0 (slot-value (xcb:get-extension-data exwm--connection 'xcb:xinput)
 | 
				
			||||||
 | 
					                       'present))
 | 
				
			||||||
 | 
					      (error "[EXWM] XI2 extension is not supported by the server")
 | 
				
			||||||
 | 
					    (with-slots (major-version minor-version)
 | 
				
			||||||
 | 
					        (xcb:+request-unchecked+reply exwm--connection
 | 
				
			||||||
 | 
					            (make-instance 'xcb:xinput:XIQueryVersion
 | 
				
			||||||
 | 
					                           :major-version 2
 | 
				
			||||||
 | 
					                           :minor-version 0))
 | 
				
			||||||
 | 
					      (when (or (/= major-version 2) (/= minor-version 0))
 | 
				
			||||||
 | 
					        (error "[EXWM] XI2 extension 2.0 is not supported by the server"))))
 | 
				
			||||||
 | 
					  (exwm-input--update-devices nil)
 | 
				
			||||||
 | 
					  ;; Initialize the XTEST extension.
 | 
				
			||||||
 | 
					  (if (= 0 (slot-value (xcb:get-extension-data exwm--connection 'xcb:xtest)
 | 
				
			||||||
 | 
					                       'present))
 | 
				
			||||||
 | 
					      (error "[EXWM] XTEST extension is not supported by the server")
 | 
				
			||||||
 | 
					    (with-slots (major-version minor-version)
 | 
				
			||||||
 | 
					        (xcb:+request-unchecked+reply exwm--connection
 | 
				
			||||||
 | 
					            (make-instance 'xcb:xtest:GetVersion
 | 
				
			||||||
 | 
					                           :major-version 2
 | 
				
			||||||
 | 
					                           :minor-version 2))
 | 
				
			||||||
 | 
					      (when (or (/= major-version 2) (/= minor-version 2))
 | 
				
			||||||
 | 
					        (error "[EXWM] XTEST extension 2.2 is not supported by the server"))))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  ;; Refresh keyboard mapping
 | 
					  ;; Refresh keyboard mapping
 | 
				
			||||||
  (xcb:keysyms:init exwm--connection #'exwm-input--on-keysyms-update)
 | 
					  (xcb:keysyms:init exwm--connection #'exwm-input--on-keysyms-update)
 | 
				
			||||||
  ;; Create the X window and intern the atom used to fetch timestamp.
 | 
					  ;; Create the X window and intern the atom used to fetch timestamp.
 | 
				
			||||||
| 
						 | 
					@ -970,7 +1103,11 @@ where both ORIGINAL-KEY and SIMULATED-KEY are key sequences."
 | 
				
			||||||
  (xcb:+event exwm--connection 'xcb:PropertyNotify
 | 
					  (xcb:+event exwm--connection 'xcb:PropertyNotify
 | 
				
			||||||
              #'exwm-input--on-PropertyNotify)
 | 
					              #'exwm-input--on-PropertyNotify)
 | 
				
			||||||
  (xcb:+event exwm--connection 'xcb:CreateNotify #'exwm-input--on-CreateNotify)
 | 
					  (xcb:+event exwm--connection 'xcb:CreateNotify #'exwm-input--on-CreateNotify)
 | 
				
			||||||
  (xcb:+event exwm--connection 'xcb:KeyPress #'exwm-input--on-KeyPress)
 | 
					  (xcb:+event exwm--connection 'xcb:xinput:KeyPress #'exwm-input--on-KeyPress)
 | 
				
			||||||
 | 
					  (xcb:+event exwm--connection 'xcb:xinput:KeyRelease
 | 
				
			||||||
 | 
					              #'exwm-input--on-KeyRelease)
 | 
				
			||||||
 | 
					  (xcb:+event exwm--connection 'xcb:xinput:Hierarchy
 | 
				
			||||||
 | 
					              #'exwm-input--on-Hierarchy)
 | 
				
			||||||
  (xcb:+event exwm--connection 'xcb:ButtonPress #'exwm-input--on-ButtonPress)
 | 
					  (xcb:+event exwm--connection 'xcb:ButtonPress #'exwm-input--on-ButtonPress)
 | 
				
			||||||
  (xcb:+event exwm--connection 'xcb:ButtonRelease
 | 
					  (xcb:+event exwm--connection 'xcb:ButtonRelease
 | 
				
			||||||
              #'exwm-floating--stop-moveresize)
 | 
					              #'exwm-floating--stop-moveresize)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue