6

I would like to define a function which behaves differently depending on the last keystroke. More specifically I would like that it behaves differently if the last keystroke (before the execution of that function) has been <home>. Like below

(defun foo ()
  (interactive)
  (if (the-last-keystroke-is-home)
     (message "yes")
    (message "no")))
Name
  • 7,689
  • 4
  • 38
  • 84

2 Answers2

5

You could take advantage of the recent-keys function. It returns a vector of the last 300 events.

Using

(defun get-last-key ()
  (interactive)
  (let ((vect (recent-keys)))
    (aref vect (1- (length vect)))))

And then doing C-x C-e on

(get-last-key)

You will get

5 (#o5, #x5, ?\C-e)

You will "just" have to compare this to the keystroke you want.

Note that as suggested by @stsquad, when you will call this function, your last keystroke probably won't be <home> (more likely <return>). So depending on what you want to achieve, re-binding <home> might be the way to go.


If you want a "readable" key, use the single-key-description function. To be thorough, you should also use prin1-to-string:

(defun get-last-key ()
  (interactive)
  (let* ((vect (recent-keys))
        (key (aref vect (1- (length vect)))))
        (if (or (integerp key) (symbolp key) (listp key))
            (single-key-description key)
            (prin1-to-string key nil)))
        )

(get-last-key); C-xC-e will give the string "C-e"
fredtantini
  • 741
  • 8
  • 13
  • Regardless of the previous keystrokes,doing `C-x C-e` on `(get-last-key)` gives only 5. Also the value of `(if (equal (get-last-key) "home")` is always nil. I think I misunderstand something here. – Name Jun 03 '15 at 10:15
  • Use `single-key-description` then. You will have to compare to `""` – fredtantini Jun 03 '15 at 10:35
  • 1
    `last-command-event` might be useful. A few other related functions and variables are : `this-command-keys`, `this-single-command-keys`, `this-command-keys-vector`, `this-single-command-raw-keys` and possibly `current-prefix-arg`. – YoungFrog Jun 03 '15 at 11:37
  • Thanks now if I in my original function I put `(defun foo () (interactive) (if (equal get-last-key "") (message "yes") (message "no")))`, then if I make then running foo, I expect that the message "yes" to be printed, but it prints "no". I think it is because of the line `(aref vect (1- (length vect))` in your code. I seems that it get the last entry of the recent-keys vector, but it should take the entry before the last entry. – Name Jun 03 '15 at 12:25
  • Depending on the keystroke changing `(aref vect (1- (length vect)))` to `(aref vect (- (length vect) n))` where n is a convenient number can do the job. – Name Jun 03 '15 at 15:57
3
(defun foo (keys)
  (interactive "kUse a key sequence: ")
  (let ((ks  (this-single-command-keys)))
    (setq ks  (aref ks (1- (length ks))))
    (if (eq 'home ks) (message "yes") (message "no"))))

Get rid of the argument and the interactive spec, if you intend to use this in a context where a key sequence has already been read and you want to test it.

Wrt other attempts shown here so far: Don't test key descriptions (strings). Test the actual key/event values.

Drew
  • 75,699
  • 9
  • 109
  • 225