From 25dec6e229c51786907f2252e4012b55ef120a70 Mon Sep 17 00:00:00 2001 From: Po Lu Date: Mon, 29 Apr 2024 20:01:59 +0800 Subject: [PATCH] Adapt eww to touch screens, mice and text conversion * doc/emacs/input.texi (On-Screen Keyboards): Update conditions for displaying the virtual keyboard when t-s-d-k is enabled. * etc/NEWS (Announce): Document changes. * lisp/net/eww.el (eww-check-text-conversion): New function. (eww-mode): Install it as a local post-command-hook. (eww-submit-map, eww-submit-file, eww-checkbox-map): Bind suitable commands to mouse-2. (eww-form-submit, eww-form-checkbox, eww-form-file) (eww-tag-select): Disguise inserted forms as buttons, that touch event translation may prefer their bindings to mouse-2 over mouse-1. (eww-form-text, eww-tag-textarea): Insert field properties as well. (eww-select-file, eww-toggle-checkbox, eww-submit): New argument EVENT, to whose position point is set. * lisp/touch-screen.el (touch-screen-handle-point-up): Trivial adjustments to the criteria for selecting mouse commands and displaying the on screen keyboard. (cherry picked from commit 4c46066cb6b3a9c87fb29be8cbdd4d90312f7020) --- doc/emacs/input.texi | 35 +++++++++-------- etc/NEWS | 16 +++++++- lisp/net/eww.el | 89 ++++++++++++++++++++++++++++++++------------ lisp/touch-screen.el | 18 ++++++++- 4 files changed, 113 insertions(+), 45 deletions(-) diff --git a/doc/emacs/input.texi b/doc/emacs/input.texi index 96a20a9bc1b..d48c13355b3 100644 --- a/doc/emacs/input.texi +++ b/doc/emacs/input.texi @@ -126,27 +126,26 @@ minibuffer being brought into use (@pxref{Minibuffer}). @vindex touch-screen-set-point-commands When a ``tap'' gesture results in a command being executed, Emacs -checks whether the command is meant to set the point by searching for -it in the list @code{touch-screen-set-point-commands}. If it is and -the text beneath the new point is not read-only, it activates the -virtual keyboard, in anticipation that the user is about to enter text -there. +checks whether the command is meant to set the point by searching for it +in the list @code{touch-screen-set-point-commands}. If it is and the +text beneath the new point is not read-only, the virtual keyboard is +activated, in anticipation of the user entering text there. - The default value of @code{touch-screen-set-point-commands} holds -only the command @code{mouse-set-point} (@pxref{Mouse Commands}), -which is the default binding of @code{mouse-1}, and thus of -touchscreen tap gestures as well. + The default value of @code{touch-screen-set-point-commands} holds only +the command @code{mouse-set-point} (@pxref{Mouse Commands}), which is +the default binding of @code{mouse-1}, and therefore of touchscreen tap +gestures as well. @vindex touch-screen-display-keyboard - The user option @code{touch-screen-display-keyboard} compels Emacs -to display the virtual keyboard on such taps even if the text is read -only; it may also be set buffer locally, in which case Emacs will -always display the keyboard in response to a tap on a window -displaying the buffer it is set in. - - There are moreover several functions to show or hide the on-screen -keyboard. For more details, @xref{On-Screen Keyboards,,, elisp, The -Emacs Lisp Reference Manual}. + The user option @code{touch-screen-display-keyboard} compels Emacs to +display the virtual keyboard on all tap gestures even if the text is +read only; it may also be set buffer locally, in which case Emacs will +always display the keyboard in response to a tap on a window displaying +the buffer it is set in. + + There are moreover several functions that display or hide the +on-screen keyboard. For more details, @xref{On-Screen Keyboards,,, +elisp, The Emacs Lisp Reference Manual}. @cindex quitting, without a keyboard Since it may not be possible for Emacs to display the virtual diff --git a/etc/NEWS b/etc/NEWS index eb78521ea32..794269b0149 100644 --- a/etc/NEWS +++ b/etc/NEWS @@ -1218,6 +1218,20 @@ for setting the remote PATH environment variable. ** EWW +--- +*** New mouse bindings in EWW buffers. +Certain form elements that were displayed as buttons, yet could only be +activated by keyboard input, are now operable using 'mouse-2'. With +"Submit" buttons, this triggers submission of the form, while clicks on +other classes of buttons either toggle their values or prompt for user +input, as the case may be. + +--- +*** EWW text input fields and areas are now fields. +In consequence, movement commands and OS input method features now +recognize and confine their activities to the text input field around +point. See also (elisp)Fields. + +++ *** 'eww-open-file' can now display the file in a new buffer. By default, the command reuses the "*eww*" buffer, but if called with @@ -1251,7 +1265,7 @@ This is useful for continuing reading the URL in the current buffer when the new URL is fetched. --- -*** History navigation in EWW now works like other browsers. +*** History navigation in EWW now behaves as in other browsers. Previously, when navigating back and forward through page history, EWW would add a duplicate entry to the end of the history list each time. This made it impossible to navigate to the "end" of the history list. diff --git a/lisp/net/eww.el b/lisp/net/eww.el index 39ea964d47a..4bb491b9970 100644 --- a/lisp/net/eww.el +++ b/lisp/net/eww.el @@ -1300,6 +1300,23 @@ This consults the entries in `eww-readable-urls' (which see)." map) "Tool bar for `eww-mode'.") +(declare-function set-text-conversion-style "textconv.c") + +(defun eww-check-text-conversion () + "Check if point is within a field and toggle text conversion. +If `text-conversion-style' is not `action' if point is within the +prompt or `nil' otherwise, set it to such a value, so as to +guarantee that the input method functions properly for the +purpose of typing within the ERC prompt." + (when (and (eq major-mode 'eww-mode) + (fboundp 'set-text-conversion-style)) + (if (eq (car-safe (get-text-property (point) 'field)) + :eww-form) + (unless (eq text-conversion-style 'action) + (set-text-conversion-style 'action)) + (unless (not text-conversion-style) + (set-text-conversion-style nil))))) + ;; Autoload cookie needed by desktop.el. ;;;###autoload (define-derived-mode eww-mode special-mode "eww" @@ -1328,6 +1345,7 @@ This consults the entries in `eww-readable-urls' (which see)." (add-hook 'text-scale-mode-hook #'eww--rescale-images nil t) (setq-local outline-search-function 'shr-outline-search outline-level 'shr-outline-level) + (add-hook 'post-command-hook #'eww-check-text-conversion nil t) (setq buffer-read-only t)) (defvar text-scale-mode) @@ -1487,16 +1505,19 @@ just re-display the HTML already fetched." (defvar-keymap eww-submit-map "RET" #'eww-submit - "C-c C-c" #'eww-submit) + "C-c C-c" #'eww-submit + "" #'eww-submit) (defvar-keymap eww-submit-file "RET" #'eww-select-file - "C-c C-c" #'eww-submit) + "C-c C-c" #'eww-submit + "" #'eww-select-file) (defvar-keymap eww-checkbox-map "SPC" #'eww-toggle-checkbox "RET" #'eww-toggle-checkbox - "C-c C-c" #'eww-submit) + "C-c C-c" #'eww-submit + "" #'eww-toggle-checkbox) (defvar-keymap eww-text-map :full t :parent text-mode-map @@ -1585,6 +1606,8 @@ just re-display the HTML already fetched." :type "submit" :name (dom-attr dom 'name))) (put-text-property start (point) 'keymap eww-submit-map) + ;; Pretend to touch-screen.el that this is a button. + (put-text-property start (point) 'button t) (insert " "))) (defun eww-form-checkbox (dom) @@ -1600,6 +1623,8 @@ just re-display the HTML already fetched." :checked (dom-attr dom 'checked) :name (dom-attr dom 'name))) (put-text-property start (point) 'keymap eww-checkbox-map) + ;; Pretend to touch-screen.el that this is a button. + (put-text-property start (point) 'button t) (insert " "))) (defun eww-form-file (dom) @@ -1618,11 +1643,16 @@ just re-display the HTML already fetched." :type (downcase (dom-attr dom 'type)) :name (dom-attr dom 'name))) (put-text-property start (point) 'keymap eww-submit-file) + ;; Pretend to touch-screen.el that this is a button. + (put-text-property start (point) 'button t) (insert " "))) -(defun eww-select-file () - "Change the value of the upload file menu under point." - (interactive nil eww-mode) +(defun eww-select-file (&optional event) + "Change the value of the upload file menu under point. +EVENT, if non-nil, is the mouse event that preceded this command." + (interactive (list last-nonmenu-event) eww-mode) + (when (and event (setq event (event-start event))) + (goto-char (posn-point event))) (let* ((input (get-text-property (point) 'eww-form))) (let ((filename (let ((insert-default-directory t)) @@ -1638,7 +1668,12 @@ just re-display the HTML already fetched." (readonly-property (if (or (dom-attr dom 'disabled) (dom-attr dom 'readonly)) 'read-only - 'inhibit-read-only))) + 'inhibit-read-only)) + form) + (setq form (list :eww-form eww-form + :value value + :type type + :name (dom-attr dom 'name))) (insert value) (when (< (length value) width) (insert (make-string (- width (length value)) ? ))) @@ -1646,11 +1681,8 @@ just re-display the HTML already fetched." (put-text-property start (point) 'inhibit-read-only t) (put-text-property start (point) 'local-map eww-text-map) (put-text-property start (point) readonly-property t) - (put-text-property start (point) 'eww-form - (list :eww-form eww-form - :value value - :type type - :name (dom-attr dom 'name))) + (put-text-property start (point) 'eww-form form) + (put-text-property start (point) 'field form) (insert " "))) (defconst eww-text-input-types '("text" "password" "textarea" @@ -1721,7 +1753,7 @@ See URL `https://developer.mozilla.org/en-US/docs/Web/HTML/Element/Input'.") (value (or (dom-text dom) "")) (lines (string-to-number (or (dom-attr dom 'rows) "10"))) (width (string-to-number (or (dom-attr dom 'cols) "10"))) - end) + end form) (shr-ensure-newline) (insert value) (shr-ensure-newline) @@ -1741,11 +1773,12 @@ See URL `https://developer.mozilla.org/en-US/docs/Web/HTML/Element/Input'.") (put-text-property (line-beginning-position) (point) 'local-map eww-textarea-map) (forward-line 1)) - (put-text-property start (point) 'eww-form - (list :eww-form eww-form - :value value - :type "textarea" - :name (dom-attr dom 'name))) + (setq form (list :eww-form eww-form + :value value + :type "textarea" + :name (dom-attr dom 'name))) + (put-text-property start (point) 'eww-form form) + (put-text-property start (point) 'field form) (put-text-property start (1+ start) 'shr-tab-stop t))) (defun eww-tag-input (dom) @@ -1809,6 +1842,8 @@ See URL `https://developer.mozilla.org/en-US/docs/Web/HTML/Element/Input'.") (put-text-property start (point) 'eww-form menu) (add-face-text-property start (point) 'eww-form-select) (put-text-property start (point) 'keymap eww-select-map) + ;; Pretend to touch-screen.el that this is a button. + (put-text-property start (point) 'button t) (unless (= start (point)) (put-text-property start (1+ start) 'help-echo "select field") (put-text-property start (1+ start) 'shr-tab-stop t)) @@ -1867,9 +1902,12 @@ See URL `https://developer.mozilla.org/en-US/docs/Web/HTML/Element/Input'.") (set-text-properties start new-end properties)) start)) -(defun eww-toggle-checkbox () - "Toggle the value of the checkbox under point." - (interactive nil eww-mode) +(defun eww-toggle-checkbox (&optional event) + "Toggle the value of the checkbox under point. +EVENT, if non-nil, is the mouse event that preceded this command." + (interactive (list last-nonmenu-event) eww-mode) + (when (and event (setq event (event-start event))) + (goto-char (posn-point event))) (let* ((input (get-text-property (point) 'eww-form)) (type (plist-get input :type))) (if (equal type "checkbox") @@ -1937,9 +1975,12 @@ See URL `https://developer.mozilla.org/en-US/docs/Web/HTML/Element/Input'.") (substring value 0 (match-beginning 0)) value))))) -(defun eww-submit () - "Submit the current form." - (interactive nil eww-mode) +(defun eww-submit (&optional event) + "Submit the form under point or EVENT. +EVENT, if non-nil, is the mouse event that preceded this command." + (interactive (list last-nonmenu-event) eww-mode) + (when (and event (setq event (event-start event))) + (goto-char (posn-point event))) (let* ((this-input (get-text-property (point) 'eww-form)) (form (plist-get this-input :eww-form)) values next-submit) diff --git a/lisp/touch-screen.el b/lisp/touch-screen.el index 52a36712c44..537780eb708 100644 --- a/lisp/touch-screen.el +++ b/lisp/touch-screen.el @@ -1339,7 +1339,9 @@ is not read-only." ;; Now simulate a mouse click there. If there is a ;; link or a button, use mouse-2 to push it. (let* ((event (list (if (or (mouse-on-link-p posn) - (and point (button-at point))) + (and point + (get-char-property + point 'button))) 'mouse-2 'mouse-1) posn)) @@ -1356,7 +1358,13 @@ is not read-only." ;; Figure out if the on screen keyboard needs to be ;; displayed. (when command - (if (memq command touch-screen-set-point-commands) + (if (or (memq command touch-screen-set-point-commands) + ;; Users of packages that redefine + ;; mouse-set-point, or other commands + ;; recognized as defining the point, should + ;; not find the on screen keyboard + ;; inaccessible even with t-s-d-k enabled. + touch-screen-display-keyboard) (if touch-screen-translate-prompt ;; Forgo displaying the virtual keyboard ;; should touch-screen-translate-prompt be @@ -1366,6 +1374,12 @@ is not read-only." ;; describe-key. (throw 'input-event event) (if (and (or (not buffer-read-only) + ;; Display the on screen + ;; keyboard even if just the + ;; text under point is not + ;; read-only. + (get-text-property point + 'inhibit-read-only) touch-screen-display-keyboard) ;; Detect the splash screen and ;; avoid displaying the on screen -- 2.39.5