Quantcast
Channel: Active questions tagged help - Emacs Stack Exchange
Viewing all articles
Browse latest Browse all 40

Inconsistency between read-key and read-key-sequence-vector w.r.t. conditional application of local-function-key-map translations

$
0
0

While working with read-key-sequence-vector and read-key, I found that the former applies the local-function-key-map translations in a conditional manner but the latter does not. I am using Emacs 28.1 on a macOS system.

The function read-key-sequence-vector translates the original key sequence to a key sequence in the local-function-key-map only if the original key sequence is unbound. If the original key sequence is bound, then the translations in local-function-key-map are not applied.

However, according to my observations, the function read-key always seems to apply the local-function-key-map translations in an unconditional manner. I would like to understand if this is a bug or expected behavior. The sections below explain the investigation I have done so far.

Documentation: read-key-sequence-vector

The documentation for read-key-sequence-vector at § 22.8.1 Key Sequence Input refers to read-key-sequence which says:

Function: read-key-sequence prompt &optional continue-echo dont-downcase-last switch-frame-ok command-loop

...

Reading a key sequence includes translating the events in various ways. See Keymaps for Translating Sequences of Events.

The documentation for § 23.14 Keymaps for Translating Sequences of Events says:

Variable: local-function-key-map

This variable holds a keymap similar to input-decode-map except that it describes key sequences which should be translated to alternative interpretations that are usually preferred. It applies after input-decode-map and before key-translation-map.

Entries in local-function-key-map are ignored if they conflict with bindings made in the minor mode, local, or global keymaps. I.e., the remapping only applies if the original key sequence would otherwise not have any binding.

Now open a fresh new Emacs:

emacs -q

Then type:

C-h v local-function-key-map RET

The output contains this entry:

 (tab .      [9])

Confirm the above observation by entering the following:

M-: (lookup-key local-function-key-map [tab]) RET

It should display the following output:

[9]

We have seen so far that if the <tab> key is unbound, then a key sequence [tab] should get translated to [9]. We'll see an example of this in an experiment presented later.

Documentation: read-key

The documentation for read-key at § 22.8.2 Reading One Event says:

Function: read-key &optional prompt disable-fallbacks

This function reads a single key. It is intermediate between read-key-sequence and read-event. Unlike the former, it reads a single key, not a key sequence. Unlike the latter, it does not return a raw event, but decodes and translates the user input according to input-decode-map, local-function-key-map, and key-translation-map (see Keymaps for Translating Sequences of Events).

It seems that the translation rules that apply for read-key are no different from that of read-key-sequence-vector. The same documentation further says:

If argument disable-fallbacks is non-nil then the usual fallback logic for unbound keys in read-key-sequence is not applied. This means that mouse button-down and multi-click events will not be discarded and local-function-key-map and key-translation-map will not get applied. If nil or unspecified, the only fallback disabled is downcasing of the last event.

The disable-fallbacks argument if set to t unconditionally skips translations, so this argument does not seem relevant to my question here. My question here is about read-key unconditionally applying translations, not about unconditionally skipping translations.

Experiment 1: Default Behaviour

Switch to a fundamental mode buffer:

C-x b foo RET

Now type the following:

C-h k <tab>

The following output should appear:

TAB (translated from <tab>) runs the command indent-for-tab-command(found in global-map), which is an interactive compiled Lisp functionin ‘indent.el’.

It shows that <tab> (represented as the symbol tab in the key sequence vector as we'll see later) is unbound and it is being translated to TAB (also something we'll see soon).

Copy this Elisp code into the buffer:

(defun check-keys ()  (interactive)  (let ((event (read-event "Event: "))    (key (read-key "Key: "))    (key-sequence-vector (read-key-sequence-vector "Key Sequence: ")))    (message "event: %S (%S); key: %S (%S); key-sequence-vector: %S (%S)"         event (type-of event)         key (type-of key)         key-sequence-vector (type-of key-sequence-vector))))

Now define this command by placing the cursor after the last parentheses and typing the following:

C-x C-e

Now execute the above command by typing:

M-x check-keys RET

This command prompts three times. Type tab all three times. The following output appears:

event: tab (symbol); key: 9 (integer); key-sequence-vector: [9] (vector)

This is expected behaviour. The function read-event reads the next event (a tab key) as the symbol tab. Since there is nothing bound to the key sequence [tab] (a vector containing the symbol tab), both read-key and read-key-sequence-vector translate it according to local-function-key-map thereby obtaining 9.

Experiment 2: Key Sequence [tab] Bound

Now define a key-binding for a key sequence containing the symbol tab as follows:

M-: (global-set-key [tab] 'whitespace-mode) RET

Now verify the key binding with the following key sequence:

C-h k <tab>

The following output appears confirming that the <tab> key itself is bound to the whitespace-command command:

<tab> runs the command whitespace-mode (found in global-map), which isan autoloaded interactive Lisp function in ‘whitespace.el’.

Now run check-keys again:

M-x check-keys RET

Once again, type tab at all three prompts. The following output appears:

event: tab (symbol); key: 9 (integer); key-sequence-vector: [tab] (vector)

Now the key sequence made of the symbol tabis bound to the whitespace-mode command. Therefore according to § 23.14 Keymaps for Translating Sequences of Events, the symbol tab should not be translated to the integer 9 anymore. In fact, the above output shows that read-key-sequence-vector indeed does not translate the symbol tab to the integer 9 anymore. This shows that the conditional translation is working as documented in read-key-sequence-vector.

However, the above output also shows that read-key still translates the symbol tab to the integer 9. The behaviour of read-key here seems to contradict § 22.8.2 Reading One Event which seems to imply that the conditional translation rules for local-function-key-map should apply here too, i.e., no translation for tab should occur when it is already bound to some command.

Does the behaviour of read-key indeed contradict the documentation? Or is this expected behaviour? If this is expected behaviour, where in the documentation can we find why this is expected behaviour?


Viewing all articles
Browse latest Browse all 40

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>