When part of a
(interactive "c(C)hoose (A)n (O)ption")
will prompt the user for a single character;
RET is not required. How can I replicate this reading behavior without the need for
read-char I recommend
read-key. The difference is that
read-key obeys all the usual remappings such as
function-key-map, so it will work properly in a tty.
In addition to built-in ways to read single events such as
read-char-exclusive, here's an option to read a single character, but also specify which characters are acceptable input:
(defun read-char-picky (prompt chars &optional inherit-input-method seconds) "Read characters like in `read-char-exclusive', but if input is not one of CHARS, return nil. CHARS may be a list of characters, single-character strings, or a string of characters." (let ((chars (mapcar (lambda (x) (if (characterp x) x (string-to-char x))) (append chars nil))) (char (read-char-exclusive prompt inherit-input-method seconds))) (when (memq char chars) char)))
So all of the following will accept either "C", "A", or "O":
(read-char-picky "(C)hoose (A)n (O)ption: " "CAO") (read-char-picky "(C)hoose (A)n (O)ption: " '("C" "A" "O")) (read-char-picky "(C)hoose (A)n (O)ption: " '(?C ?A ?O))
And here's an example way to loop for the correct input into a
(let (response) (while (null (setq response (read-char-picky "(C)hoose (A)n (O)ption: " "CAO"))) (message "Please pick one of \"C\", \"A\", or \"O\"!") (sit-for .5)) response)
call-interactively is what interprets the
(interactive "cPROMPT") specification, the
c option is dispatched to
read-char. Therefore, the following should work in a non-interactive context:
(read-char "(C)hoose (A)n (O)ption")
The question was answered long ago, but this additional answer may provide some assistance to other searchers.
read-char-choice allows you to specify a list of choices. The fn will not return until the user selects one of those valid options.
(read-char-choice "prompt here (A, B, or C)? " '(?A ?B ?C))
In the degenerate case in which the options are simply Y or N (case insenstive), there is
y-or-n-p are rigid, and insist on a valid answer. In the former case, it must one of the options you specify (like A, B or C in my example), and in latter case, it must be Y or N . If the user presses enter or any other key, the
y-or-n-p will ask again. The
read-char-choice will just sit there, silent. Neither provides a way to just return a default. To get that behavior, I think you've got to build your own interaction with
In my experience, the problem with
read-key alone, is that while they display the prompt in the minibuffer, the cursor remains in the main editing buffer. This is disorienting to the user, and is also unlike the behavior of
To avoid THAT, you can let the variable
cursor-in-echo-area prior to calling
read-key to display the cursor in the minibuffer.
(defun my-y-or-n-with-default (raw-prompt &optional default-yes) "displays PROMPT in the minibuffer, prompts for a y or n, returns t or nil accordingly. If neither Y or N is entered, then if DEFAULT-YES, returns t, else nil." (let* ((options-string (if default-yes "Y or n" "y or N")) (prompt (concat raw-prompt "(" options-string ")? ")) (cursor-in-echo-area t) (key (read-key (propertize prompt 'face 'minibuffer-prompt))) (isyes (or (eq key ?y) (eq key ?Y))) (isno (or (eq key ?n) (eq key ?N)))) (if (not (or isyes isno)) default-yes isyes)))