Reputation: 17422
When I start a new emacs in a terminal like so
emacs -nw -Q
I can try to check what a certain keyboard shortcut is bound to by typing C-h k. When I do this for the shortcut M-S-<left> in the *scratch*
buffer right after starting Emacs, I get:
<M-left> runs the command left-word (found in global-map), which is an interactive compiled Lisp function in ‘bindings.el’.
It is bound to <C-left>, <M-left>.
[...]
Note the absence of the "Shift" modifier in the recognized key sequence.
Now, the first instinct would be that the terminal (gnome-terminal in my case) does not produce the correct escape sequence, but it does: typing CTRL-V ALT-SHIFT-left in the terminal (i.e., not in Emacs) produces
^[[1;4D
and typing C-q C-S-<left> inside Emacs inserts the same into the current buffer. (Note that ^[
is a single character, namely ASCII 27 ("Escape").)
Checking input-decode-map
reveals the following value (some parts left out (marked as ...
) for brevity):
(keymap
(27 keymap ... )
keymap
(keymap
(27 keymap
...
(91 keymap
...
(51 keymap
...
(59 keymap
(51 keymap
...
(68 .
[M-left])
(52 keymap
...
(68 .
[M-S-left])
...)
...)
...)
...))))
Verifying the two key sequences with the following code gives the expected results:
(mapc '(lambda (c) (insert (format "%c" c))) '(27 91 49 59 51 68)) ; ^[[1;3D
(mapc '(lambda (c) (insert (format "%c" c))) '(27 91 49 59 52 68)) ; ^[[1;4D
However, I don't understand why these sequences are embedded in a second-level inner (keymap ...)
list?!
It gets weirder.
Back in *scratch*
, when I type
M-x local-set-key
and then M-S-<left>, it gets recognized correctly, as the next prompt in the minibuffer reveals:
Set key <M-S-left> locally to command:
If I proceed and provide a random function, say, beginning-of-line
, a subsequent invocation of C-h k followed by M-S-<left> then indeed gives:
<M-S-left> runs the command beginning-of-line (found in lisp-interaction-mode-map), which is an interactive built-in function in ‘C source code’.
It is bound to <M-S-left>.
[...]
Locally setting M-S-<left> to nil
will restore the initial behavior in which C-h k reports M-S-<left> as <M-left>
.
What is going on here? Is this a configuration issue, or is it intended behavior, or are some other keymaps involved that transparently add another layer of remapping?
Upvotes: 3
Views: 608
Reputation: 73246
It's a feature.
M-x elisp-index-search
RET shift-translation
says:
If an input character is upper-case (or has the shift modifier) and has no key binding, but its lower-case equivalent has one, then ‘read-key-sequence’ converts the character to lower case. Note that ‘lookup-key’ does not perform case conversion in this way.
When reading input results in such a “shift-translation”, Emacs sets the variable ‘this-command-keys-shift-translated’ to a non-‘nil’ value. Lisp programs can examine this variable if they need to modify their behavior when invoked by shift-translated keys. For example, the function ‘handle-shift-selection’ examines the value of this variable to determine how to activate or deactivate the region (*note handle-shift-selection: The Mark.).
Upvotes: 3