Fix auto commit issue with input methods

* exwm-xim.el (exwm-xim--handle-forward-event-request): Factored out
from `exwm-xim--on-request' to make auto commit work.  With input
methods providing candidates the first candidate can be implicitly
selected if no further matching is possible.  The last event would be
stored in `unread-command-events' (at least for `quail-input-method')
and should be reused by the input method.
(exwm-xim--on-request): Use it.
This commit is contained in:
Chris Feng 2019-06-02 00:00:00 +00:00
parent f70bdb5868
commit fe2336a11e

View file

@ -490,70 +490,8 @@ The actual XIM request is in client message data or a property."
(exwm--log "FORWARD-EVENT") (exwm--log "FORWARD-EVENT")
(setq req (make-instance 'xim:forward-event)) (setq req (make-instance 'xim:forward-event))
(xcb:unmarshal req data) (xcb:unmarshal req data)
(let ((im-func (with-current-buffer (window-buffer) (exwm-xim--handle-forward-event-request req xim:lsb conn
input-method-function)) client-xwin))
key-event keysym event result)
;; Note: The flag slot is ignored.
;; Do conversion in client's byte-order.
(let ((xcb:lsb xim:lsb))
(setq key-event (make-instance 'xcb:KeyPress))
(xcb:unmarshal key-event (slot-value req 'event)))
(with-slots (detail state) key-event
(setq keysym (xcb:keysyms:keycode->keysym exwm-xim--conn detail
state))
(when (/= (car keysym) 0)
(setq event (xcb:keysyms:keysym->event
exwm-xim--conn
(car keysym)
(logand state (lognot (cdr keysym)))))))
(if exwm-xim--event-pending
;; In case any event reaches here, it should be forwarded
;; to Emacs.
(when event
(setq unread-command-events
(append unread-command-events (list event))))
(setq exwm-xim--event-pending t)
(if (or (not im-func)
;; `list' is the default method.
(eq im-func #'list)
(not event)
;; Select only printable keys.
(not (integerp event)) (> #x20 event) (< #x7e event))
;; Either there is no active input method, or invalid key
;; is detected.
(with-slots (im-id ic-id serial-number event) req
(push (make-instance 'xim:forward-event
:im-id im-id
:ic-id ic-id
:flag xim:commit-flag:synchronous
:serial-number serial-number
:event event)
replies))
(when (eq exwm--selected-input-mode 'char-mode)
;; Grab keyboard temporarily for char-mode.
(exwm-input--grab-keyboard))
(unwind-protect
(with-temp-buffer
;; Always show key strokes.
(let ((input-method-use-echo-area t))
(setq result (funcall im-func event))))
(when (eq exwm--selected-input-mode 'char-mode)
(exwm-input--release-keyboard)))
;; This also works for portable character encoding.
(setq result
(encode-coding-string (concat result)
'compound-text-with-extensions))
(message "")
(push
(make-instance 'xim:commit-x-lookup-chars
:im-id (slot-value req 'im-id)
:ic-id (slot-value req 'ic-id)
:flag (logior xim:commit-flag:synchronous
xim:commit-flag:x-lookup-chars)
:length (length result)
:string result)
replies))
(setq exwm-xim--event-pending nil))))
((= opcode xim:opcode:sync) ((= opcode xim:opcode:sync)
(exwm--log "SYNC") (exwm--log "SYNC")
(setq req (make-instance 'xim:sync)) (setq req (make-instance 'xim:sync))
@ -591,6 +529,78 @@ The actual XIM request is in client message data or a property."
replies) replies)
(xcb:flush conn)))) (xcb:flush conn))))
(defun exwm-xim--handle-forward-event-request (req lsb conn client-xwin)
(let ((im-func (with-current-buffer (window-buffer)
input-method-function))
key-event keysym event result)
;; Note: The flag slot is ignored.
;; Do conversion in client's byte-order.
(let ((xcb:lsb lsb))
(setq key-event (make-instance 'xcb:KeyPress))
(xcb:unmarshal key-event (slot-value req 'event)))
(with-slots (detail state) key-event
(setq keysym (xcb:keysyms:keycode->keysym exwm-xim--conn detail
state))
(when (/= (car keysym) 0)
(setq event (xcb:keysyms:keysym->event
exwm-xim--conn
(car keysym)
(logand state (lognot (cdr keysym)))))))
(if exwm-xim--event-pending
;; In case any event reaches here, it should be forwarded
;; to Emacs.
(when event
(setq unread-command-events
(append unread-command-events (list event))))
(setq exwm-xim--event-pending t)
(if (or (not im-func)
;; `list' is the default method.
(eq im-func #'list)
(not event)
;; Select only printable keys.
(not (integerp event)) (> #x20 event) (< #x7e event))
;; Either there is no active input method, or invalid key
;; is detected.
(with-slots (im-id ic-id serial-number event) req
(exwm-xim--make-request
(make-instance 'xim:forward-event
:im-id im-id
:ic-id ic-id
:flag xim:commit-flag:synchronous
:serial-number serial-number
:event event)
conn client-xwin)
(xcb:flush conn))
(when (eq exwm--selected-input-mode 'char-mode)
;; Grab keyboard temporarily for char-mode.
(exwm-input--grab-keyboard))
(unwind-protect
(with-temp-buffer
;; Always show key strokes.
(let ((input-method-use-echo-area t))
(while (or event unread-command-events)
(unless event
(setq event (pop unread-command-events)))
(setq result (funcall im-func event)
event nil)
;; This also works for portable character encoding.
(setq result
(encode-coding-string (concat result)
'compound-text-with-extensions))
(exwm-xim--make-request
(make-instance 'xim:commit-x-lookup-chars
:im-id (slot-value req 'im-id)
:ic-id (slot-value req 'ic-id)
:flag (logior xim:commit-flag:synchronous
xim:commit-flag:x-lookup-chars)
:length (length result)
:string result)
conn client-xwin)
(xcb:flush conn))))
(when (eq exwm--selected-input-mode 'char-mode)
(exwm-input--release-keyboard))))
(setq exwm-xim--event-pending nil))))
(defun exwm-xim--make-request (req conn client-xwin) (defun exwm-xim--make-request (req conn client-xwin)
"Make an XIM request REQ via connection CONN. "Make an XIM request REQ via connection CONN.