about summary refs log tree commit diff
path: root/exwm-input.el
diff options
context:
space:
mode:
Diffstat (limited to 'exwm-input.el')
-rw-r--r--exwm-input.el307
1 files changed, 85 insertions, 222 deletions
diff --git a/exwm-input.el b/exwm-input.el
index 9bb6444808c0..153410828f00 100644
--- a/exwm-input.el
+++ b/exwm-input.el
@@ -36,9 +36,6 @@
 ;;; Code:
 
 (require 'xcb-keysyms)
-(require 'xcb-xinput)
-(require 'xcb-xtest)
-
 (require 'exwm-core)
 
 (defgroup exwm-input nil
@@ -105,8 +102,6 @@ defined in `exwm-mode-map' here."
 (defconst exwm-input--update-focus-interval 0.01
   "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
   "Indicate whether between `pre-command-hook' and `post-command-hook'.")
 
@@ -369,44 +364,6 @@ ARGS are additional arguments to CALLBACK."
                      :window exwm--root
                      :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)
   "Handle ButtonPress event."
   (let ((obj (make-instance 'xcb:ButtonPress))
@@ -460,30 +417,12 @@ ARGS are additional arguments to CALLBACK."
 
 (defun exwm-input--on-KeyPress (data _synthetic)
   "Handle KeyPress event."
-  (let ((obj (make-instance 'xcb:xinput:KeyPress)))
+  (let ((obj (make-instance 'xcb:KeyPress)))
     (xcb:unmarshal obj data)
     (if (eq major-mode 'exwm-mode)
         (funcall exwm--on-KeyPress obj data)
       (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)
   "Handle CreateNotify events."
   (let ((evt (make-instance 'xcb:CreateNotify)))
@@ -506,44 +445,29 @@ ARGS are additional arguments to CALLBACK."
                            'children))))))
 
 (defun exwm-input--grab-global-prefix-keys (&rest xwins)
-  (let ((req (make-instance 'xcb:xinput:XIPassiveGrabDevice
-                            :time xcb:Time:CurrentTime
+  (let ((req (make-instance 'xcb:GrabKey
+                            :owner-events 0
                             :grab-window nil
-                            :cursor 0
-                            :detail nil
-                            :deviceid nil
-                            :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 nil))
-        keysym keycode sequences)
+                            :modifiers nil
+                            :key nil
+                            :pointer-mode xcb:GrabMode:Async
+                            :keyboard-mode xcb:GrabMode:Async))
+        keysym keycode)
     (dolist (k exwm-input--global-prefix-keys)
       (setq keysym (xcb:keysyms:event->keysym exwm--connection k)
             keycode (xcb:keysyms:keysym->keycode exwm--connection
                                                  (car keysym)))
-      (setf (slot-value req 'modifiers) (list (cdr keysym))
-            (slot-value req 'detail) keycode)
-      (dolist (device exwm-input--devices)
-        (setf (slot-value req 'deviceid) device)
-        (dolist (xwin xwins)
-          (setf (slot-value req 'grab-window) xwin)
-          (setq sequences (append sequences
-                                  (list (xcb:+request exwm--connection req))))
-          ;; Also grab this key with num-lock mask set.
-          (when (/= 0 xcb:keysyms:num-lock-mask)
-            (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))))
+      (setf (slot-value req 'modifiers) (cdr keysym)
+            (slot-value req 'key) keycode)
+      (dolist (xwin xwins)
+        (setf (slot-value req 'grab-window) xwin)
+        (xcb:+request exwm--connection req)
+        ;; Also grab this key with num-lock mask set.
+        (when (/= 0 xcb:keysyms:num-lock-mask)
+          (setf (slot-value req 'modifiers)
+                (logior (cdr keysym) xcb:keysyms:num-lock-mask))
+          (xcb:+request exwm--connection req))))
+    (xcb:flush exwm--connection)))
 
 (defun exwm-input--set-key (key command)
   (global-set-key key command)
@@ -639,71 +563,60 @@ instead."
 
 (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."
-  (with-slots (deviceid detail root-x root-y mods) key-press
-    (let* ((state (slot-value mods 'effective))
-           (keysym (xcb:keysyms:keycode->keysym exwm--connection detail state))
-           event raw-event)
-      (if (and (/= 0 (car keysym))
-               (setq raw-event (xcb:keysyms:keysym->event
-                                exwm--connection (car keysym)
-                                (logand state (lognot (cdr keysym)))))
-               (setq event (exwm-input--mimic-read-event raw-event))
-               (or exwm-input-line-mode-passthrough
-                   exwm-input--during-command
-                   ;; Forward the event when there is an incomplete key
-                   ;; sequence or when the minibuffer is active.
-                   exwm-input--line-mode-cache
-                   (eq (active-minibuffer-window) (selected-window))
-                   ;;
-                   (memq event exwm-input--global-prefix-keys)
-                   (memq event exwm-input-prefix-keys)
-                   (when overriding-terminal-local-map
-                     (lookup-key overriding-terminal-local-map
-                                 (vector event)))
-                   (lookup-key (current-local-map) (vector event))
-                   (gethash event exwm-input--simulation-keys)))
-          (progn
-            (exwm-input--cache-event event)
-            (exwm-input--unread-event raw-event))
-        (if (/= 0 (logand #x6000 state)) ;Check the 13~14 bits.
-            ;; An XKB state; sent it with SendEvent.
-            ;; FIXME: Can this also be replayed?
-            ;; FIXME: KeyRelease events are lost.
-            (xcb:+request exwm--connection
-                (make-instance 'xcb:SendEvent
-                               :propagate 0
-                               :destination (slot-value key-press 'event)
-                               :event-mask xcb:EventMask:NoEvent
-                               :event raw-data))
-          ;; Replay the key.
+  (with-slots (detail state) key-press
+    (let ((keysym (xcb:keysyms:keycode->keysym exwm--connection detail state))
+          event raw-event mode)
+      (when (and (/= 0 (car keysym))
+                 (setq raw-event (xcb:keysyms:keysym->event
+                                  exwm--connection (car keysym)
+                                  (logand state (lognot (cdr keysym)))))
+                 (setq event (exwm-input--mimic-read-event raw-event))
+                 (or exwm-input-line-mode-passthrough
+                     exwm-input--during-command
+                     ;; Forward the event when there is an incomplete key
+                     ;; sequence or when the minibuffer is active.
+                     exwm-input--line-mode-cache
+                     (eq (active-minibuffer-window) (selected-window))
+                     ;;
+                     (memq event exwm-input--global-prefix-keys)
+                     (memq event exwm-input-prefix-keys)
+                     (when overriding-terminal-local-map
+                       (lookup-key overriding-terminal-local-map
+                                   (vector event)))
+                     (lookup-key (current-local-map) (vector event))
+                     (gethash event exwm-input--simulation-keys)))
+        (setq mode xcb:Allow:AsyncKeyboard)
+        (exwm-input--cache-event event)
+        (exwm-input--unread-event raw-event))
+      (unless mode
+        (if (= 0 (logand #x6000 state)) ;Check the 13~14 bits.
+            ;; Not an XKB state; just replay it.
+            (setq mode xcb:Allow:ReplayKeyboard)
+          ;; An XKB state; sent it with SendEvent.
+          ;; FIXME: Can this also be replayed?
+          ;; FIXME: KeyRelease events are lost.
+          (setq mode xcb:Allow:AsyncKeyboard)
           (xcb:+request exwm--connection
-              (make-instance 'xcb:xtest:FakeInput
-                             :type 2    ;KeyPress
-                             :detail detail
-                             :time xcb:Time:CurrentTime
-                             :root exwm--root
-                             :rootX root-x
-                             :rootY root-y
-                             :deviceid deviceid)))
+              (make-instance 'xcb:SendEvent
+                             :propagate 0
+                             :destination (slot-value key-press 'event)
+                             :event-mask xcb:EventMask:NoEvent
+                             :event raw-data)))
         ;; Make Emacs aware of this event when defining keyboard macros.
         (when (and defining-kbd-macro event)
           (set-transient-map '(keymap (t . (lambda () (interactive)))))
           (exwm-input--unread-event event)))
       (xcb:+request exwm--connection
-          (make-instance 'xcb:xinput:XIAllowEvents
-                         :time xcb:Time:CurrentTime
-                         :deviceid deviceid
-                         :event-mode xcb:xinput:EventMode:AsyncDevice
-                         :touchid 0
-                         :grab-window 0))
+          (make-instance 'xcb:AllowEvents
+                         :mode mode
+                         :time xcb:Time:CurrentTime))
       (xcb:flush exwm--connection))))
 
 (defun exwm-input--on-KeyPress-char-mode (key-press &optional _raw-data)
   "Handle KeyPress event in char-mode."
-  (with-slots (deviceid detail mods) key-press
-    (let* ((state (slot-value mods 'effective))
-           (keysym (xcb:keysyms:keycode->keysym exwm--connection detail state))
-           event raw-event)
+  (with-slots (detail state) key-press
+    (let ((keysym (xcb:keysyms:keycode->keysym exwm--connection detail state))
+          event raw-event)
       (when (and (/= 0 (car keysym))
                  (setq raw-event (xcb:keysyms:keysym->event
                                   exwm--connection (car keysym)
@@ -715,15 +628,12 @@ instead."
           (setq exwm-input--temp-line-mode t)
           (exwm-input--grab-keyboard)
           (exwm-input--cache-event event)
-          (exwm-input--unread-event raw-event))))
-    (xcb:+request exwm--connection
-        (make-instance 'xcb:xinput:XIAllowEvents
-                       :time xcb:Time:CurrentTime
-                       :deviceid deviceid
-                       :event-mode xcb:xinput:EventMode:AsyncDevice
-                       :touchid 0
-                       :grab-window 0))
-    (xcb:flush exwm--connection)))
+          (exwm-input--unread-event raw-event)))))
+  (xcb:+request exwm--connection
+      (make-instance 'xcb:AllowEvents
+                     :mode xcb:Allow:AsyncKeyboard
+                     :time xcb:Time:CurrentTime))
+  (xcb:flush exwm--connection))
 
 (defun exwm-input--update-mode-line (id)
   "Update the propertized `mode-line-process' for window ID."
@@ -757,30 +667,15 @@ instead."
   "Grab all key events on window ID."
   (unless id (setq id (exwm--buffer->id (window-buffer))))
   (when id
-    (let ((sequences
-           (mapcar
-            (lambda (device)
-              (xcb:+request exwm--connection
-                  (make-instance 'xcb:xinput:XIPassiveGrabDevice
-                                 :time xcb:Time:CurrentTime
-                                 :grab-window id
-                                 :cursor 0
-                                 :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)))
+    (when (xcb:+request-checked+request-check exwm--connection
+              (make-instance 'xcb:GrabKey
+                             :owner-events 0
+                             :grab-window id
+                             :modifiers xcb:ModMask:Any
+                             :key xcb:Grab:Any
+                             :pointer-mode xcb:GrabMode:Async
+                             :keyboard-mode xcb:GrabMode:Sync))
+      (exwm--log "Failed to grab keyboard for #x%x" id))
     (with-current-buffer (exwm--id->buffer id)
       (setq exwm--on-KeyPress #'exwm-input--on-KeyPress-line-mode))))
 
@@ -788,16 +683,12 @@ instead."
   "Ungrab all key events on window ID."
   (unless id (setq id (exwm--buffer->id (window-buffer))))
   (when id
-    (dolist (device exwm-input--devices)
-      (xcb:+request exwm--connection
-          (make-instance 'xcb:xinput:XIPassiveUngrabDevice
-                         :grab-window id
-                         :detail xcb:Grab:Any
-                         :deviceid device
-                         :num-modifiers 1
-                         :grab-type xcb:xinput:GrabType:Keycode
-                         :modifiers (list 2147483648.)))) ;1 << 31
-    (xcb:flush exwm--connection)
+    (when (xcb:+request-checked+request-check exwm--connection
+              (make-instance 'xcb:UngrabKey
+                             :key xcb:Grab:Any
+                             :grab-window id
+                             :modifiers xcb:ModMask:Any))
+      (exwm--log "Failed to release keyboard for #x%x" id))
     (exwm-input--grab-global-prefix-keys id)
     (with-current-buffer (exwm--id->buffer id)
       (setq exwm--on-KeyPress #'exwm-input--on-KeyPress-char-mode))))
@@ -1039,30 +930,6 @@ where both ORIGINAL-KEY and SIMULATED-KEY are key sequences."
 
 (defun exwm-input--init ()
   "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
   (xcb:keysyms:init exwm--connection #'exwm-input--on-keysyms-update)
   ;; Create the X window and intern the atom used to fetch timestamp.
@@ -1103,11 +970,7 @@ where both ORIGINAL-KEY and SIMULATED-KEY are key sequences."
   (xcb:+event exwm--connection 'xcb:PropertyNotify
               #'exwm-input--on-PropertyNotify)
   (xcb:+event exwm--connection 'xcb:CreateNotify #'exwm-input--on-CreateNotify)
-  (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:KeyPress #'exwm-input--on-KeyPress)
   (xcb:+event exwm--connection 'xcb:ButtonPress #'exwm-input--on-ButtonPress)
   (xcb:+event exwm--connection 'xcb:ButtonRelease
               #'exwm-floating--stop-moveresize)